Procházet zdrojové kódy

宝时丰收-增加组合商品唯一码逻辑

zhaohuanhuan před 1 týdnem
rodič
revize
5f77f8d643

+ 17 - 0
src/api/takeDelivery/index.ts

@@ -85,6 +85,23 @@ export function getCommodityRule(params:getCommodityRuleType) {
   })
 }
 
+/** 货主规则 */
+export function getOwnerRule(code: string) {
+  return request({
+    url: '/api/basic/owner/rule/get',
+    method: 'get',
+    params: { code },
+  })
+}
+
+/** 组合商品外箱唯一码换子件唯一码 */
+export function getPanpassCodeRelation(params: { docNo: string; uniqueCode: string; customer: string }) {
+  return request({
+    url: '/api/wms/panpass/code-relation',
+    method: 'post',
+    params,
+  })
+}
 
 /**
  * 完成收货

+ 4 - 1
src/views/inbound/takeDelivery/components/BarcodeCombine.vue

@@ -44,6 +44,9 @@ const show = () => {
     countRef.value?.focus()
   }, 200)
 }
+const hide = () => {
+  goodsTrueFalseBy.value = false
+}
 const dataResult = (data) =>
   data.map((item) => {
     const { matchedJson, ...rest } = item
@@ -72,7 +75,7 @@ const beforeClose = (action) =>
     }
     resolve(true)
   })
-defineExpose({ show })
+defineExpose({ show, hide })
 </script>
 <style scoped lang="sass">
 .goods

+ 22 - 9
src/views/inbound/takeDelivery/components/UniqueCodeInput.vue

@@ -86,7 +86,9 @@ const props = defineProps({
   scanType: Number,
   searchCount: [String, Number],
   asnInfo:Object,
-  checkAllType:Boolean
+  checkAllType:Boolean,
+  /** 组合外箱码获取内件码 */
+  resolvePanpassCodes: { type: Function, default: undefined },
 })
 const scanInputType=props.checkAllType?'barcode':'unique'
 const uniqueCodeScanType=ref(scanInputType)
@@ -111,9 +113,17 @@ const onCheckAllType=()=>{
   localStorage.setItem('checkAllType',newCheckAllType.value)
   emit('update:checkAllType',newCheckAllType.value)
 }
+const refocusAfterUniqueInput = () => {
+  uniqueBarcode.value = ''
+  uniqueCode.value = ''
+  if (newCheckAllType.value) uniqueBarcodeRef.value?.focus()
+  else uniqueCodeRef.value?.focus()
+}
+
 //商品条码验证
 const uniqueBarcodeChange=()=>{
   if(newCheckAllType.value){
+    if (props.resolvePanpassCodes) return true
     if(!uniqueBarcode.value){
       showNotify({ type: 'danger', duration: 3000, message: `请先扫描商品条码` })
       scanError()
@@ -133,9 +143,18 @@ const uniqueBarcodeChange=()=>{
   }
   return true
 }
-const onKeydown = () => {
+const onKeydown = async () => {
   if(!uniqueBarcodeChange()) return
   if (uniqueCode.value) {
+    if (props.resolvePanpassCodes) {
+      const result = await props.resolvePanpassCodes(uniqueCode.value)
+      if (result == null) {
+        uniqueCode.value = ''
+        return
+      }
+      refocusAfterUniqueInput()
+      return
+    }
     const uniqueRegExp = uniqueRuleMap.value['sku'] ? uniqueRuleMap.value['sku'] : uniqueRuleMap.value['all']
     const isValidCode = new RegExp(uniqueRegExp).test(uniqueCode.value)
     if (!isValidCode) {
@@ -152,13 +171,7 @@ const onKeydown = () => {
     }
     scanSuccess()
     containerList.value.unshift(uniqueCode.value)
-    uniqueBarcode.value=''
-    uniqueCode.value = ''
-    if(newCheckAllType.value){
-      uniqueBarcodeRef.value?.focus()
-    }else {
-      uniqueCodeRef.value?.focus()
-    }
+    refocusAfterUniqueInput()
   }
   emit('update:uniqueCodeList', containerList.value)
 }

+ 167 - 35
src/views/inbound/takeDelivery/task/index.vue

@@ -138,6 +138,7 @@
                      v-model:checkAllType="checkAllType"
                      :searchCount="searchCount"
                      :asnInfo="asnInfo"
+                     :resolve-panpass-codes="isCombinePanpass ? resolvePanpassScan : undefined"
                      @setUniqueCode="onConfirm"
 
   />
@@ -166,6 +167,8 @@ import { useRouter } from 'vue-router'
 import {
   calculateShelfLife, getCommodityRule,
   getIReceivingTask,
+  getOwnerRule,
+  getPanpassCodeRelation,
   getProductAttribute, getProductLot,
   getReceivingAsnDetails,
   setProductAttribute, setReceiving,
@@ -272,32 +275,51 @@ const setBarcode = (code, type) => {
   getIReceivingTask({ taskNo:code,version:'V6',warehouse }).then(res=>{
     back.value = true
     if(res.data.receivedQty==res.data.expectedQty && res.data.expectedQty>0 ){
-      if(type){
-        reset()
-        taskNo.value=''
-        taskInfo.value={}
+      reset()
+      taskNo.value = ''
+      taskInfo.value = {}
+      containerNo.value = ''
+      stopTimer()
+      allAsnDetailList.value = []
+      ownerPanpassEnabled.value = false
+      scanType.value = 2
+      uniqueCodeList.value = []
+      if (type) {
         switchTask()
+      } else {
+        inputBarcodeType.value = 'task'
+        back.value = true
+        inputBarcodeRef.value?.show('', '请扫描开单任务号', '')
       }
+      scanSuccess()
+      return
+    }
+    if(!type){//切换任务成功重启计时器
+      currentTime.value=getCurrentTime()
+      startTimer()
       containerNo.value=''
-      stopTimer()
-
-    }else {
-      if(!type){//切换任务成功重启计时器
-        currentTime.value=getCurrentTime()
-        startTimer()
-        containerNo.value=''
-      }
     }
     taskInfo.value=res.data
     taskNo.value=code
     scanType.value=2
     uniqueCodeList.value=[]
+    const ownerCode = res.data?.customerId
+    if (ownerCode) {
+      getOwnerRule(ownerCode).then((ruleRes) => {
+        ownerPanpassEnabled.value = !!ruleRes.data?.panpassEnabled
+      }).catch(() => {
+        ownerPanpassEnabled.value = false
+      })
+    } else {
+      ownerPanpassEnabled.value = false
+    }
     const params = { warehouse, asnNos: taskInfo.value?.asnNos.join(',') }
     getReceivingAsnDetails(params).then(res => {
       allAsnDetailList.value = res.data
     })
     scanSuccess()
   }).catch(err=>{
+    ownerPanpassEnabled.value = false
     inputBarcodeRef.value?.show('', '请扫描开单任务号',err.message)
     scanError()
   }).finally(()=>{
@@ -317,7 +339,25 @@ const switchTask = () => {
 const asnDetailsTrueFalseBy = ref(false)
 const asnDetailsList = ref([])
 const asnInfo = ref({})
+// 组合商品
+const barcodeCombineRef = ref(null)
+const combineMatchedSku = ref([])
+const combineAsnSelectList = ref([])
+const isCombineSelectMode = ref(false)
+const combineReceivingData = ref([]) // 确认实收数后暂存,完成收货时提交
+
+/** 重置组合收货状态 */
+function resetCombineProductState() {
+  barcodeCombineRef.value?.hide?.()
+  combineMatchedSku.value = []
+  combineAsnSelectList.value = []
+  isCombineSelectMode.value = false
+  combineReceivingData.value = []
+  asnDetailsTrueFalseBy.value = false
+}
+
 const reset = () => {
+  resetCombineProductState()
   asnInfo.value = {}
   lotData.value = []
   lotMap.value={}
@@ -325,10 +365,6 @@ const reset = () => {
   searchBarcode.value = ''
   oldSearchBarcode.value = ''
   uniqueCodeList.value = []
-  combineMatchedSku.value = []
-  combineAsnSelectList.value = []
-  isCombineSelectMode.value = false
-  combineReceivingData.value = []
 }
 const onDetailActive = (item) => {
   if (isCombineSelectMode.value) {
@@ -344,6 +380,7 @@ const onDetailActive = (item) => {
 }
 const onAsnCancel = () => {
   if (searchBarcode.value === '' || (oldSearchBarcode.value.length != searchBarcode.value.length && oldSearchBarcode.value != '')) {
+    resetCombineProductState()
     asnInfo.value = {}
     lotData.value = []
     lotMap.value={}
@@ -351,13 +388,100 @@ const onAsnCancel = () => {
   }
 }
 const uniqueCodeList = ref([])
+/** 货主规则组合收货需扫外箱码获取内件唯一码 */
+const ownerPanpassEnabled = ref(false)
 
-// 组合商品
-const barcodeCombineRef = ref(null)
-const combineMatchedSku = ref([])
-const combineAsnSelectList = ref([])
-const isCombineSelectMode = ref(false)
-const combineReceivingData = ref([]) // 确认实收数后暂存,完成收货时提交
+/** 获取内件唯一码 */
+function parsePanpassChildCodes(apiRes) {
+  const outer = apiRes?.data
+  const childPayload =
+    outer && typeof outer === 'object' && Array.isArray(outer.childCodes)
+      ? outer
+      : outer?.data
+  if (childPayload == null || typeof childPayload !== 'object') return null
+  const fromApi = childPayload.childCodes
+  if (!Array.isArray(fromApi) || fromApi.length === 0) return null
+  return fromApi.map(String).filter(Boolean)
+}
+
+function resetUniqueCodeDialogFocus() {
+  const dialogCmp = uniqueCodeRef.value
+  if (!dialogCmp) return
+  dialogCmp.uniqueBarcode = ''
+  dialogCmp.uniqueCodeScanType = checkAllType.value ? 'barcode' : 'unique'
+}
+
+async function resolvePanpassScan(code) {
+  showLoading()
+  try {
+    const customerId = asnInfo.value.customerId || taskInfo.value.customerId
+    if (!taskNo.value || !customerId) {
+      showNotify({ type: 'danger', duration: 3000, message: '缺少任务号或货主,无法校验兆信唯一码' })
+      scanError()
+      return null
+    }
+    const res = await getPanpassCodeRelation({
+      docNo: taskNo.value,
+      uniqueCode: code,
+      customer: customerId,
+    })
+    const childCodes = parsePanpassChildCodes(res)
+    if (!childCodes?.length) {
+      const uniqueRegExp = uniqueRuleMap.value['sku']
+        ? uniqueRuleMap.value['sku']
+        : uniqueRuleMap.value['all']
+      if (uniqueRegExp) {
+        const isValidCode = new RegExp(uniqueRegExp).test(code)
+        if (!isValidCode) {
+          scanError()
+          showNotify({ type: 'danger', duration: 3000, message: `唯一码《${code}》不符合规则、请重新扫描` })
+          return null
+        }
+      }
+      const prev = uniqueCodeList.value
+      if (prev.includes(code)) {
+        showNotify({ type: 'danger', duration: 3000, message: `唯一码《${code}》已存在列表内请重新扫描` })
+        scanError()
+        return null
+      }
+      if (prev.length + 1 > Number(searchCount.value)) {
+        showNotify({ type: 'danger', duration: 3000, message: '唯一码数量超过收货数量' })
+        scanError()
+        return null
+      }
+      uniqueCodeList.value = [...prev, code]
+      showNotify({ type: 'warning', duration: 3000, message: '未获取到内箱唯一码' })
+      scanSuccess()
+      return [code]
+    }
+    const prev = uniqueCodeList.value
+    if (childCodes.some((childCode) => prev.includes(childCode))) {
+      const duplicateCode = childCodes.find((childCode) => prev.includes(childCode))
+      showNotify({ type: 'danger', duration: 3000, message: `唯一码《${duplicateCode}》已存在列表内请重新扫描` })
+      scanError()
+      return null
+    }
+    const merged = prev.length + childCodes.length
+    if (merged > Number(searchCount.value)) {
+      showNotify({ type: 'danger', duration: 3000, message: '唯一码数量超过收货数量' })
+      scanError()
+      return null
+    }
+    uniqueCodeList.value = [...prev, ...childCodes]
+    scanSuccess()
+    return childCodes
+  } catch {
+    scanError()
+    return null
+  } finally {
+    closeLoading()
+  }
+}
+
+/** 兆信开启且当前为组合商品:外箱码获取内件唯一码 */
+const isCombinePanpass = computed(
+  () => ownerPanpassEnabled.value && combineReceivingData.value.length > 0,
+)
 
 // 组合商品只支持1个
 const _handleCombineProduct = (code) => {
@@ -428,6 +552,7 @@ const _handlerScan = (code) => {
   if (scanType.value == 2) {
     searchBarcode.value = code
     oldSearchBarcode.value = code
+      resetCombineProductState()
       if ( allAsnDetailList.value.length > 0) {
         const upperCode = barcodeToUpperCase(code) || ''
         const clientMatched = allAsnDetailList.value.filter((detail) => {
@@ -477,13 +602,22 @@ const _handlerScan = (code) => {
           return;
         }
       }
-      // 如果是通过唯一码扫描,并且没有扫描条码
-      if (uniqueCodeScanType === 'unique' && ( uniqueCodeRef.value.uniqueBarcode == '' && checkAllType.value)) {
+      // 唯一码扫描
+      if (
+        !isCombinePanpass.value &&
+        uniqueCodeScanType === 'unique' &&
+        uniqueCodeRef.value?.uniqueBarcode == '' &&
+        checkAllType.value
+      ) {
         showNotify({ type: 'danger', duration: 3000, message: '请先扫描商品条码' });
         uniqueCodeRef.value.uniqueCodeScanType = 'barcode';
         scanError();
         return;
       }
+      if (isCombinePanpass.value) {
+        void resolvePanpassScan(code).then((panpassResult) => panpassResult != null && resetUniqueCodeDialogFocus())
+        return
+      }
       const uniqueRegExp = uniqueRuleMap.value['sku'] ? uniqueRuleMap.value['sku'] : uniqueRuleMap.value['all']
       const isValidCode = new RegExp(uniqueRegExp).test(code)
       if (!isValidCode) {
@@ -498,12 +632,7 @@ const _handlerScan = (code) => {
       }
       scanSuccess()
       uniqueCodeList.value.unshift(code)
-      uniqueCodeRef.value.uniqueBarcode=''
-      if(checkAllType.value){
-        uniqueCodeRef.value.uniqueCodeScanType='barcode'
-      }else {
-        uniqueCodeRef.value.uniqueCodeScanType='unique'
-      }
+      resetUniqueCodeDialogFocus()
 
     }
   }else if(scanType.value==5){
@@ -608,10 +737,10 @@ const onLot = (item) => {
   }
 }
 //设置质量状态
-const onSelectLotQuality=(key)=>{
+const onSelectLotQuality=(qualityKey)=>{
   lotData.value.forEach((lot) => {
     if (lot.field == lotField.value) {
-      lot.mapping = key
+      lot.mapping = qualityKey
     }
   })
   lotQualityTrueFalseBy.value=false
@@ -745,10 +874,13 @@ const isCheck = () => {
     showToast({ duration: 3000, message: '请先输入容器号' })
     return false
   }
-  // 唯一码收集
-  if (uniqueRuleList.value.length > 0 && uniqueCodeList.value.length != searchCount.value) {
+  const needUnique = uniqueRuleList.value.length > 0 || isCombinePanpass.value
+  if (needUnique && uniqueCodeList.value.length != searchCount.value) {
       scanType.value = 3
-      uniqueCodeRef.value?.show('', '请扫描唯一码', `收货数量:${searchCount.value}`, uniqueRuleMap.value)
+      const tips = isCombinePanpass.value
+        ? `收货数量:${searchCount.value},请逐套扫描组合外箱唯一码`
+        : `收货数量:${searchCount.value}`
+      uniqueCodeRef.value?.show('', '请扫描唯一码', tips, uniqueRuleMap.value)
       return false
   }
   return true