Quellcode durchsuchen

Merge branch 'master_huangjunjie' of http://121.40.253.172:3000/pengyue/jsh_erp into master_liaozeyong

# Conflicts:
#	src/main/java/com/jsh/erp/filter/LogCostFilter.java
廖泽勇 vor 1 Monat
Ursprung
Commit
8fb3439c8e
59 geänderte Dateien mit 2759 neuen und 618 gelöschten Zeilen
  1. 15 0
      docs/new_sql.sql
  2. 4 0
      jshERP-web/src/components/jeecgbiz/modal/JSelectMaterialModal.vue
  3. 4 2
      jshERP-web/src/components/tools/ImportFileModal.vue
  4. 1 1
      jshERP-web/src/mixins/JeecgListMixin.js
  5. 79 0
      jshERP-web/src/mixins/newTableMixin.js
  6. 2 2
      jshERP-web/src/views/material/MaterialList.vue
  7. 44 10
      jshERP-web/src/views/material/modules/MaterialModal.vue
  8. 207 0
      jshERP-web/src/views/stock/CheckList.vue
  9. 128 42
      jshERP-web/src/views/stock/TaskList.vue
  10. 48 19
      jshERP-web/src/views/stock/components/FilterForm.vue
  11. 405 0
      jshERP-web/src/views/stock/components/checkModal.vue
  12. 123 34
      jshERP-web/src/views/stock/components/editForm.vue
  13. 178 68
      jshERP-web/src/views/stock/components/stockModal.vue
  14. 40 12
      jshERP-web/src/views/stock/utils/table.js
  15. 5 0
      src/main/java/com/jsh/erp/constants/ExceptionConstants.java
  16. 1 0
      src/main/java/com/jsh/erp/controller/MaterialCategoryController.java
  17. 2 1
      src/main/java/com/jsh/erp/controller/MaterialExtendController.java
  18. 4 3
      src/main/java/com/jsh/erp/controller/OpenController.java
  19. 28 0
      src/main/java/com/jsh/erp/controller/pda/PdaController.java
  20. 14 1
      src/main/java/com/jsh/erp/controller/stocktaking/StocktakingController.java
  21. 43 0
      src/main/java/com/jsh/erp/datasource/entities/InventoryLog.java
  22. 2 0
      src/main/java/com/jsh/erp/datasource/entities/MaterialCategory.java
  23. 2 0
      src/main/java/com/jsh/erp/datasource/entities/MaterialCurrentStock.java
  24. 5 0
      src/main/java/com/jsh/erp/datasource/entities/MaterialExtend.java
  25. 5 5
      src/main/java/com/jsh/erp/datasource/entities/MaterialVo4Unit.java
  26. 2 0
      src/main/java/com/jsh/erp/datasource/entities/Supplier.java
  27. 9 0
      src/main/java/com/jsh/erp/datasource/mappers/InventoryLogMapper.java
  28. 2 1
      src/main/java/com/jsh/erp/datasource/mappers/MaterialCategoryMapper.java
  29. 2 0
      src/main/java/com/jsh/erp/datasource/mappers/MaterialExtendMapper.java
  30. 7 0
      src/main/java/com/jsh/erp/datasource/mappers/MaterialMapperEx.java
  31. 25 0
      src/main/java/com/jsh/erp/datasource/pda/dto/PDAInventoryDTO.java
  32. 5 0
      src/main/java/com/jsh/erp/datasource/pda/vo/PDADepotItemVO.java
  33. 30 0
      src/main/java/com/jsh/erp/datasource/pda/vo/PDATypeTree.java
  34. 87 0
      src/main/java/com/jsh/erp/datasource/tesco/request/ErpXsddReqVO.java
  35. 56 0
      src/main/java/com/jsh/erp/datasource/vo/Material4UnitPrice.java
  36. 2 0
      src/main/java/com/jsh/erp/datasource/vo/MaterialExtendVo4List.java
  37. 4 5
      src/main/java/com/jsh/erp/filter/LogCostFilter.java
  38. 8 0
      src/main/java/com/jsh/erp/service/InventoryLogService.java
  39. 28 266
      src/main/java/com/jsh/erp/service/MaterialCategoryService.java
  40. 5 0
      src/main/java/com/jsh/erp/service/MaterialExtendService.java
  41. 19 0
      src/main/java/com/jsh/erp/service/MaterialService.java
  42. 13 0
      src/main/java/com/jsh/erp/service/SupplierService.java
  43. 432 77
      src/main/java/com/jsh/erp/service/SyncTescoSystemService.java
  44. 8 0
      src/main/java/com/jsh/erp/service/UserBusinessService.java
  45. 10 1
      src/main/java/com/jsh/erp/service/impl/DepotHeadServiceImpl.java
  46. 46 15
      src/main/java/com/jsh/erp/service/impl/DepotItemServiceImpl.java
  47. 12 0
      src/main/java/com/jsh/erp/service/impl/InventoryLogServiceImpl.java
  48. 316 0
      src/main/java/com/jsh/erp/service/impl/MaterialCategoryServiceImpl.java
  49. 29 13
      src/main/java/com/jsh/erp/service/impl/MaterialExtendServiceImpl.java
  50. 49 2
      src/main/java/com/jsh/erp/service/impl/MaterialServiceImpl.java
  51. 23 0
      src/main/java/com/jsh/erp/service/impl/SupplierServiceImpl.java
  52. 37 1
      src/main/resources/mapper_xml/DepotHeadMapper.xml
  53. 11 5
      src/main/resources/mapper_xml/DepotItemMapper.xml
  54. 5 0
      src/main/resources/mapper_xml/InventoryLogMapper.xml
  55. 5 6
      src/main/resources/mapper_xml/MaterialCategoryMapper.xml
  56. 3 1
      src/main/resources/mapper_xml/MaterialCategoryMapperEx.xml
  57. 4 3
      src/main/resources/mapper_xml/MaterialExtendMapper.xml
  58. 64 10
      src/main/resources/mapper_xml/MaterialMapperEx.xml
  59. 12 12
      src/main/resources/mapper_xml/SupplierMapper.xml

+ 15 - 0
docs/new_sql.sql

@@ -88,6 +88,21 @@ CREATE TABLE `task_stocktaking_item` (
     PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='盘点任务关联商品表';
 
+-- 库存修改日志表
+DROP TABLE IF EXISTS `jsh_inventory_log`;
+CREATE TABLE `jsh_inventory_log` (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
+  `type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '商品修改' COMMENT '操作类型',
+  `item_id` bigint DEFAULT NULL COMMENT '单据、盘点子表id',
+  `material_id` bigint DEFAULT NULL COMMENT '商品id',
+  `material_extend_id` bigint DEFAULT NULL COMMENT '商品子表id',
+  `original_stock` int DEFAULT NULL COMMENT '原始库存',
+  `current_stock` int DEFAULT NULL COMMENT '当前库存',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  `update_user` bigint DEFAULT NULL COMMENT '更新用户',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='库存修改日志表';
+
 CREATE TABLE `apk_version` (
     `id` bigint NOT NULL COMMENT '主键ID',
     `url` varchar(255) DEFAULT NULL COMMENT '下载地址',

+ 4 - 0
jshERP-web/src/components/jeecgbiz/modal/JSelectMaterialModal.vue

@@ -104,6 +104,7 @@
               </template>
             </a-row>
           </a-form>
+          <a-button type="primary" @click="findAllSelect">一键全选</a-button>
           <a-table
             ref="table"
             :scroll="scrollTrigger"
@@ -472,6 +473,9 @@ export default {
         },
       }
     },
+    findAllSelect() {
+      this.$emit('all', this.queryParam)
+    },
   },
 }
 </script>

+ 4 - 2
jshERP-web/src/components/tools/ImportFileModal.vue

@@ -71,6 +71,7 @@ export default {
       disableMixinCreated: true,
       templateUrl: '',
       templateName: '',
+      templateDownloadName: '',
       url: {
         importExcelUrl: '',
       },
@@ -83,15 +84,16 @@ export default {
     },
   },
   methods: {
-    initModal(apiUrl, templateUrl, templateName) {
+    initModal(apiUrl, templateUrl, templateName, templateDownloadName = '供应商模板') {
       this.url.importExcelUrl = apiUrl
       this.templateUrl = templateUrl
       this.templateName = templateName
+      this.templateDownloadName = templateDownloadName
       this.visible = true
     },
     importTemplate() {
       let link = this.$refs.myLink
-      link.setAttribute('download', '供应商模板' + '.xls')
+      link.setAttribute('download', this.templateDownloadName + '.xls')
     },
     close() {
       this.$emit('close')

+ 1 - 1
jshERP-web/src/mixins/JeecgListMixin.js

@@ -101,7 +101,7 @@ export const JeecgListMixin = {
       getAction(this.url.list, params).then((res) => {
         if (res.code === 200) {
           this.dataSource = res.data.rows
-          this.ipagination.total = res.data.total
+          this.ipagination.total = Number(res.data.total)
           this.tableAddTotalRow(this.columns, this.dataSource)
         } else if (res.code === 510) {
           this.$message.warning(res.data)

+ 79 - 0
jshERP-web/src/mixins/newTableMixin.js

@@ -0,0 +1,79 @@
+import Vue from 'vue'
+import { cloneDeep } from 'lodash'
+export const newTableMixin = {
+  data() {
+    return {
+      ipagination: {
+        current: 1,
+        pageSize: 2,
+        pageSizeOptions: ['2', '20', '30', '50', '100'],
+        showTotal: (total, range) => {
+          return range[0] + '-' + range[1] + ' 共' + total + '条'
+        },
+        showQuickJumper: true,
+        showSizeChanger: true,
+        total: 0,
+      },
+      /* table选中keys*/
+      selectedRowKeys: [],
+      /* table选中records*/
+      selectionRows: [],
+      /* 排序参数 */
+      isorter: {
+        column: 'createTime',
+        order: 'desc',
+      },
+      editableData: {},
+      // colList: ['categoryName', 'newPosition', 'differenceCount', 'differenceReason'],
+      colList: ['categoryName'],
+    }
+  },
+  methods: {
+    onSelectChange(selectedRowKeys, selectionRows) {
+      this.selectedRowKeys = selectedRowKeys
+      this.selectionRows = selectionRows
+    },
+    handleTableChange(pagination, filters, sorter) {
+      //分页、排序、筛选变化时触发
+      if (Object.keys(sorter).length > 0) {
+        if (sorter.order) {
+          this.isorter.column = sorter.field
+          this.isorter.order = 'ascend' === sorter.order ? 'asc' : 'desc'
+        } else {
+          this.isorter.column = 'createTime'
+          this.isorter.order = 'desc'
+        }
+      }
+      if (pagination && pagination.current) {
+        this.ipagination = pagination
+      }
+      this.getList()
+    },
+    formateTaskStatus(type) {
+      switch (type) {
+        case 1:
+          return '未开始'
+        case 2:
+          return '进行中'
+        case 3:
+          return '已完成'
+        case 4:
+          return '已取消'
+        default:
+          return ''
+      }
+    },
+    edit(id, col) {
+      this.editableData[id] = cloneDeep(this.dataSource.filter((item) => id === item.id)[0])
+      this.$forceUpdate()
+      console.log('111111111111111111111', col)
+    },
+    save(id) {
+      Object.assign(this.dataSource.filter((item) => id === item.id)[0], this.editableData[id])
+      delete this.editableData[id]
+    },
+    cancel(id) {
+      delete this.editableData[id]
+    },
+  },
+}

+ 2 - 2
jshERP-web/src/views/material/MaterialList.vue

@@ -549,8 +549,8 @@ export default {
     handleImportXls() {
       let importExcelUrl = this.url.importExcelUrl
       let templateUrl = '/doc/goods_template.xls'
-      let templateName = '商品Excel模板[下载]'
-      this.$refs.modalImportForm.initModal(importExcelUrl, templateUrl, templateName)
+      let templateName = '商品信息导入模版[下载]'
+      this.$refs.modalImportForm.initModal(importExcelUrl, templateUrl, templateName, '商品信息导入模版')
       this.$refs.modalImportForm.title = '商品导入'
     },
     searchReset() {

+ 44 - 10
jshERP-web/src/views/material/modules/MaterialModal.vue

@@ -111,14 +111,47 @@
                   </a-row>
                 </a-form-item>
               </a-col>
+           
             </a-row>
             <a-row class="form-row" :gutter="24">
+              <a-col :md="6" :sm="24" v-if="!model.id">
+                <a-form-item
+                  :labelCol="labelCol"
+                  :wrapperCol="wrapperCol"
+                  label="多属性"
+                  data-step="5"
+                  data-title="多属性"
+                  data-intro="多属性是针对的sku商品(比如服装、鞋帽行业),此处开关如果启用就可以在下方进行多sku的配置,配置具体的颜色、尺码之类的组合"
+                >
+                  <a-tooltip title="多属性针对服装、鞋帽等行业,需要先录入单位才能激活此处输入框">
+                    <a-tag class="tag-info" v-if="!manySkuStatus">需要先录入单位才能激活</a-tag>
+                    <a-select
+                      mode="multiple"
+                      v-decorator="['manySku']"
+                      showSearch
+                      optionFilterProp="children"
+                      placeholder="请选择多属性(可多选)"
+                      @change="onManySkuChange"
+                      v-show="manySkuStatus"
+                    >
+                      <a-select-option
+                        v-for="(item, index) in materialAttributeList"
+                        :key="index"
+                        :value="item.value"
+                        :disabled="item.disabled"
+                      >
+                        {{ item.name }}
+                      </a-select-option>
+                    </a-select>
+                  </a-tooltip>
+                </a-form-item>
+              </a-col>
               <a-col :md="6" :sm="24">
                 <a-form-item
                   :labelCol="labelCol"
                   :wrapperCol="wrapperCol"
                   label="颜色"
-                  data-step="5"
+                  data-step="6"
                   data-title="颜色"
                   data-intro="请填写商品的颜色,如果是多属性商品可以不填(下面有多属性开关)"
                 >
@@ -130,7 +163,7 @@
                   :labelCol="labelCol"
                   :wrapperCol="wrapperCol"
                   label="品牌"
-                  data-step="6"
+                  data-step="7"
                   data-title="品牌"
                   data-intro="请填写商品的品牌,方便区别不同品牌的商品"
                 >
@@ -142,19 +175,22 @@
                   :labelCol="labelCol"
                   :wrapperCol="wrapperCol"
                   label="助记码"
-                  data-step="7"
+                  data-step="8"
                   data-title="助记码"
                   data-intro="助记码自动生成,助记码是商品名称的首字母缩写"
                 >
                   <a-input placeholder="" v-decorator.trim="['mnemonic']" :readOnly="true" />
                 </a-form-item>
               </a-col>
+    
+            </a-row>
+            <a-row class="form-row" :gutter="24">
               <a-col :md="6" :sm="24">
                 <a-form-item
                   :labelCol="labelCol"
                   :wrapperCol="wrapperCol"
                   label="类别"
-                  data-step="8"
+                  data-step="9"
                   data-title="类别"
                   data-intro="类别需要在【商品类别】页面进行录入,录入之后在此处进行调用"
                 >
@@ -169,14 +205,12 @@
                   </a-tree-select>
                 </a-form-item>
               </a-col>
-            </a-row>
-            <a-row class="form-row" :gutter="24">
               <a-col :md="6" :sm="24">
                 <a-form-item
                   :labelCol="labelCol"
                   :wrapperCol="wrapperCol"
                   label="基础重量"
-                  data-step="9"
+                  data-step="10"
                   data-title="基础重量"
                   data-intro="请填写基本单位对应的重量,用于计算按重量分摊费用时单据中各行商品分摊的费用成本"
                 >
@@ -188,7 +222,7 @@
                   :labelCol="labelCol"
                   :wrapperCol="wrapperCol"
                   label="序列号"
-                  data-step="10"
+                  data-step="11"
                   data-title="序列号"
                   data-intro="此处是商品的序列号开关,如果选择了有,则在采购入库单据需要录入该商品的序列号,在销售出库单据需要选择该商品的序列号进行出库"
                 >
@@ -205,7 +239,7 @@
                   :labelCol="labelCol"
                   :wrapperCol="wrapperCol"
                   label="系统SKU"
-                  data-step="11"
+                  data-step="12"
                   data-title="系统SKU"
                   data-intro="系统SKU"
                 >
@@ -217,7 +251,7 @@
                   :labelCol="labelCol"
                   :wrapperCol="wrapperCol"
                   label="无动销提醒周期"
-                  data-step="12"
+                  data-step="13"
                   data-title="无动销提醒周期"
                   data-intro="无动销提醒周期"
                 >

+ 207 - 0
jshERP-web/src/views/stock/CheckList.vue

@@ -0,0 +1,207 @@
+<template>
+  <a-row :gutter="24">
+    <a-col :md="24">
+      <a-card :bordered="false">
+        <!-- 查询区域 -->
+        <filter-form
+          @search="getList"
+          :queryParam="queryParam"
+          :spinnerList="spinnerList"
+          :deoptData="deoptData"
+        ></filter-form>
+        <div style="margin-bottom: 6px">
+          <a-button type="primary" icon="plus" @click="addTask('add')">开始盘点</a-button>
+
+          <!-- <a-popconfirm style="margin: 0 6px" title="确定取消选中的盘点任务吗?" @confirm="() => cancelTask()">
+            <a-button :disabled="!selectedRowKeys.length">取消盘点</a-button>
+          </a-popconfirm>
+          <a-popconfirm title="确定删除选中的盘点任务吗?" @confirm="() => handleDelete()">
+            <a-button :disabled="!selectedRowKeys.length">批量删除</a-button>
+          </a-popconfirm> -->
+          <!-- <a-button style="margin-left: 6px">导出任务</a-button> -->
+        </div>
+        <a-table
+          ref="table"
+          size="middle"
+          bordered
+          rowKey="id"
+          :columns="columns"
+          :dataSource="dataSource"
+          :pagination="ipagination"
+          :scroll="scroll"
+          :loading="loading"
+          :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
+          @change="handleTableChange"
+        >
+          <template slot="taskType" slot-scope="value">
+            {{ value === 1 ? '全盘' : '抽盘' }}
+          </template>
+          <template slot="taskStatus" slot-scope="value">
+            {{ formateTaskStatus(value) }}
+          </template>
+          <span slot="action" slot-scope="text, record">
+            <a @click="addTask('detail', record)">查看</a>
+            <a-divider type="vertical" />
+            <a @click="addTask('edit', record)">编辑</a>
+            <a-divider type="vertical" />
+            <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
+              <a>删除</a>
+            </a-popconfirm>
+          </span>
+        </a-table>
+      </a-card>
+    </a-col>
+    <check-modal
+      :spinnerList="spinnerList"
+      :deoptData="deoptData"
+      :stockVisible.sync="stockVisible"
+      :title="title"
+      :rules="rules"
+      :taskId="taskId"
+      :openType="openType"
+      ref="stockF"
+    ></check-modal>
+  </a-row>
+</template>
+
+<script>
+// import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+import FilterForm from './components/FilterForm.vue'
+import table from './utils/table'
+// import StockModal from './components/stockModal.vue'
+import { getAction, postAction } from '@/api/manage'
+import { newTableMixin } from '@/mixins/newTableMixin'
+import CheckModal from './components/checkModal.vue'
+
+export default {
+  components: { FilterForm, CheckModal },
+  mixins: [newTableMixin],
+  data() {
+    return {
+      description: '盘点任务列表',
+      // 表头
+      scroll: { x: 1500 },
+      // 权限按钮集合
+      btnEnableList: [1, 1, 1],
+      queryParam: {
+        taskStatus: '',
+        number: '',
+        depotId: '',
+        createBy: '',
+      },
+      // stockTable: {
+      //   loading: false,
+      //   dataSource: [],
+      //   columns: table.taskColumns,
+      // },
+      columns: table.taskColumns,
+      dataSource: [],
+      loading: false,
+
+      rules: {
+        taskType: { rules: [{ required: true, message: '请选择盘点类型' }] },
+        depotId: { rules: [{ required: true, message: '请选择盘点仓库' }] },
+        taskName: { rules: [{ required: true, message: '请输入盘点任务名称' }] },
+      },
+
+      // rules: {
+      //   number: { rules: [{ required: true, message: '请输入盘点编号' }] },
+      // },
+
+      url: {
+        list: '/stocktaking/list',
+        add: '/stocktaking/add',
+        detailList: '/stocktaking/detail',
+        spinnerList: '/stocktaking/creatorSpinnerList',
+        depotList: '/depot/findDepotByCurrentUser',
+        detailByItemList: '/stocktaking/detailByItemList',
+        delete: '/stocktaking/taskDelete/',
+        cancel: '/stocktaking/taskCancel/',
+      },
+      stockVisible: false,
+      title: '',
+      spinnerList: [],
+      deoptData: [],
+      taskId: '',
+      openType: 'add',
+    }
+  },
+  watch: {
+    stockVisible(val) {
+      if (!val) {
+        this.getList()
+      }
+    },
+  },
+  created() {
+    this.getList()
+    this.getSpinnerList(), this.getDepotList()
+  },
+  methods: {
+    addTask(type, data) {
+      this.taskId = ''
+      this.openType = type
+      this.title = type === 'add' ? '新增' : type === 'edit' ? '编辑' : '查看'
+      if (type !== 'add') {
+        this.getDetailList(data.id)
+      }
+      this.stockVisible = true
+    },
+    getList(type) {
+      if (type === 'search') this.ipagination.current = 1 // 重新加载数据时,重置当前页为第一页
+      if (type === 'reset') {
+        for (let i in this.queryParam) {
+          this.$set(this.queryParam, i, null)
+        }
+      }
+      const url = this.url.list + '?pageNum=' + this.ipagination.current + '&pageSize=' + this.ipagination.pageSize
+      this.loading = true
+      const params = { ...this.queryParam }
+      postAction(url, params).then((res) => {
+        this.dataSource = res.data.rows
+        this.ipagination.total = Number(res.data.total)
+        this.loading = false
+      })
+    },
+    getDetailList(id) {
+      this.taskId = id
+    },
+
+    getSpinnerList() {
+      getAction(this.url.spinnerList).then((res) => {
+        this.spinnerList = res.data || []
+      })
+    },
+
+    getDepotList() {
+      getAction(this.url.depotList).then((res) => {
+        this.deoptData = res.data.map((item) => {
+          return {
+            label: item.depotName,
+            value: item.id,
+          }
+        })
+      })
+    },
+
+    handleDelete(id) {
+      const ids = id || this.selectedRowKeys
+      const url = this.url.delete + ids
+      getAction(url).then((res) => {
+        this.$message.success('删除成功')
+        this.getList()
+      })
+    },
+    cancelTask() {
+      const ids = this.selectedRowKeys
+      const url = this.url.cancel + ids
+      getAction(url).then((res) => {
+        this.$message.success('取消成功')
+        this.getList()
+      })
+    },
+  },
+}
+</script>
+
+<style></style>

+ 128 - 42
jshERP-web/src/views/stock/TaskList.vue

@@ -3,12 +3,22 @@
     <a-col :md="24">
       <a-card :bordered="false">
         <!-- 查询区域 -->
-        <!-- <filter-form></filter-form> -->
-        <div>
-          <a-button type="primary" icon="plus" @click="addTask">新增盘点任务</a-button>
-          <a-button>取消盘点</a-button>
-          <a-button>批量删除</a-button>
-          <a-button>导出任务</a-button>
+        <filter-form
+          @search="getList"
+          :queryParam="queryParam"
+          :spinnerList="spinnerList"
+          :deoptData="deoptData"
+        ></filter-form>
+        <div style="margin-bottom: 6px">
+          <a-button type="primary" icon="plus" @click="addTask('add')">新增盘点任务</a-button>
+
+          <a-popconfirm style="margin: 0 6px" title="确定取消选中的盘点任务吗?" @confirm="() => cancelTask()">
+            <a-button :disabled="!selectedRowKeys.length">取消盘点</a-button>
+          </a-popconfirm>
+          <a-popconfirm title="确定删除选中的盘点任务吗?" @confirm="() => handleDelete()">
+            <a-button :disabled="!selectedRowKeys.length">批量删除</a-button>
+          </a-popconfirm>
+          <!-- <a-button style="margin-left: 6px">导出任务</a-button> -->
         </div>
         <a-table
           ref="table"
@@ -17,23 +27,24 @@
           rowKey="id"
           :columns="columns"
           :dataSource="dataSource"
-          :components="handleDrag(columns)"
           :pagination="ipagination"
           :scroll="scroll"
           :loading="loading"
           :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
           @change="handleTableChange"
         >
+          <template slot="taskType" slot-scope="value">
+            {{ value === 1 ? '全盘' : '抽盘' }}
+          </template>
+          <template slot="taskStatus" slot-scope="value">
+            {{ formateTaskStatus(value) }}
+          </template>
           <span slot="action" slot-scope="text, record">
-            <a @click="myHandleDetail(record, '采购入库', prefixNo)">查看</a>
-            <a-divider v-if="btnEnableList.indexOf(1) > -1" type="vertical" />
-            <a v-if="btnEnableList.indexOf(1) > -1" @click="myHandleEdit(record)">编辑</a>
-            <a-divider v-if="btnEnableList.indexOf(1) > -1" type="vertical" />
-            <a-popconfirm
-              v-if="btnEnableList.indexOf(1) > -1"
-              title="确定删除吗?"
-              @confirm="() => myHandleDelete(record)"
-            >
+            <a @click="addTask('detail', record)">查看</a>
+            <a-divider type="vertical" />
+            <a @click="addTask('edit', record)">编辑</a>
+            <a-divider type="vertical" />
+            <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
               <a>删除</a>
             </a-popconfirm>
           </span>
@@ -41,24 +52,29 @@
       </a-card>
     </a-col>
     <stock-modal
+      :spinnerList="spinnerList"
+      :deoptData="deoptData"
       :stockVisible.sync="stockVisible"
-      :form="form"
-      :validatorRules="validatorRules"
+      :title="title"
+      :rules="rules"
+      :taskId="taskId"
+      :openType="openType"
       ref="stockF"
     ></stock-modal>
   </a-row>
 </template>
 
 <script>
-import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+// import { JeecgListMixin } from '@/mixins/JeecgListMixin'
 import FilterForm from './components/FilterForm.vue'
 import table from './utils/table'
 import StockModal from './components/stockModal.vue'
-import { getAction } from '@/api/manage'
+import { getAction, postAction } from '@/api/manage'
+import { newTableMixin } from '@/mixins/newTableMixin'
 
 export default {
   components: { FilterForm, StockModal },
-  mixins: [JeecgListMixin],
+  mixins: [newTableMixin],
   data() {
     return {
       description: '盘点任务列表',
@@ -77,42 +93,112 @@ export default {
       //   dataSource: [],
       //   columns: table.taskColumns,
       // },
-      defColumns: table.taskColumns,
+      columns: table.taskColumns,
       dataSource: [],
-      form: {
-        number: '',
-        taskType: '',
-        taskName: '',
-        depotId: '',
-        creator: '',
-        createBy: '',
-        createTime: '',
-        positionRange: '',
-        materialExtendIdList: [],
-      },
-      validatorRules: {
+      loading: false,
+
+      rules: {
         taskType: { rules: [{ required: true, message: '请选择盘点类型' }] },
         depotId: { rules: [{ required: true, message: '请选择盘点仓库' }] },
         taskName: { rules: [{ required: true, message: '请输入盘点任务名称' }] },
       },
-      rules: {
-        number: { rules: [{ required: true, message: '请输入盘点编号' }] },
-      },
-      organId: { rules: [{ required: true, message: '请选择盘点类型' }] },
-      organId: { rules: [{ required: true, message: '请选择盘点仓库' }] },
-      organId: { rules: [{ required: true, message: '请选择盘点负责人' }] },
+
+      // rules: {
+      //   number: { rules: [{ required: true, message: '请输入盘点编号' }] },
+      // },
+
       url: {
         list: '/stocktaking/list',
         add: '/stocktaking/add',
+        detailList: '/stocktaking/detail',
+        spinnerList: '/stocktaking/creatorSpinnerList',
+        depotList: '/depot/findDepotByCurrentUser',
+        detailByItemList: '/stocktaking/detailByItemList',
+        delete: '/stocktaking/taskDelete/',
+        cancel: '/stocktaking/taskCancel/',
       },
       stockVisible: false,
+      title: '',
+      spinnerList: [],
+      deoptData: [],
+      taskId: '',
+      openType: 'add',
     }
   },
-
+  watch: {
+    stockVisible(val) {
+      if (!val) {
+        this.getList()
+      }
+    },
+  },
+  created() {
+    this.getList()
+    this.getSpinnerList(), this.getDepotList()
+  },
   methods: {
-    addTask() {
+    addTask(type, data) {
+      this.taskId = ''
+      this.openType = type
+      this.title = type === 'add' ? '新增盘点任务' : type === 'edit' ? '编辑盘点任务' : '查看盘点任务'
+      if (type !== 'add') {
+        this.getDetailList(data.id)
+      }
       this.stockVisible = true
     },
+    getList(type) {
+      if (type === 'search') this.ipagination.current = 1 // 重新加载数据时,重置当前页为第一页
+      if (type === 'reset') {
+        for (let i in this.queryParam) {
+          this.$set(this.queryParam, i, null)
+        }
+      }
+      const url = this.url.list + '?currentPage=' + this.ipagination.current + '&pageSize=' + this.ipagination.pageSize
+      this.loading = true
+      const params = { ...this.queryParam }
+      postAction(url, params).then((res) => {
+        this.dataSource = res.data.rows
+        this.ipagination.total = Number(res.data.total)
+        this.loading = false
+      })
+    },
+    getDetailList(id) {
+      this.taskId = id
+    },
+
+    getSpinnerList() {
+      getAction(this.url.spinnerList).then((res) => {
+        this.spinnerList = res.data || []
+      })
+    },
+
+    getDepotList() {
+      getAction(this.url.depotList).then((res) => {
+        this.deoptData = res.data.map((item) => {
+          return {
+            label: item.depotName,
+            value: item.id,
+          }
+        })
+      })
+    },
+
+    handleDelete(id) {
+      const ids = id || this.selectedRowKeys
+      const url = this.url.delete + ids
+      getAction(url).then((res) => {
+        this.$message.success('删除成功')
+        this.getList()
+      })
+    },
+    cancelTask() {
+      const ids = this.selectedRowKeys
+      const url = this.url.cancel + ids
+      getAction(url).then((res) => {
+        this.$message.success('取消成功')
+        this.getList()
+      })
+    },
   },
 }
 </script>

+ 48 - 19
jshERP-web/src/views/stock/components/FilterForm.vue

@@ -5,36 +5,24 @@
       <a-row :gutter="24">
         <a-col :md="6" :sm="24">
           <a-form-item label="盘点状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
-            <a-select placeholder="请选择供应商" showSearch optionFilterProp="children" v-model="queryParam.taskStatus">
-              <a-select-option v-for="(item, index) in statusList" :key="index" :value="item.id">
-                {{ item.supplier }}
-              </a-select-option>
+            <a-select placeholder="请选择供应商" showSearch :options="taskStatusList" v-model="queryParam.taskStatus">
             </a-select>
           </a-form-item>
         </a-col>
         <a-col :md="6" :sm="24">
           <a-form-item label="盘点单号" :labelCol="labelCol" :wrapperCol="wrapperCol">
-            <a-input
-              placeholder="请输入条码、名称、助记码、规格、型号等信息"
-              v-model="queryParam.number"
-            ></a-input>
+            <a-input placeholder="请输入条码、名称、助记码、规格、型号等信息" v-model="queryParam.number"></a-input>
           </a-form-item>
         </a-col>
         <a-col :md="6" :sm="24">
           <a-form-item label="盘点仓库" :labelCol="labelCol" :wrapperCol="wrapperCol">
-            <a-select placeholder="请选择盘点仓库" showSearch optionFilterProp="children" v-model="queryParam.depotId">
-              <a-select-option v-for="(item, index) in statusList" :key="index" :value="item.id">
-                {{ item.supplier }}
-              </a-select-option>
+            <a-select placeholder="请选择盘点仓库" showSearch :options="spinnerList" v-model="queryParam.depotId">
             </a-select>
           </a-form-item>
         </a-col>
         <a-col :md="6" :sm="24">
           <a-form-item label="创建人" :labelCol="labelCol" :wrapperCol="wrapperCol">
-            <a-select placeholder="请选择创建人" showSearch optionFilterProp="children" v-model="queryParam.createBy">
-              <a-select-option v-for="(item, index) in statusList" :key="index" :value="item.id">
-                {{ item.supplier }}
-              </a-select-option>
+            <a-select placeholder="请选择创建人" showSearch :options="deoptData" v-model="queryParam.createBy">
             </a-select>
           </a-form-item>
         </a-col>
@@ -51,12 +39,12 @@
           <a-form-item label="商品信息" :labelCol="labelCol" :wrapperCol="wrapperCol">
             <a-input placeholder="请输入商品信息" v-model="queryParam.number"></a-input>
           </a-form-item>
-        </a-col>
+        </a-col> -->
         <span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
           <a-col :md="6" :sm="24">
             <a-button type="primary" @click="searchQuery">查询</a-button>
             <a-button style="margin-left: 8px" @click="searchReset">重置</a-button>
-          </a-col> -->
+          </a-col>
         </span>
       </a-row>
     </a-form>
@@ -64,7 +52,48 @@
 </template>
 
 <script>
-export default {}
+export default {
+  props: {
+    queryParam: {
+      type: Object,
+      default: () => {},
+    },
+    spinnerList: {
+      type: Array,
+      default: () => [],
+    },
+    deoptData: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data() {
+    return {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 },
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 },
+      },
+      taskStatusList: [
+        { value: 1, label: '未开始' },
+        { value: 2, label: '进行中' },
+        { value: 3, label: '已完成' },
+        { value: 4, label: '已取消' },
+      ],
+    }
+  },
+  methods: {
+    searchQuery() {
+      this.$emit('search', 'search')
+    },
+    searchReset() {
+      this.$emit('search', 'reset')
+    },
+  },
+}
 </script>
 
 <style></style>

+ 405 - 0
jshERP-web/src/views/stock/components/checkModal.vue

@@ -0,0 +1,405 @@
+<template>
+  <div>
+    <a-modal @cancel="handleCancel" :visible="stockVisible" :title="title" width="90%">
+      <a-spin :spinning="confirmLoading">
+        <edit-form
+          :spinnerList="spinnerList"
+          :depotList="deoptData"
+          :form="form"
+          :rules="rules"
+          :stockVisible="stockVisible"
+          ref="editForm"
+          :total="dataSource.length || 0"
+          openType="detail"
+          :stockType="stockType"
+          @getForm="getForm"
+          @clear="onClearList"
+        ></edit-form>
+        <a-divider />
+        <div>
+          <div>
+            <a-form :form="queryParams" ref="form">
+              <a-row class="form-row" :gutter="24">
+                <a-col :lg="6" :md="12" :sm="24" class="form-col">
+                  <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="商品类别">
+                    <!-- <a-input disabled placeholder="请输入" v-model="queryParams.categoryId" /> -->
+                    <a-tree-select
+                      style="width: 100%"
+                      :dropdownStyle="{ maxHeight: '200px', overflow: 'auto' }"
+                      allow-clear
+                      :treeData="categoryTree"
+                      v-model="queryParams.categoryId"
+                      placeholder="请选择商品类别"
+                    >
+                    </a-tree-select>
+                  </a-form-item>
+                </a-col>
+                <a-col :lg="6" :md="12" :sm="24" class="form-col">
+                  <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="商品名称">
+                    <a-input placeholder="请输入" v-model="queryParams.name" />
+                  </a-form-item>
+                </a-col>
+                <a-col :lg="6" :md="12" :sm="24" class="form-col">
+                  <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="批次号">
+                    <a-input placeholder="请输入" v-model="queryParams.batchNumber" />
+                  </a-form-item>
+                </a-col>
+                <a-col :lg="6" :md="12" :sm="24" class="form-col">
+                  <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="仓位货架">
+                    <a-input placeholder="请输入" v-model="queryParams.position" />
+                  </a-form-item>
+                </a-col>
+                <a-col :lg="6" :md="12" :sm="24" class="form-col">
+                  <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="是否存在数量差异">
+                    <a-select placeholder="请选择" v-model="form.isDifference" :options="isDifferenceData"> </a-select>
+                  </a-form-item>
+                </a-col>
+                <span>
+                  <a-col :md="6" :sm="24">
+                    <a-button type="primary" @click="getList">查询</a-button>
+                    <a-button style="margin-left: 8px" @click="getList">重置</a-button>
+                  </a-col>
+                </span>
+              </a-row>
+            </a-form>
+          </div>
+          <a-table
+            ref="table"
+            size="middle"
+            bordered
+            rowKey="id"
+            :columns="columns"
+            :dataSource="dataSource"
+            :pagination="ipagination"
+            :loading="loading"
+            @change="handleTableChange"
+          >
+            <!-- <template v-for="col in colList" :slot="col" slot-scope="text, record">
+              <div :key="col">
+                <a-input v-if="editableData[record.id]" v-model="editableData[record.id][col]" style="margin: -5px 0" />
+                <template v-else>
+                  {{ col }}
+                </template>
+              </div>
+            </template> -->
+            <span slot="action" v-if="openType !== 'detail'" slot-scope="text, record">
+              <a type="text" @click="handleEdit(record)">编辑</a>
+            </span>
+            <!-- <template slot="customName" slot-scope="text, record">
+          {{ record.name }}
+          <a-tag v-if="record.enableSerialNumber == 1" color="orange">序</a-tag>
+          <a-tag v-if="record.enableBatchNumber == 1" color="orange">批</a-tag>
+        </template> -->
+          </a-table>
+        </div>
+      </a-spin>
+      <template slot="footer">
+        <a-button @click="handleCancel">取消</a-button>
+        <a-button v-if="isShowBtn" @click="handleCancel">完成盘点</a-button>
+        <a-button v-if="isShowBtn" @click="handleOk" type="primary">确认更新盘点数据</a-button>
+      </template>
+    </a-modal>
+    <j-select-material-modal
+      @ok="getGoods"
+      @all="findAllSelect"
+      ref="selectModal"
+      :multi="true"
+    ></j-select-material-modal>
+    <a-modal @cancel="editVisible = false" @ok="onSubmitGoods" :visible="editVisible" title="编辑" width="50%">
+      <a-form :form="editForm">
+        <a-form-item label="盘点任务名称" :labelCol="{ span: 4 }" :wrapperCol="{ span: 14 }">
+          <a-input disabled v-model="editForm.name" placeholder="请输入"></a-input>
+        </a-form-item>
+        <a-form-item label="批次号" :labelCol="{ span: 4 }" :wrapperCol="{ span: 14 }">
+          <a-input disabled v-model="editForm.batchNumber" placeholder="请输入"></a-input>
+        </a-form-item>
+        <a-form-item label="实际库存" :labelCol="{ span: 4 }" :wrapperCol="{ span: 14 }">
+          <a-input v-model="editForm.newInventory" placeholder="请输入"></a-input>
+        </a-form-item>
+        <a-form-item label="实际仓位货架" :labelCol="{ span: 4 }" :wrapperCol="{ span: 14 }">
+          <a-input v-model="editForm.newPosition" placeholder="请输入"></a-input>
+        </a-form-item>
+        <a-form-item label="差异数量" :labelCol="{ span: 4 }" :wrapperCol="{ span: 14 }">
+          <a-input v-model="editForm.differenceCount" placeholder="请输入"></a-input>
+        </a-form-item>
+        <a-form-item label="差异原因" :labelCol="{ span: 4 }" :wrapperCol="{ span: 14 }">
+          <a-input v-model="editForm.differenceReason" placeholder="请输入"></a-input>
+        </a-form-item>
+      </a-form>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import { findBySelectOrgan, queryMaterialCategoryTreeList, getAllOrganizationTreeByUser } from '@/api/api'
+
+import editForm from './editForm.vue'
+import table from '../utils/table'
+import JSelectMaterialModal from '../../../components/jeecgbiz/modal/JSelectMaterialModal.vue'
+import { getAction, postAction } from '@/api/manage'
+import { getMaterialByBatchNumber } from '@/api/api'
+import { newTableMixin } from '@/mixins/newTableMixin'
+// import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+// import { Form } from 'ant-design-vue'
+// const useForm = Form.useForm
+export default {
+  components: { editForm, JSelectMaterialModal },
+  mixins: [newTableMixin],
+  props: {
+    rules: {
+      type: Object,
+      default: () => {
+        return {}
+      },
+    },
+
+    stockVisible: {
+      type: Boolean,
+      default: false,
+    },
+    title: {
+      type: String,
+      default: '新增',
+    },
+    spinnerList: {
+      type: Array,
+      default: () => [],
+    },
+    deoptData: {
+      type: Array,
+      default: () => [],
+    },
+    taskId: {
+      type: String,
+      default: '',
+    },
+    openType: {
+      type: String,
+      default: 'add',
+    },
+  },
+  data() {
+    return {
+      width: '1600px',
+      visible: false,
+      confirmLoading: false,
+      prefixNo: '',
+      loading: false,
+      dataSource: [],
+      columns: table.checkGoodsColumns,
+      url: {
+        add: '/stocktaking/add',
+        update: '/stocktaking/detailUpdate',
+        edit: '/stocktaking/itemUpdate',
+      },
+      form: {},
+      isShow: false,
+      stockType: 'check',
+      queryParams: { categoryId: '', materialName: '', batchNumber: '', position: '', isDifference: null },
+      isDifferenceData: [
+        {
+          label: '是',
+          value: '1',
+        },
+        {
+          label: '否',
+          value: '2',
+        },
+      ],
+      categoryTree: [],
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 },
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 },
+      },
+      editForm: {},
+      editVisible: false,
+    }
+  },
+  watch: {
+    stockVisible(val) {
+      this.loadCategoryTreeData()
+      if (val) {
+        if (this.taskId) {
+          this.$nextTick(() => {
+            this.getDetailList(this.taskId)
+          })
+
+          return
+        }
+      } else {
+        this.dataSource = []
+        this.ipagination.current = 1
+        this.loading = false
+      }
+    },
+    editVisible(val) {
+      if (!val) {
+        this.editForm = {}
+        this.form.resetFields()
+      }
+    },
+  },
+  computed: {
+    isShowBtn() {
+      return this.openType !== 'detail' || this.form.taskStatus !== 1
+    },
+  },
+  methods: {
+    handleEdit(data) {
+      this.editForm = { ...data }
+      this.editVisible = true
+    },
+    onSubmitGoods() {
+      postAction(this.url.edit, this.editForm).then((res) => {
+        this.$message.success('操作成功')
+        this.editVisible = false
+      })
+    },
+    loadCategoryTreeData() {
+      let params = {}
+      params.id = ''
+      queryMaterialCategoryTreeList(params).then((res) => {
+        if (res) {
+          this.categoryTree = []
+          for (let i = 0; i < res.length; i++) {
+            let temp = res[i]
+            this.categoryTree.push(temp)
+          }
+        }
+      })
+    },
+    handleCancel() {
+      this.$emit('update:stockVisible', false)
+    },
+    handleOk() {
+      this.$refs.editForm.form.validateFields((err, values) => {
+        if (!err) {
+          const params = { ...values }
+          if (params.taskType === 2) {
+            params.materialExtendIdList = this.dataSource.map((item) => item.batchNumber)
+          }
+          const url = this.openType === 'add' ? this.url.add : this.url.update
+          postAction(url, params).then((res) => {
+            this.$message.success('操作成功')
+            this.handleCancel()
+          })
+        }
+      })
+    },
+    onChangeGoods() {
+      this.$refs.selectModal.queryParam.depotId = this.form.depotId
+      this.$refs.selectModal.showModal()
+    },
+    getDetailList(id) {
+      const url = '/stocktaking/detail/' + id
+      const form = this.$refs['editForm'].form
+
+      getAction(url).then((res) => {
+        const {
+          depotId,
+          taskName,
+          taskStatus,
+          taskType,
+          createTime,
+          createByName,
+          materialCount,
+          positionRange,
+          creator,
+          id,
+          operBy,
+          operTime,
+        } = res.data
+        form.setFieldsValue({
+          depotId,
+          taskName,
+          taskStatus,
+          taskType,
+          createTime,
+          createByName,
+          materialCount,
+          positionRange,
+          creator,
+          id,
+          operBy,
+          operTime,
+        })
+        this.getList(id)
+      })
+    },
+    getList(id) {
+      const url2 = '/stocktaking/detailByItemList'
+
+      const params = { ...this.queryParams, taskStocktakingId: id }
+      const url = url2 + '?pageNum=' + this.ipagination.current + '&pageSize=' + this.ipagination.pageSize
+      postAction(url, params).then((res) => {
+        this.dataSource = res.data
+        this.ipagination.total = this.dataSource.length
+        const materialExtendIdList = this.dataSource.map((item) => item.batchNumber)
+
+        form.setFieldsValue({
+          materialExtendIdList,
+        })
+        this.getForm(form.getFieldsValue())
+      })
+    },
+    getGoods(rows, ids) {
+      const str = ids
+        .split(',')
+        .filter((item) => item)
+        .join(',')
+      this.getBatchData(str)
+    },
+    findAllSelect() {
+      const params = { ...this.$refs.selectModal.queryParam }
+      getAction('/material/findBatchNumbersBySelect', params).then((res) => {
+        this.$refs.selectModal.close()
+        this.getBatchData(res.data)
+      })
+    },
+    getBatchData(val) {
+      const batchStr = val
+        .split(',')
+        .filter((item) => item)
+        .join(',')
+      const params = {
+        batchNumber: batchStr,
+        organId: '',
+        mpList: '',
+        prefixNo: '',
+      }
+      getMaterialByBatchNumber(params).then((res) => {
+        this.dataSource.push(...res.data)
+        this.dataSource = this.dataSource.reduce((acc, cur) => {
+          const hasDuplicate = acc.some((item) => item.batchNumber === cur.batchNumber)
+          if (!hasDuplicate) {
+            acc.push(cur)
+          }
+          return acc
+        }, [])
+      })
+    },
+    getForm(val) {
+      this.form = val
+      this.$refs['editForm'].model = val
+    },
+    //删除
+    handleDelete(record) {
+      this.dataSource = this.dataSource.filter((item) => item.batchNumber !== record.batchNumber)
+    },
+
+    onClearList(val) {
+      this.dataSource = []
+      this.getForm(val)
+      if (val.taskType === 1) {
+        this.findAllSelect()
+      }
+    },
+  },
+}
+</script>
+
+<style></style>

+ 123 - 34
jshERP-web/src/views/stock/components/editForm.vue

@@ -1,80 +1,102 @@
 <template>
-  <a-form :model="form">
+  <a-form :form="form" ref="form">
     <a-row class="form-row" :gutter="24">
       <a-col :lg="6" :md="12" :sm="24" class="form-col">
         <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点单号">
-          <a-input placeholder="请输入" v-model="form.number" />
+          <a-input disabled placeholder="请输入" v-decorator="['number']" />
         </a-form-item>
       </a-col>
       <a-col :lg="6" :md="12" :sm="24" class="form-col">
         <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点类型">
-          <a-select placeholder="请选择" v-model="form.taskType" :options="taskTypeList"> </a-select>
+          <a-select
+            placeholder="请选择"
+            @change="handleTaskType"
+            v-decorator="['taskType', rules.taskType]"
+            :options="taskTypeList"
+            :disabled="isDisabled"
+          >
+          </a-select>
         </a-form-item>
       </a-col>
       <a-col :lg="6" :md="12" :sm="24" class="form-col">
-        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点任务名称">
-          <a-input placeholder="请输入" v-model="form.taskName" />
+        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" required prop="taskName" label="盘点任务名称">
+          <a-input placeholder="请输入" :disabled="isDisabled" v-decorator="['taskName', rules.taskName]" />
         </a-form-item>
       </a-col>
       <a-col :lg="6" :md="12" :sm="24" class="form-col">
-        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点仓库">
-          <a-select placeholder="请选择" v-model="form.depotId" :options="depotList"> </a-select>
+        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" prop="depotId" label="盘点仓库">
+          <a-select
+            placeholder="请选择"
+            v-decorator="['depotId', rules.depotId]"
+            :options="depotList"
+            :disabled="isDisabled"
+            @change="exportForm"
+          >
+          </a-select>
         </a-form-item>
       </a-col>
       <a-col :lg="6" :md="12" :sm="24" class="form-col">
         <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点负责人">
-          <a-select placeholder="请选择" v-model="form.creator" :options="spinnerList"> </a-select>
+          <a-select placeholder="请选择" v-decorator="['creator']" :options="spinnerList" :disabled="isDisabled">
+          </a-select>
         </a-form-item>
       </a-col>
       <a-col :lg="6" :md="12" :sm="24" class="form-col">
         <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="创建人">
-          <a-input placeholder="请输入" disabled v-model="form.createBy" />
+          <a-input placeholder="请输入" v-decorator="['createByName']" disabled />
         </a-form-item>
       </a-col>
       <a-col :lg="6" :md="12" :sm="24" class="form-col">
         <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="创建时间">
-          <a-input placeholder="请输入" disabled v-model="form.createTime" />
+          <a-input placeholder="请输入" disabled v-decorator="['createTime']" />
         </a-form-item>
       </a-col>
       <a-col :lg="6" :md="12" :sm="24" class="form-col">
         <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点库位范围">
-          <a-input placeholder="请输入" v-model="form.positionRange" />
+          <a-input placeholder="请输入" v-decorator="['positionRange']" disabled />
         </a-form-item>
       </a-col>
       <a-col :lg="6" :md="12" :sm="24" class="form-col">
         <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="商品数量">
-          <a-input placeholder="请输入" v-model="form.materialCount" />
+          <a-input disabled placeholder="请输入" v-decorator="['materialCount']" />
         </a-form-item>
       </a-col>
-      <a-col :lg="6" :md="12" :sm="24" class="form-col">
-        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点状态">
-          <!-- <a-input placeholder="请输入" v-model="form.taskStatus" /> -->
-          <a-select placeholder="请选择" v-model="form.taskStatus" :options="taskStatusList"> </a-select>
-        </a-form-item>
-      </a-col>
-      <!-- <a-col :lg="6" :md="12" :sm="24" class="form-col">
+      <a-col v-if="stockType === 'check'" :lg="6" :md="12" :sm="24" class="form-col">
         <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点人">
-          <a-input placeholder="请输入" v-decorator.trim="['number']" />
+          <a-input placeholder="请输入" disabled v-decorator.trim="['operBy']" />
         </a-form-item>
       </a-col>
-      <a-col :lg="6" :md="12" :sm="24" class="form-col">
+      <a-col v-if="stockType === 'check'" :lg="6" :md="12" :sm="24" class="form-col">
         <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="完成时间">
-          <a-input placeholder="请输入" v-decorator.trim="['number']" />
+          <a-input placeholder="请输入" disabled v-decorator.trim="['operTime']" />
+        </a-form-item>
+      </a-col>
+      <a-col v-show="false" :lg="6" :md="12" :sm="24" class="form-col">
+        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点状态">
+          <a-select placeholder="请选择" v-decorator="['taskStatus']" :options="taskStatusList" :disabled="isDisabled">
+          </a-select>
+        </a-form-item>
+      </a-col>
+      <a-col v-show="false" :lg="6" :md="12" :sm="24" class="form-col">
+        <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="盘点状态">
+          <a-input v-decorator="['id']"></a-input>
         </a-form-item>
-      </a-col> -->
+      </a-col>
     </a-row>
   </a-form>
 </template>
 
 <script>
+import pick from 'lodash.pick'
+
 export default {
   name: 'EditForm',
   props: {
-    form: {
-      type: Object,
-      default: null,
-    },
-    validatorRules: {
+    // form: {
+    //   type: Object,
+    //   default: null,
+    // },
+    rules: {
       type: Object,
       default: () => {
         return {}
@@ -92,9 +114,31 @@ export default {
         return []
       },
     },
+    stockVisible: {
+      type: Boolean,
+      default: false,
+    },
+    total: {
+      type: [Number, String],
+      default: 0,
+    },
+    openType: {
+      type: String,
+      default: 'add',
+    },
+    stockType: {
+      type: String,
+      default: '',
+    },
   },
   data() {
     return {
+      taskStatusList: [
+        { value: 1, label: '未开始' },
+        { value: 2, label: '进行中' },
+        { value: 3, label: '已完成' },
+        { value: 4, label: '已取消' },
+      ],
       labelCol: {
         xs: { span: 24 },
         sm: { span: 8 },
@@ -107,14 +151,59 @@ export default {
         { value: 1, label: '全盘' },
         { value: 2, label: '抽盘' },
       ],
-      taskStatusList: [
-        { value: 0, label: '未开始' },
-        { value: 1, label: '进行中' },
-        { value: 2, label: '已完成' },
-        { value: 3, label: '已取消' },
-      ],
+
+      validatorRules: {},
+      model: {},
+      form: this.$form.createForm(this),
     }
   },
+  watch: {
+    model: {
+      handler(val) {
+        console.log('=====================222', this.form.getFieldsValue())
+      },
+      deep: true,
+      immediate: true,
+    },
+    total(val) {
+      this.form.setFieldsValue({ materialCount: val })
+    },
+    // 监听弹窗显示隐藏,重置表单数据
+    stockVisible: {
+      handler(val) {
+        if (!val) {
+          this.form.resetFields()
+          this.exportForm()
+        }
+        if (this.openType === 'add') {
+          this.model.taskStatus = 1
+
+          this.$nextTick(() => {
+            this.form.setFieldsValue({ taskStatus: 1 })
+          })
+        }
+      },
+      immediate: true,
+      deep: true,
+    },
+  },
+  computed: {
+    isDisabled() {
+      return this.openType === 'detail' || this.model.taskStatus !== 1
+    },
+  },
+  methods: {
+    exportForm() {
+      this.$nextTick(() => {
+        this.$emit('getForm', this.form.getFieldsValue())
+      })
+    },
+    handleTaskType() {
+      this.$nextTick(() => {
+        this.$emit('clear', this.form.getFieldsValue())
+      })
+    },
+  },
 }
 </script>
 

+ 178 - 68
jshERP-web/src/views/stock/components/stockModal.vue

@@ -1,23 +1,26 @@
 <template>
   <div>
-    <a-modal
-      :visible="stockVisible"
-      :title="title"
-      @ok="handleOk"
-      @cancel="handleCancel"
-      width="90%"
-      wrapClassName="full-modal"
-    >
+    <a-modal @cancel="handleCancel" :visible="stockVisible" :title="title" width="90%">
       <a-spin :spinning="confirmLoading">
         <edit-form
           :spinnerList="spinnerList"
           :depotList="deoptData"
           :form="form"
-          :validatorRules="validatorRules"
+          :rules="rules"
+          :stockVisible="stockVisible"
+          ref="editForm"
+          :total="dataSource.length || 0"
+          :openType="openType"
+          :stockType="stockType"
+          @getForm="getForm"
+          @clear="onClearList"
         ></edit-form>
-        <div v-if="form.taskType === 2">
-          <a-button style="margin-bottom: 6px" type="primary" @click="onChangeGoods">选择商品</a-button>
+        <div>
+          <a-button v-if="form.taskType === 2" style="margin-bottom: 6px" type="primary" @click="onChangeGoods"
+            >选择商品</a-button
+          >
           <a-table
+            v-if="dataSource.length"
             ref="table"
             size="middle"
             bordered
@@ -29,15 +32,13 @@
             :loading="loading"
             @change="handleTableChange"
           >
-            <!-- <span slot="action" slot-scope="text, record">
-          <a>查看</a>
-          <a>编辑</a>
-          <a-divider v-if="btnEnableList.indexOf(1) > -1" type="vertical" />
-          <a-popconfirm title="确定删除吗?">
-            <a>删除</a>
-          </a-popconfirm>
-        </span>
-        <template slot="customName" slot-scope="text, record">
+            <span v-if="form.taskType === 2" slot="action" slot-scope="text, record">
+              <a-divider type="vertical" />
+              <a-popconfirm @confirm="handleDelete(record)" title="确定删除吗?">
+                <a>删除</a>
+              </a-popconfirm>
+            </span>
+            <!-- <template slot="customName" slot-scope="text, record">
           {{ record.name }}
           <a-tag v-if="record.enableSerialNumber == 1" color="orange">序</a-tag>
           <a-tag v-if="record.enableBatchNumber == 1" color="orange">批</a-tag>
@@ -45,8 +46,17 @@
           </a-table>
         </div>
       </a-spin>
+      <template slot="footer">
+        <a-button @click="handleCancel">取消</a-button>
+        <a-button v-if="isShowBtn" @click="handleOk" type="primary">确认发布盘点任务</a-button>
+      </template>
     </a-modal>
-    <j-select-material-modal @ok="getGoods" ref="selectModal" :multi="true"></j-select-material-modal>
+    <j-select-material-modal
+      @ok="getGoods"
+      @all="findAllSelect"
+      ref="selectModal"
+      :multi="true"
+    ></j-select-material-modal>
   </div>
 </template>
 
@@ -55,20 +65,22 @@ import editForm from './editForm.vue'
 import table from '../utils/table'
 import JSelectMaterialModal from '../../../components/jeecgbiz/modal/JSelectMaterialModal.vue'
 import { getAction, postAction } from '@/api/manage'
-
+import { getMaterialByBatchNumber } from '@/api/api'
+import { newTableMixin } from '@/mixins/newTableMixin'
+// import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+// import { Form } from 'ant-design-vue'
+// const useForm = Form.useForm
 export default {
   components: { editForm, JSelectMaterialModal },
+  mixins: [newTableMixin],
   props: {
-    form: {
-      type: Object,
-      default: null,
-    },
-    validatorRules: {
+    rules: {
       type: Object,
       default: () => {
         return {}
       },
     },
+
     stockVisible: {
       type: Boolean,
       default: false,
@@ -77,46 +89,61 @@ export default {
       type: String,
       default: '新增',
     },
+    spinnerList: {
+      type: Array,
+      default: () => [],
+    },
+    deoptData: {
+      type: Array,
+      default: () => [],
+    },
+    taskId: {
+      type: String,
+      default: '',
+    },
+    openType: {
+      type: String,
+      default: 'add',
+    },
   },
   data() {
     return {
-      //   validatorRules: {
-      //     organId: { rules: [{ required: true, message: '请选择盘点类型' }] },
-      //     organId: { rules: [{ required: true, message: '请选择盘点仓库' }] },
-      //     organId: { rules: [{ required: true, message: '请选择盘点负责人' }] },
-      //   },
       width: '1600px',
       visible: false,
       confirmLoading: false,
       prefixNo: '',
-      //   form: {},
-
       loading: false,
       dataSource: [],
       columns: table.goodsColums,
       url: {
-        spinnerList: '/stocktaking/creatorSpinnerList',
-        depotList: '/depot/findDepotByCurrentUser',
         add: '/stocktaking/add',
+        update: '/stocktaking/detailUpdate',
       },
-      spinnerList: [],
-      deoptData: [],
+      form: {},
+      isShow: false,
+      stockType: 'task',
     }
   },
   watch: {
     stockVisible(val) {
       if (val) {
-        this.getSpinnerList()
-        this.getDepotList()
+        if (this.taskId) {
+          this.$nextTick(() => {
+            this.getDetailList(this.taskId)
+          })
+
+          return
+        }
+      } else {
+        this.dataSource = []
+        this.ipagination.current = 1
+        this.loading = false
       }
     },
-    form: {
-      handler(val) {
-        if (val.taskType === 1) {
-          val.materialExtendIdList = []
-        }
-      },
-      deep: true,
+  },
+  computed: {
+    isShowBtn() {
+      return this.openType !== 'detail' || this.form.taskStatus !== 1
     },
   },
   methods: {
@@ -124,40 +151,123 @@ export default {
       this.$emit('update:stockVisible', false)
     },
     handleOk() {
-      postAction(this.url.add, this.form).then((res) => {
-        console.log('222222222222222222222', res)
-
-        // this.$emit('ok')
+      this.$refs.editForm.form.validateFields((err, values) => {
+        if (!err) {
+          const params = { ...values }
+          if (params.taskType === 2) {
+            params.materialExtendIdList = this.dataSource.map((item) => item.batchNumber)
+          }
+          const url = this.openType === 'add' ? this.url.add : this.url.update
+          postAction(url, params).then((res) => {
+            this.$message.success('操作成功')
+            this.handleCancel()
+          })
+        }
       })
     },
     onChangeGoods() {
+      this.$refs.selectModal.queryParam.depotId = this.form.depotId
       this.$refs.selectModal.showModal()
     },
-    getSpinnerList() {
-      getAction(this.url.spinnerList).then((res) => {
-        this.spinnerList = res.data || []
-      })
-    },
+    getDetailList(id) {
+      const url = '/stocktaking/detail/' + id
+      const url2 = '/stocktaking/detailByItemList'
+      const form = this.$refs['editForm'].form
 
-    getDepotList() {
-      getAction(this.url.depotList).then((res) => {
-        this.deoptData = res.data.map((item) => {
-          return {
-            label: item.depotName,
-            value: item.id,
-          }
+      getAction(url).then((res) => {
+        const {
+          depotId,
+          taskName,
+          taskStatus,
+          taskType,
+          createTime,
+          createByName,
+          materialCount,
+          positionRange,
+          creator,
+          id,
+        } = res.data
+        form.setFieldsValue({
+          depotId,
+          taskName,
+          taskStatus,
+          taskType,
+          createTime,
+          createByName,
+          materialCount,
+          positionRange,
+          creator,
+          id,
+        })
+
+        postAction(url2, { taskStocktakingId: id }).then((res) => {
+          this.dataSource = res.data
+          this.ipagination.total = this.dataSource.length
+          const materialExtendIdList = this.dataSource.map((item) => item.batchNumber)
+
+          form.setFieldsValue({
+            materialExtendIdList,
+          })
+          this.getForm(form.getFieldsValue())
         })
       })
     },
     getGoods(rows, ids) {
-      this.form.materialExtendIdList = ids.split(',').filter((item) => item)
-      this.dataSource = rows
+      const str = ids
+        .split(',')
+        .filter((item) => item)
+        .join(',')
+      this.getBatchData(str)
+    },
+    findAllSelect() {
+      const params = { ...this.$refs.selectModal.queryParam }
+      getAction('/material/findBatchNumbersBySelect', params).then((res) => {
+        this.$refs.selectModal.close()
+        this.getBatchData(res.data)
+      })
+    },
+    getBatchData(val) {
+      const batchStr = val
+        .split(',')
+        .filter((item) => item)
+        .join(',')
+      const params = {
+        batchNumber: batchStr,
+        organId: '',
+        mpList: '',
+        prefixNo: '',
+      }
+      getMaterialByBatchNumber(params).then((res) => {
+        this.dataSource.push(...res.data)
+        this.dataSource = this.dataSource.reduce((acc, cur) => {
+          const hasDuplicate = acc.some((item) => item.batchNumber === cur.batchNumber)
+          if (!hasDuplicate) {
+            acc.push(cur)
+          }
+          return acc
+        }, [])
+      })
+    },
+    getForm(val) {
+      this.form = val
+      this.$refs['editForm'].model = val
+    },
+    //删除
+    handleDelete(record) {
+      this.dataSource = this.dataSource.filter((item) => item.batchNumber !== record.batchNumber)
+    },
+
+    onClearList(val) {
+      this.dataSource = []
+      this.getForm(val)
+      if (val.taskType === 1) {
+        this.findAllSelect()
+      }
     },
 
     handleDrag() {},
-    ipagination() {},
-    selectedRowKeys() {},
-    onSelectChange() {},
+    // ipagination() {},
+
     handleTableChange() {},
   },
 }

+ 40 - 12
jshERP-web/src/views/stock/utils/table.js

@@ -7,48 +7,50 @@ const table = {
     },
     {
       title: '盘点任务编号',
-      dataIndex: 'num',
+      dataIndex: 'number',
     },
 
     {
       title: '盘点任务名称',
-      dataIndex: 'name',
+      dataIndex: 'taskName',
     },
     {
       title: '盘点类型',
-      dataIndex: 'type',
+      dataIndex: 'taskType',
+      scopedSlots: { customRender: 'taskType' },
     },
     {
       title: '盘点仓库',
-      dataIndex: 'num',
+      dataIndex: 'depotName',
     },
     {
       title: '商品数量',
-      dataIndex: 'time',
+      dataIndex: 'materialCount',
     },
     {
       title: '盘点库位范围',
-      dataIndex: 'status',
+      dataIndex: 'positionRange',
     },
     {
       title: '创建人',
-      dataIndex: 'person',
+      dataIndex: 'createByName',
     },
     {
       title: '创建时间',
-      dataIndex: 'status',
+      dataIndex: 'createTime',
     },
     {
       title: '盘点负责人',
-      dataIndex: 'person',
+      dataIndex: 'creatorName',
     },
     {
       title: '盘点状态',
-      dataIndex: 'remark',
+      dataIndex: 'taskStatus',
+      scopedSlots: { customRender: 'taskStatus' },
     },
     {
       title: '完成时间',
-      dataIndex: 'remark',
+      dataIndex: 'operTime',
     },
   ],
   goodsColums: [
@@ -56,9 +58,11 @@ const table = {
       title: '操作',
       dataIndex: 'action',
       align: 'center',
-      width: 60,
+      width: 90,
       scopedSlots: { customRender: 'action' },
     },
+    { dataIndex: 'id', title: 'id' },
+
     // { dataIndex: 'mBarCode', title: '条码', scopedSlots: { customRender: 'customBarCode' } },
     { dataIndex: 'batchNumber', title: '批次号' },
     { dataIndex: 'name', title: '名称', scopedSlots: { customRender: 'customName' } },
@@ -77,6 +81,30 @@ const table = {
     { dataIndex: 'depotId', title: '仓库名称' },
     { dataIndex: 'position', title: '仓库货架' },
   ],
+  checkGoodsColumns: [
+    { dataIndex: 'categoryName', title: '商品类别', scopedSlots: { customRender: 'categoryName' } },
+    { dataIndex: 'name', title: '商品名称' },
+    { dataIndex: 'systemSku', title: '系统SKU' },
+    { dataIndex: 'batchNumber', title: '批次号' },
+    { dataIndex: 'unit', title: '单位' },
+    { dataIndex: 'productionDate', title: '生产日期' },
+    { dataIndex: 'supplierName', title: '供应商' },
+    { dataIndex: 'barCode', title: '商品条码' },
+    { dataIndex: 'stock', title: '库存(最小单位)' },
+    { dataIndex: 'depotId', title: '仓库名称' },
+    { dataIndex: 'position', title: '仓库货架' },
+    { dataIndex: 'newInventory', title: '实际库存' },
+    { dataIndex: 'newPosition', title: '实际仓位货架' },
+    { dataIndex: 'differenceCount', title: '差异数量' },
+    { dataIndex: 'differenceReason', title: '差异原因' },
+    {
+      title: '操作',
+      dataIndex: 'action',
+      align: 'center',
+      width: 90,
+      scopedSlots: { customRender: 'action' },
+    },
+  ],
 }
 
 export default table

+ 5 - 0
src/main/java/com/jsh/erp/constants/ExceptionConstants.java

@@ -369,6 +369,10 @@ public class ExceptionConstants {
     public static final int MATERIAL_DEPOT_NOT_DECIMAL_CODE = 8000031;
     public static final String MATERIAL_DEPOT_NOT_DECIMAL_MSG = "第%s行仓库不存在";
 
+    //erp_sku 不存在
+    public static final int MATERIAL_ERP_SKU_NOT_DECIMAL_CODE = 8000032;
+    public static final String MATERIAL_ERP_SKU_NOT_DECIMAL_MSG = "商品erp_sku[%s]不存在";
+
     /**
      *  单据信息
      * type = 85
@@ -461,6 +465,7 @@ public class ExceptionConstants {
     public static final int DEPOT_HEAD_NOT_EXIST_CODE = 8500031;
     public static final String DEPOT_HEAD_NOT_EXIST_MSG = "抱歉,单据不存在";
 
+
     /**
      *  单据明细信息
      * type = 90

+ 1 - 0
src/main/java/com/jsh/erp/controller/MaterialCategoryController.java

@@ -8,6 +8,7 @@ import com.jsh.erp.base.TableDataInfo;
 import com.jsh.erp.datasource.entities.MaterialCategory;
 import com.jsh.erp.datasource.vo.TreeNode;
 import com.jsh.erp.service.MaterialCategoryService;
+
 import com.jsh.erp.utils.BaseResponseInfo;
 import com.jsh.erp.utils.Constants;
 import com.jsh.erp.utils.ErpInfo;

+ 2 - 1
src/main/java/com/jsh/erp/controller/MaterialExtendController.java

@@ -6,6 +6,7 @@ import com.jsh.erp.datasource.entities.MaterialExtend;
 import com.jsh.erp.datasource.vo.MaterialExtendVo4List;
 import com.jsh.erp.service.MaterialExtendService;
 import com.jsh.erp.utils.BaseResponseInfo;
+import com.jsh.erp.utils.DateUtils;
 import com.jsh.erp.utils.ErpInfo;
 import com.jsh.erp.utils.StringUtil;
 import io.swagger.annotations.Api;
@@ -108,7 +109,7 @@ public class MaterialExtendController {
                     item.put("commodityDecimal", md.getCommodityDecimal());
                     item.put("wholesaleDecimal", md.getWholesaleDecimal());
                     item.put("lowDecimal", md.getLowDecimal());
-                    item.put("productionDate",md.getProductionDate());
+                    item.put("productionDate", DateUtils.dateTime(md.getProductionDate()));
                     item.put("expiryNum",md.getExpiryNum());
                     item.put("supplierId",md.getSupplierId());
                     item.put("barCode",md.getBarCode());

+ 4 - 3
src/main/java/com/jsh/erp/controller/OpenController.java

@@ -10,6 +10,7 @@ import io.swagger.annotations.ApiOperation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -39,15 +40,15 @@ public class OpenController {
      */
     @ApiOperation(value = "获取商品系统sku,返回信息集采系统")
     @PostMapping(value = "/sync-system-sku")
-    public String syncSystemSku(String param) {
+    public String syncSystemSku(@RequestBody String param) {
         return syncTescoSystemService.syncSystemSku(param);
     }
 
 
     @ApiOperation(value = "同步集采订单-》销售订单")
     @PostMapping(value = "/sync-order")
-    public String syncOrder(String param){
-        return null;
+    public String syncOrder(@RequestBody String param){
+        return syncTescoSystemService.syncOrder(param);
     }
 
 

+ 28 - 0
src/main/java/com/jsh/erp/controller/pda/PdaController.java

@@ -8,8 +8,12 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.jsh.erp.base.AjaxResult;
 import com.jsh.erp.base.BaseController;
 import com.jsh.erp.base.TableDataInfo;
+import com.jsh.erp.datasource.entities.DepotHead;
+import com.jsh.erp.datasource.entities.MaterialVo4Unit;
+import com.jsh.erp.datasource.entities.Supplier;
 import com.jsh.erp.datasource.entities.*;
 import com.jsh.erp.datasource.pda.dto.PDADepotHeadDTO;
+import com.jsh.erp.datasource.pda.dto.PDAInventoryDTO;
 import com.jsh.erp.datasource.pda.dto.PDATaskStocktakingDTO;
 import com.jsh.erp.datasource.pda.dto.PDATaskStocktakingItemDTO;
 import com.jsh.erp.datasource.pda.vo.PDADepotHeadVO;
@@ -54,6 +58,9 @@ public class PdaController extends BaseController {
     private SupplierService supplierService;
 
     @Resource
+    private MaterialService materialService;
+
+    @Resource
     private TaskStocktakingService taskStocktakingService;
 
     @Resource
@@ -270,6 +277,27 @@ public class PdaController extends BaseController {
         return AjaxResult.success();
     }
 
+    @PostMapping("/inventoryInquiry")
+    @ApiOperation("存货查询-商品存货查询")
+    public TableDataInfo inventoryInquiry(@RequestBody PDAInventoryDTO pdaInventoryDTO){
+        startPage();
+        List<PDADepotItemVO> list = materialService.inventoryInquiry(pdaInventoryDTO);
+        return getDataTable(list);
+    }
+
+    @ApiOperation("存货查询-库位树查询")
+    @GetMapping("/inventoryPositionTree")
+    public AjaxResult inventoryPositionTree() throws Exception {
+        return AjaxResult.success(materialService.selectPosition());
+    }
+
+    @ApiOperation("存货查询-类型树查询")
+    @GetMapping("/inventoryTypeTree")
+    public AjaxResult inventoryTypeTree() throws Exception {
+        return AjaxResult.success(materialCategoryService.getMaterialCategoryTree(null));
+    }
+
+
     @ApiOperation("下载安装包")
     @PostMapping("/downloadApk")
     public void downloadApk(@RequestBody ApkVersion apkVersion, HttpServletRequest request, HttpServletResponse response) throws Exception {

+ 14 - 1
src/main/java/com/jsh/erp/controller/stocktaking/StocktakingController.java

@@ -9,11 +9,14 @@ import com.jsh.erp.datasource.dto.TaskStocktakingDTO;
 import com.jsh.erp.datasource.dto.TaskStocktakingItemDTO;
 import com.jsh.erp.datasource.dto.TaskStocktakingItemQueryDTO;
 import com.jsh.erp.datasource.dto.TaskStocktakingQueryDTO;
+import com.jsh.erp.datasource.entities.MaterialExtend;
 import com.jsh.erp.datasource.entities.TaskStocktaking;
 import com.jsh.erp.datasource.entities.TaskStocktakingItem;
 import com.jsh.erp.datasource.entities.User;
 import com.jsh.erp.datasource.vo.SpinnerVO;
 import com.jsh.erp.datasource.vo.TaskStocktakingVO;
+import com.jsh.erp.query.LambdaQueryWrapperX;
+import com.jsh.erp.service.MaterialExtendService;
 import com.jsh.erp.service.TaskStocktakingItemService;
 import com.jsh.erp.service.TaskStocktakingService;
 import com.jsh.erp.service.UserService;
@@ -41,6 +44,9 @@ public class StocktakingController extends BaseController {
     @Resource
     private TaskStocktakingItemService taskStocktakingItemService;
 
+    @Resource
+    private MaterialExtendService materialExtendService;
+
     @ApiOperation("盘点任务列表")
     @PostMapping("/list")
     public TableDataInfo list(@RequestBody TaskStocktakingQueryDTO taskStocktakingQueryDTO){
@@ -170,9 +176,16 @@ public class StocktakingController extends BaseController {
 
     @ApiOperation("任务更新库存")
     @GetMapping("/taskUpdateStock/{ids}")
-    public AjaxResult updateStock(@PathVariable("ids") Long[] ids) {
+    public AjaxResult updateStock(@PathVariable("ids") Long[] ids) throws Exception {
         for (Long id : ids) {
             taskStocktakingService.update(new UpdateWrapper<TaskStocktaking>().set("task_status", 5).eq("id", id));
+            List<TaskStocktakingItem> list = taskStocktakingItemService.list(new LambdaQueryWrapperX<TaskStocktakingItem>().eq(TaskStocktakingItem::getTaskStocktakingId,id));
+            for (TaskStocktakingItem taskStocktakingItem : list) {
+                MaterialExtend materialExtend = materialExtendService.getMaterialExtend(taskStocktakingItem.getMaterialItemId());
+                materialExtend.setInventory(taskStocktakingItem.getNewInventory());
+                materialExtend.setPosition(taskStocktakingItem.getNewPosition());
+                materialExtendService.updateInventory("盘点",taskStocktakingItem.getId(),materialExtend);
+            }
         }
         return AjaxResult.success();
     }

+ 43 - 0
src/main/java/com/jsh/erp/datasource/entities/InventoryLog.java

@@ -0,0 +1,43 @@
+package com.jsh.erp.datasource.entities;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 商品库存修改日志表实体类
+ */
+@Data
+@TableName("jsh_inventory_log")
+public class InventoryLog {
+
+    @ApiModelProperty("主键id")
+    private Long id;
+
+    @ApiModelProperty("操作类型")
+    private String type;
+
+    @ApiModelProperty("单据、盘点子表id")
+    private Long itemId;
+
+    @ApiModelProperty("商品id")
+    private Long materialId;
+
+    @ApiModelProperty("商品子表id")
+    private Long materialExtendId;
+
+    @ApiModelProperty("原始库存")
+    private Integer originalStock;
+
+    @ApiModelProperty("当前库存")
+    private Integer currentStock;
+
+    @ApiModelProperty("更新时间")
+    private Date updateTime;
+
+    @ApiModelProperty("更新用户")
+    private Long updateUser;
+
+}

+ 2 - 0
src/main/java/com/jsh/erp/datasource/entities/MaterialCategory.java

@@ -1,5 +1,6 @@
 package com.jsh.erp.datasource.entities;
 
+import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
@@ -10,6 +11,7 @@ import java.util.Date;
  */
 @Data
 @Accessors(chain = true)
+@TableName("jsh_material_category")
 public class MaterialCategory {
 
     private Long id;

+ 2 - 0
src/main/java/com/jsh/erp/datasource/entities/MaterialCurrentStock.java

@@ -1,5 +1,6 @@
 package com.jsh.erp.datasource.entities;
 
+import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
@@ -10,6 +11,7 @@ import java.math.BigDecimal;
  */
 @Data
 @Accessors(chain = true)
+@TableName("jsh_material_current_stock")
 public class MaterialCurrentStock {
     private Long id;
 

+ 5 - 0
src/main/java/com/jsh/erp/datasource/entities/MaterialExtend.java

@@ -1,8 +1,10 @@
 package com.jsh.erp.datasource.entities;
 
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import lombok.experimental.Accessors;
 
 import java.math.BigDecimal;
 import java.util.Date;
@@ -12,6 +14,7 @@ import java.util.Date;
  */
 @Data
 @TableName("jsh_material_extend")
+@Accessors
 public class MaterialExtend {
 
     @ApiModelProperty("主键id")
@@ -42,6 +45,7 @@ public class MaterialExtend {
     private String defaultFlag;
 
     @ApiModelProperty("创建日期")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
 
     @ApiModelProperty("创建人编码")
@@ -60,6 +64,7 @@ public class MaterialExtend {
     private String deleteFlag;
 
     @ApiModelProperty("生产日期")
+    @JsonFormat(pattern = "yyyy-MM-dd")
     private Date productionDate;
 
     @ApiModelProperty("保质期天数")

+ 5 - 5
src/main/java/com/jsh/erp/datasource/entities/MaterialVo4Unit.java

@@ -102,19 +102,19 @@ public class MaterialVo4Unit extends Material{
     private String depotName;
 
     @ApiModelProperty("实际出入库数量")
-    private BigDecimal actualQuantityInStorage;
+    private String actualQuantityInStorage = "";
 
     @ApiModelProperty("出入库差异")
-    private BigDecimal warehousingVariance;
+    private String warehousingVariance = "";
 
     @ApiModelProperty("出入库差异原因")
-    private String reasonOfDifference;
+    private String reasonOfDifference = "";
 
     @ApiModelProperty("出入库用户")
-    private Long warehousingUser;
+    private String warehousingUser = "";
 
     @ApiModelProperty("出入库时间")
-    private Date warehousingTime;
+    private String warehousingTime = "";
 
     @ApiModelProperty("多单位集合")
     private List<UnitListVo> unitList;

+ 2 - 0
src/main/java/com/jsh/erp/datasource/entities/Supplier.java

@@ -1,6 +1,7 @@
 package com.jsh.erp.datasource.entities;
 
 import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
 
 import java.math.BigDecimal;
 
@@ -8,6 +9,7 @@ import java.math.BigDecimal;
  * 供应商/客户信息表实体类
  *
  */
+@Data
 @TableName("jsh_supplier")
 public class Supplier {
 

+ 9 - 0
src/main/java/com/jsh/erp/datasource/mappers/InventoryLogMapper.java

@@ -0,0 +1,9 @@
+package com.jsh.erp.datasource.mappers;
+
+import com.jsh.erp.datasource.entities.InventoryLog;
+
+public interface InventoryLogMapper extends BaseMapperX<InventoryLog> {
+
+
+
+}

+ 2 - 1
src/main/java/com/jsh/erp/datasource/mappers/MaterialCategoryMapper.java

@@ -1,11 +1,12 @@
 package com.jsh.erp.datasource.mappers;
 
+import com.jsh.erp.datasource.entities.DepotHead;
 import com.jsh.erp.datasource.entities.MaterialCategory;
 import com.jsh.erp.datasource.entities.MaterialCategoryExample;
 import java.util.List;
 import org.apache.ibatis.annotations.Param;
 
-public interface MaterialCategoryMapper {
+public interface MaterialCategoryMapper extends BaseMapperX<MaterialCategory> {
     long countByExample(MaterialCategoryExample example);
 
     int deleteByExample(MaterialCategoryExample example);

+ 2 - 0
src/main/java/com/jsh/erp/datasource/mappers/MaterialExtendMapper.java

@@ -52,4 +52,6 @@ public interface MaterialExtendMapper extends BaseMapperX<MaterialExtend>{
     BigDecimal getInventorySumByDepotAndMid(@Param("depotList") List<Long> depotList,
                                             @Param("mid") long mid);
 
+    List<String> selectPosition();
+
 }

+ 7 - 0
src/main/java/com/jsh/erp/datasource/mappers/MaterialMapperEx.java

@@ -1,11 +1,14 @@
 package com.jsh.erp.datasource.mappers;
 
 import com.jsh.erp.datasource.entities.*;
+import com.jsh.erp.datasource.pda.dto.PDAInventoryDTO;
+import com.jsh.erp.datasource.pda.vo.PDADepotItemVO;
 import com.jsh.erp.datasource.vo.MaterialVoSearch;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Description
@@ -161,4 +164,8 @@ public interface MaterialMapperEx {
     List<MaterialVo4Unit> getMaterialByBatchNumber(@Param("batchNumberArray") String [] batchNumberArray);
 
     List<MaterialVo4Unit> getMaterialBySystemSku(@Param("systemSkuArray") String [] systemSkuArray);
+
+    List<PDADepotItemVO> inventoryInquiry(PDAInventoryDTO pdaInventoryDTO);
+
+
 }

+ 25 - 0
src/main/java/com/jsh/erp/datasource/pda/dto/PDAInventoryDTO.java

@@ -0,0 +1,25 @@
+package com.jsh.erp.datasource.pda.dto;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 存货查询接口
+ */
+@Data
+public class PDAInventoryDTO {
+
+    @ApiModelProperty("查询类型")
+    private String type;
+
+    @ApiModelProperty("商品种类ID")
+    private Long categoryId;
+
+    @ApiModelProperty("库位")
+    private String position;
+
+    @ApiModelProperty("关键字")
+    private String keyword;
+
+}

+ 5 - 0
src/main/java/com/jsh/erp/datasource/pda/vo/PDADepotItemVO.java

@@ -61,4 +61,9 @@ public class PDADepotItemVO{
 
     @ApiModelProperty("实际出入库数量")
     private String actualQuantityInStorage;
+
+    @ApiModelProperty("图片名称")
+    private String imgName;
+
+
 }

+ 30 - 0
src/main/java/com/jsh/erp/datasource/pda/vo/PDATypeTree.java

@@ -0,0 +1,30 @@
+package com.jsh.erp.datasource.pda.vo;
+
+import com.jsh.erp.datasource.vo.TreeNode;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * PDA库位类型树
+ */
+@Data
+public class PDATypeTree {
+
+    private Long id;
+
+    private Long key;
+
+    private String value;
+
+    /**
+     * title显示的文本
+     * */
+    private String label;
+
+    /**
+     * children 子节点
+     * */
+    private List<PDATypeTree> children;
+
+}

+ 87 - 0
src/main/java/com/jsh/erp/datasource/tesco/request/ErpXsddReqVO.java

@@ -0,0 +1,87 @@
+package com.jsh.erp.datasource.tesco.request;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @Description TODO
+ * @Author MS.BLUE
+ * @Date 2025-04-14
+ */
+@Data
+public class ErpXsddReqVO {
+
+    /**
+     * 订单编号
+     */
+    private String orderSn;
+
+    /**
+     * 订单总额
+     */
+    private BigDecimal totalPrice ;
+
+    /**
+     * 客户信息
+     */
+    private Customer customer;
+
+    /**
+     * 订单商品列表
+     */
+    private List<OrderItem> items;
+
+    @Data
+    public static class Customer {
+        /**
+         * 客户名称
+         */
+        private String name;
+
+        /**
+         * 客户账号
+         */
+        private String account;
+
+        /**
+         * 收货人姓名
+         */
+        private String receiverName;
+
+        /**
+         * 收货人电话
+         */
+        private String receiverPhone;
+
+        /**
+         * 收货人地址
+         */
+        private String receiverAddress;
+    }
+
+    @Data
+    public static class OrderItem {
+        /**
+         * ERP SKU编号
+         */
+        private String erpSku;
+
+        /**
+         * 商品单价
+         */
+        private BigDecimal unitPrice;
+
+        /**
+         * 商品下单数量
+         */
+        private Integer quantity;
+
+        /**
+         * 商品实付价格
+         */
+        private BigDecimal price;
+    }
+}

+ 56 - 0
src/main/java/com/jsh/erp/datasource/vo/Material4UnitPrice.java

@@ -0,0 +1,56 @@
+package com.jsh.erp.datasource.vo;
+
+import com.jsh.erp.datasource.entities.Unit;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @Description TODO
+ * @Author MS.BLUE
+ * @Date 2025-04-15
+ */
+@Data
+public class Material4UnitPrice extends Unit {
+
+    /**
+     *基础单位 销售价格
+     */
+    private BigDecimal basicUnitPrice;
+
+    /**
+     *其他单位 销售价格
+     */
+    private BigDecimal otherUnitPrice;
+
+    /**
+     *其他单位2 销售价格
+     */
+    private BigDecimal otherUnitTwoPrice;
+
+    /**
+     *其他单位3 销售价格
+     */
+    private BigDecimal otherUnitThreePrice;
+
+    /**
+     *基础单位 基础数量
+     */
+    private BigDecimal basicUnitNumber;
+
+    /**
+     *其他单位 基础数量
+     */
+    private BigDecimal otherUnitNumber;
+
+    /**
+     *其他单位2 基础数量
+     */
+    private BigDecimal otherUnitTwoNumber;
+
+    /**
+     *其他单位3 基础数量
+     */
+    private BigDecimal otherUnitThreeNumber;
+
+}

+ 2 - 0
src/main/java/com/jsh/erp/datasource/vo/MaterialExtendVo4List.java

@@ -1,9 +1,11 @@
 package com.jsh.erp.datasource.vo;
 
 import com.jsh.erp.datasource.entities.MaterialExtend;
+import lombok.Data;
 
 import java.math.BigDecimal;
 
+@Data
 public class MaterialExtendVo4List extends MaterialExtend {
 
     private String supplier;

+ 4 - 5
src/main/java/com/jsh/erp/filter/LogCostFilter.java

@@ -14,8 +14,7 @@ import java.io.IOException;
 @WebFilter(filterName = "LogCostFilter", urlPatterns = {"/*"},
         initParams = {@WebInitParam(name = "filterPath",
                       value = "/user/login#" +
-                              "/user/pdaLogin#" +
-                              "/pda/downloadApk#" +
+                              "user/pdaLogin#" +
                               "/user/weixinLogin#" +
                               "/user/weixinBind#" +
                               "/user/registerUser#" +
@@ -56,9 +55,9 @@ public class LogCostFilter implements Filter {
             return;
         }
         if (requestUrl != null && (requestUrl.contains("/doc.html") ||
-            requestUrl.contains("/user/pdaLogin") || requestUrl.contains("/pda/downloadApk")
-                || requestUrl.contains("/pda/selectVersion") ||
-            requestUrl.contains("/user/login") || requestUrl.contains("/user/register") || requestUrl.contains("/user/randomImage"))) {
+            requestUrl.contains("/user/pdaLogin") || requestUrl.contains("/pda/downloadApk") || requestUrl.contains("/pda/selectVersion") ||
+            requestUrl.contains("/user/login") || requestUrl.contains("/user/register") || requestUrl.contains("/user/randomImage")
+            ||requestUrl.contains("/open-api"))) {
             chain.doFilter(request, response);
             return;
         }

+ 8 - 0
src/main/java/com/jsh/erp/service/InventoryLogService.java

@@ -0,0 +1,8 @@
+package com.jsh.erp.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jsh.erp.datasource.entities.InventoryLog;
+
+public interface InventoryLogService extends IService<InventoryLog> {
+
+}

+ 28 - 266
src/main/java/com/jsh/erp/service/MaterialCategoryService.java

@@ -1,301 +1,63 @@
 package com.jsh.erp.service;
 
 import com.alibaba.fastjson.JSONObject;
-import com.jsh.erp.constants.BusinessConstants;
-import com.jsh.erp.constants.ExceptionConstants;
-import com.jsh.erp.datasource.entities.Material;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.jsh.erp.datasource.entities.MaterialCategory;
-import com.jsh.erp.datasource.entities.MaterialCategoryExample;
-import com.jsh.erp.datasource.entities.User;
-import com.jsh.erp.datasource.mappers.MaterialCategoryMapper;
-import com.jsh.erp.datasource.mappers.MaterialCategoryMapperEx;
-import com.jsh.erp.datasource.mappers.MaterialMapperEx;
 import com.jsh.erp.datasource.vo.TreeNode;
-import com.jsh.erp.exception.BusinessRunTimeException;
-import com.jsh.erp.exception.JshException;
-import com.jsh.erp.utils.PageUtils;
-import com.jsh.erp.utils.StringUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
 
-import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
-@Service
-public class MaterialCategoryService {
-    private Logger logger = LoggerFactory.getLogger(MaterialCategoryService.class);
+public interface MaterialCategoryService extends IService<MaterialCategory> {
 
-    @Resource
-    private MaterialCategoryMapper materialCategoryMapper;
-    @Resource
-    private MaterialCategoryMapperEx materialCategoryMapperEx;
-    @Resource
-    private UserService userService;
-    @Resource
-    private LogService logService;
-    @Resource
-    private MaterialMapperEx materialMapperEx;
 
-    public MaterialCategory getMaterialCategory(long id)throws Exception {
-        MaterialCategory result=null;
-        try{
-            result=materialCategoryMapper.selectByPrimaryKey(id);
-        }catch(Exception e){
-            JshException.readFail(logger, e);
-        }
-        return result;
-    }
+    MaterialCategory getMaterialCategory(long id)throws Exception;
 
-    public List<MaterialCategory> getMaterialCategoryListByIds(String ids)throws Exception {
-        List<Long> idList = StringUtil.strToLongList(ids);
-        List<MaterialCategory> list = new ArrayList<>();
-        try{
-            MaterialCategoryExample example = new MaterialCategoryExample();
-            example.createCriteria().andIdIn(idList);
-            list = materialCategoryMapper.selectByExample(example);
-        }catch(Exception e){
-            JshException.readFail(logger, e);
-        }
-        return list;
-    }
+    List<MaterialCategory> getMaterialCategoryListByIds(String ids)throws Exception;
 
-    public List<MaterialCategory> getMaterialCategory()throws Exception {
-        MaterialCategoryExample example = new MaterialCategoryExample();
-        List<MaterialCategory> list=null;
-        try{
-            list=materialCategoryMapper.selectByExample(example);
-        }catch(Exception e){
-            JshException.readFail(logger, e);
-        }
-        return list;
-    }
+    List<MaterialCategory> getMaterialCategory()throws Exception;
 
-    public List<MaterialCategory> getAllList(Long parentId)throws Exception {
-        List<MaterialCategory> list=null;
-        try{
-            list = getMCList(parentId);
-        }catch(Exception e){
-            JshException.readFail(logger, e);
-        }
-        return list;
-    }
+    List<MaterialCategory> getAllList(Long parentId)throws Exception;
 
-    public List<MaterialCategory> getMCList(Long parentId)throws Exception {
-        List<MaterialCategory> res= new ArrayList<MaterialCategory>();
-        List<MaterialCategory> list=null;
-        MaterialCategoryExample example = new MaterialCategoryExample();
-        example.createCriteria().andParentIdEqualTo(parentId).andIdNotEqualTo(1L);
-        example.setOrderByClause("id");
-        list=materialCategoryMapper.selectByExample(example);
-        if(list!=null && list.size()>0) {
-            res.addAll(list);
-            for(MaterialCategory mc : list) {
-                List<MaterialCategory> mcList = getMCList(mc.getId());
-                if(mcList!=null && mcList.size()>0) {
-                    res.addAll(mcList);
-                }
-            }
-        }
-        return res;
-    }
+    List<MaterialCategory> getMCList(Long parentId)throws Exception;
 
-    public List<MaterialCategory> select(String name, Integer parentId) throws Exception{
-        List<MaterialCategory> list=null;
-        try{
-            PageUtils.startPage();
-            list=materialCategoryMapperEx.selectByConditionMaterialCategory(name, parentId);
-        }catch(Exception e){
-            JshException.readFail(logger, e);
-        }
-        return list;
-    }
+    List<MaterialCategory> select(String name, Integer parentId) throws Exception;
 
+    /**
+     * 新增商品类别
+     * @param obj 商品类别数据
+     */
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
-    public int insertMaterialCategory(JSONObject obj, HttpServletRequest request)throws Exception {
-        MaterialCategory materialCategory = JSONObject.parseObject(obj.toJSONString(), MaterialCategory.class);
-        materialCategory.setCreateTime(new Date());
-        materialCategory.setUpdateTime(new Date());
-        materialCategory.setSerialNo(materialCategoryMapper.selectMaxId()+10001);
-        int result=0;
-        try{
-            result=materialCategoryMapper.insertSelective(materialCategory);
-            logService.insertLog("商品类型",
-                    new StringBuffer(BusinessConstants.LOG_OPERATION_TYPE_ADD).append(materialCategory.getName()).toString(), request);
-        }catch(Exception e){
-            JshException.writeFail(logger, e);
-        }
-        return result;
-    }
+    int insertMaterialCategory(JSONObject obj, HttpServletRequest request)throws Exception;
 
+    /**
+     * 修改商品类别
+     * @param obj 商品类别数据
+     */
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
-    public int updateMaterialCategory(JSONObject obj, HttpServletRequest request) throws Exception{
-        MaterialCategory materialCategory = JSONObject.parseObject(obj.toJSONString(), MaterialCategory.class);
-        materialCategory.setUpdateTime(new Date());
-        int result=0;
-        try{
-            result=materialCategoryMapperEx.editMaterialCategory(materialCategory);
-            logService.insertLog("商品类型",
-                    new StringBuffer(BusinessConstants.LOG_OPERATION_TYPE_EDIT).append(materialCategory.getName()).toString(), request);
-        }catch(Exception e){
-            JshException.writeFail(logger, e);
-        }
-        return result;
-    }
+    int updateMaterialCategory(JSONObject obj, HttpServletRequest request) throws Exception;
 
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
-    public int deleteMaterialCategory(Long id, HttpServletRequest request)throws Exception {
-        return batchDeleteMaterialCategoryByIds(id.toString());
-    }
+    int deleteMaterialCategory(Long id, HttpServletRequest request)throws Exception;
 
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
-    public int batchDeleteMaterialCategory(String ids, HttpServletRequest request)throws Exception {
-        return batchDeleteMaterialCategoryByIds(ids);
-    }
+    int batchDeleteMaterialCategory(String ids, HttpServletRequest request)throws Exception;
 
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
-    public int batchDeleteMaterialCategoryByIds(String ids) throws Exception {
-        int result=0;
-        String [] idArray=ids.split(",");
-        //校验产品表	jsh_material
-        List<Material> materialList=null;
-        try{
-            materialList= materialMapperEx.getMaterialListByCategoryIds(idArray);
-        }catch(Exception e){
-            JshException.readFail(logger, e);
-        }
-        if(materialList!=null&&materialList.size()>0){
-            logger.error("异常码[{}],异常提示[{}],参数,CategoryIds[{}]",
-                    ExceptionConstants.DELETE_FORCE_CONFIRM_CODE,ExceptionConstants.DELETE_FORCE_CONFIRM_MSG,ids);
-            throw new BusinessRunTimeException(ExceptionConstants.DELETE_FORCE_CONFIRM_CODE,
-                    ExceptionConstants.DELETE_FORCE_CONFIRM_MSG);
-        }
-        StringBuffer sb = new StringBuffer();
-        sb.append(BusinessConstants.LOG_OPERATION_TYPE_DELETE);
-        List<MaterialCategory> list = getMaterialCategoryListByIds(ids);
-        for(MaterialCategory materialCategory: list){
-            sb.append("[").append(materialCategory.getName()).append("]");
-        }
-        logService.insertLog("商品类型", sb.toString(),
-                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
-        //更新时间
-        Date updateDate =new Date();
-        //更新人
-        User userInfo=userService.getCurrentUser();
-        Long updater=userInfo==null?null:userInfo.getId();
-        String strArray[]=ids.split(",");
-        if(strArray.length<1){
-            return 0;
-        }
-        List<MaterialCategory> mcList = materialCategoryMapperEx.getMaterialCategoryListByCategoryIds(idArray);
-        if(mcList!=null && mcList.size()>0) {
-            logger.error("异常码[{}],异常提示[{}]",
-                    ExceptionConstants.MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_CODE,ExceptionConstants.MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_MSG);
-            throw new BusinessRunTimeException(ExceptionConstants.MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_CODE,
-                    ExceptionConstants.MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_MSG);
-        } else {
-            result=materialCategoryMapperEx.batchDeleteMaterialCategoryByIds(updateDate,updater,strArray);
-        }
-        return result;
-    }
+    int batchDeleteMaterialCategoryByIds(String ids) throws Exception;
 
-    public int checkIsNameExist(Long id, String name)throws Exception {
-        MaterialCategoryExample example = new MaterialCategoryExample();
-        example.createCriteria().andIdNotEqualTo(id).andNameEqualTo(name).andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED);
-        List<MaterialCategory> list=null;
-        try{
-            list= materialCategoryMapper.selectByExample(example);
-        }catch(Exception e){
-            JshException.readFail(logger, e);
-        }
-        return list==null?0:list.size();
-    }
+    int checkIsNameExist(Long id, String name)throws Exception;
 
-    public List<MaterialCategory> findById(Long id)throws Exception {
-        List<MaterialCategory> list=null;
-        if(id!=null) {
-            MaterialCategoryExample example = new MaterialCategoryExample();
-            example.createCriteria().andIdEqualTo(id);
-            try{
-                list=materialCategoryMapper.selectByExample(example);
-            }catch(Exception e){
-                JshException.readFail(logger, e);
-            }
-        }
-        return list;
-    }
-    /**
-     * description:
-     * 获取商品类别树数据
-     */
-    public List<TreeNode> getMaterialCategoryTree(Long id) throws Exception{
-        List<TreeNode> list=null;
-        try{
-            list=materialCategoryMapperEx.getNodeTree(id);
-        }catch(Exception e){
-            JshException.readFail(logger, e);
-        }
-       return list;
-    }
-    /**
-     * 根据商品类别编号判断商品类别是否已存在
-     * */
-    public void  checkMaterialCategorySerialNo(MaterialCategory mc)throws Exception {
-        if(mc==null){
-            return;
-        }
-        if( mc.getSerialNo() < 0){
-            return;
-        }
-        //根据商品类别编号查询商品类别
-        List<MaterialCategory> mList=null;
-        try{
-            mList= materialCategoryMapperEx.getMaterialCategoryBySerialNo(mc.getSerialNo(), mc.getId());
-        }catch(Exception e){
-            JshException.readFail(logger, e);
-        }
-        if(mList==null||mList.size()<1){
-            //未查询到对应数据,编号可用
-            return;
-        }
-        if(mList.size()>1){
-            //查询到的数据条数大于1,编号已存在
-            throw new BusinessRunTimeException(ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_CODE,
-                    ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_MSG);
-        }
-        if(mc.getId()==null){
-            //新增时,编号已存在
-            throw new BusinessRunTimeException(ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_CODE,
-                    ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_MSG);
-        }
-        /**
-         * 包装类型用equals来比较
-         * */
-        if(mc.getId().equals(mList.get(0).getId())){
-            //修改时,相同编号,id不同
-            throw new BusinessRunTimeException(ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_CODE,
-                    ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_MSG);
-        }
-    }
+    List<MaterialCategory> findById(Long id)throws Exception;
+
+    List<TreeNode> getMaterialCategoryTree(Long id) throws Exception;
+
+    void  checkMaterialCategorySerialNo(MaterialCategory mc)throws Exception;
 
     /**
      * 根据名称获取类型
      * @param name
      */
-    public Long getCategoryIdByName(String name){
-        Long categoryId = null;
-        MaterialCategoryExample example = new MaterialCategoryExample();
-        example.createCriteria().andNameEqualTo(name).andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED);
-        List<MaterialCategory> list = materialCategoryMapper.selectByExample(example);
-        if(list!=null && list.size()>0) {
-            categoryId = list.get(0).getId();
-        }
-        return categoryId;
-    }
+    Long getCategoryIdByName(String name);
 }

+ 5 - 0
src/main/java/com/jsh/erp/service/MaterialExtendService.java

@@ -54,4 +54,9 @@ public interface MaterialExtendService extends IService<MaterialExtend> {
     int getCountByManyBarCodeWithoutUs(String manyBarCode, String barCode);
 
     MaterialExtend getInfoByBatchNumber(String batchNumber)throws Exception;
+
+    /**
+     * 修改子商品库存
+     */
+    void updateInventory(String type, Long id,MaterialExtend materialExtend) throws Exception;
 }

+ 19 - 0
src/main/java/com/jsh/erp/service/MaterialService.java

@@ -5,6 +5,9 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.jsh.erp.datasource.entities.*;
+import com.jsh.erp.datasource.pda.dto.PDAInventoryDTO;
+import com.jsh.erp.datasource.pda.vo.PDADepotItemVO;
+import com.jsh.erp.datasource.pda.vo.PDATypeTree;
 import com.jsh.erp.datasource.vo.MaterialWarnListVo;
 import com.jsh.erp.utils.BaseResponseInfo;
 import org.springframework.transaction.annotation.Transactional;
@@ -36,6 +39,10 @@ public interface MaterialService extends IService<Material> {
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
     int insertMaterial(JSONObject obj, HttpServletRequest request)throws Exception;
 
+    /**
+     * 修改商品
+     * @param obj
+     */
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
     int updateMaterial(JSONObject obj, HttpServletRequest request) throws Exception;
 
@@ -177,4 +184,16 @@ public interface MaterialService extends IService<Material> {
 
     //导入表格
     BaseResponseInfo importExcelTwo(MultipartFile file, HttpServletRequest request) throws Exception;
+
+    /**
+     * PDA库存查询
+     * pdaInventoryDTO
+     * @return
+     */
+    List<PDADepotItemVO> inventoryInquiry(PDAInventoryDTO pdaInventoryDTO);
+
+    /**
+     * 查询库位树
+     */
+    List<PDATypeTree> selectPosition();
 }

+ 13 - 0
src/main/java/com/jsh/erp/service/SupplierService.java

@@ -89,4 +89,17 @@ public interface SupplierService extends IService<Supplier> {
 
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
     int batchSetAdvanceIn(String ids) throws Exception;
+
+    /**
+     * 根据类型 和 电话号码查询供应商/客户信息
+     * @param type
+     * @param telephone
+     * @return
+     */
+    Supplier getSupplierByPhone(String type,String telephone );
+
+    Supplier getCustomerByPhone(String telephone );
+
+    // 创建新客户
+    Supplier createCustomer(Supplier supplier);
 }

+ 432 - 77
src/main/java/com/jsh/erp/service/SyncTescoSystemService.java

@@ -1,14 +1,25 @@
 package com.jsh.erp.service;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.jsh.erp.constants.ExceptionConstants;
 import com.jsh.erp.datasource.entities.DepotHeadVo4Body;
 import com.jsh.erp.datasource.entities.MaterialVo4Unit;
+import com.jsh.erp.datasource.entities.Supplier;
+import com.jsh.erp.datasource.entities.Unit;
+import com.jsh.erp.datasource.tesco.request.ErpXsddReqVO;
 import com.jsh.erp.datasource.vo.DepotHeadXsddRequestVO;
 import com.jsh.erp.datasource.vo.DepotItemXsddRequestVO;
+import com.jsh.erp.datasource.vo.Material4UnitPrice;
+import com.jsh.erp.exception.BusinessRunTimeException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
@@ -38,6 +49,9 @@ public class SyncTescoSystemService {
     @Resource
     private SequenceService sequenceService;
 
+    @Resource
+    private SupplierService supplierService;
+
     public String syncSystemSku(String param) {
         logger.info("获取商品系统sku,返回信息集采系统 param:{}", param);
         JSONObject result = new JSONObject();
@@ -52,7 +66,7 @@ public class SyncTescoSystemService {
             }
 
             // 解析传入的JSON参数
-            JSONArray barCodeArray = JSONArray.parseArray(param);
+            JSONArray barCodeArray = JSON.parseArray(param);
             if (barCodeArray == null || barCodeArray.isEmpty()) {
                 result.put("code", 1);
                 result.put("msg", "参数格式错误");
@@ -82,13 +96,14 @@ public class SyncTescoSystemService {
                 result.put("msg", "未找到对应商品信息");
             }
         } catch (Exception e) {
+            e.printStackTrace();
             result.put("code", 1);
             result.put("msg", "系统异常,请稍后重试");
         }
 
         // 将数据数组放入返回结果
         result.put("data", dataArray);
-        logger.info("  result:{}", param);
+        logger.info("  result:{}", result);
         return result.toJSONString();
     }
 
@@ -118,39 +133,37 @@ public class SyncTescoSystemService {
         logger.info("同步集采订单-》销售订单 param:{}", param);
         JSONObject result = new JSONObject();
         try {
-            // 解析传入的JSON参数
-            JSONObject paramJson = JSONObject.parseObject(param);
-            if (paramJson == null || paramJson.isEmpty()) {
+            // 解析传入的JSON参数为 ErpXsddReqVO
+            ErpXsddReqVO erpXsddReqVO = JSON.parseObject(param, ErpXsddReqVO.class);
+            if (erpXsddReqVO == null) {
                 result.put("code", 1);
                 result.put("msg", "参数不能为空");
                 return result.toJSONString();
             }
 
             // 校验订单编号
-            String orderSn = paramJson.getString("orderSn");
-            if (orderSn == null || orderSn.isEmpty()) {
+            if (erpXsddReqVO.getOrderSn() == null || erpXsddReqVO.getOrderSn().isEmpty()) {
                 result.put("code", 1);
                 result.put("msg", "订单编号不能为空");
                 return result.toJSONString();
             }
 
             // 校验客户信息
-            JSONObject customer = paramJson.getJSONObject("customer");
-            if (customer == null || customer.isEmpty()) {
+            if (erpXsddReqVO.getCustomer() == null) {
                 result.put("code", 1);
                 result.put("msg", "客户信息不能为空");
                 return result.toJSONString();
             }
 
             // 校验订单商品信息
-            JSONArray itemArray = paramJson.getJSONArray("item");
-            if (itemArray == null || itemArray.isEmpty()) {
+            if (erpXsddReqVO.getItems() == null || erpXsddReqVO.getItems().isEmpty()) {
                 result.put("code", 1);
                 result.put("msg", "订单商品信息不能为空");
                 return result.toJSONString();
             }
 
-            buildOrderAndItem(paramJson, itemArray);
+            // 构建订单和商品信息
+            buildOrderAndItem(erpXsddReqVO);
 
             // 返回成功结果
             result.put("code", 0);
@@ -163,107 +176,449 @@ public class SyncTescoSystemService {
         return result.toJSONString();
     }
 
-    private void buildOrderAndItem(JSONObject orderJson, JSONArray itemJsonArray) throws Exception {
+    @Transactional(value = "transactionManager", rollbackFor = Exception.class)
+    private void buildOrderAndItem(ErpXsddReqVO erpXsddReqVO) throws Exception {
+        // 1. 初始化订单基本信息
+        DepotHeadXsddRequestVO order = initSalesOrder(erpXsddReqVO);
+
+        // 2. 处理订单商品项
+        List<DepotItemXsddRequestVO> itemList = processOrderItems(erpXsddReqVO, order);
+
+        // 3. 提交订单
+        depotHeadService.syncOrderToXsdd(order, itemList);
+    }
+
+    private DepotHeadXsddRequestVO initSalesOrder(ErpXsddReqVO erpXsddReqVO) throws Exception {
         DepotHeadXsddRequestVO order = new DepotHeadXsddRequestVO();
-        order.setType("其他");
+        order.setType("其");
         order.setSubType("销售订单");
-        String orderSn = orderJson.getString("orderSn");
+        order.setLinkTesco(erpXsddReqVO.getOrderSn());
+
+        ErpXsddReqVO.Customer customer = erpXsddReqVO.getCustomer();
+        // 根据手机号查询客户
+        Supplier supplier = supplierService.getCustomerByPhone(customer.getAccount());
+        if (supplier == null) {
+            // 如果客户不存在,创建新客户
+            supplier = new Supplier();
+            supplier.setSupplier(customer.getName());
+            supplier.setTelephone(customer.getAccount());
+            supplier.setContacts(customer.getReceiverName());
+            supplier.setPhoneNum(customer.getReceiverPhone());
+            supplier.setAddress(customer.getReceiverAddress());
+            supplier = supplierService.createCustomer(supplier);
+        }
 
+        // 绑定客户 ID
+        order.setOrganId(supplier.getId());
+        order.setReceiverName(customer.getReceiverName());
+        order.setReceiverPhone(customer.getReceiverPhone());
+        order.setReceiverAddress(customer.getReceiverAddress());
+        order.setRemark("集采同步订单");
         String number = sequenceService.buildOnlyNumber();
         String defaultNumber = "XSDD" + number;
         order.setDefaultNumber(defaultNumber);
         order.setNumber(defaultNumber);
         order.setCreateTime(new Date());
         order.setOperTime(new Date());
-        order.setOrganId(1L);// 供应商
-        order.setCreator(1L);// 创建人
-        order.setAccountId(1L);// 账户
+        order.setCreator(1L); // 创建人ID
+        order.setAccountId(1L); // 账户ID
         order.setChangeAmount(BigDecimal.ZERO);
         order.setBackAmount(BigDecimal.ZERO);
-        order.setTotalPrice(orderJson.getBigDecimal("totalPrice"));
+        order.setTotalPrice(erpXsddReqVO.getTotalPrice());
         order.setPayType("现付");
         order.setDiscount(BigDecimal.ZERO);
         order.setDiscountMoney(BigDecimal.ZERO);
-        order.setDiscountLastMoney(orderJson.getBigDecimal("totalPrice"));
+        order.setDiscountLastMoney(erpXsddReqVO.getTotalPrice());
         order.setStatus("0");
         order.setPurchaseStatus("0");
-        order.setSource("2");// 来源集采商城
+        order.setSource("2"); // 来源集采商城
         order.setTenantId(null);
         order.setDeleteFlag("0");
+        return order;
+    }
+
+    /**
+     * 处理订单商品项
+     */
+    private List<DepotItemXsddRequestVO> processOrderItems(ErpXsddReqVO erpXsddReqVO, DepotHeadXsddRequestVO order) throws Exception {
 
         List<DepotItemXsddRequestVO> itemList = new ArrayList<>();
+        List<ErpXsddReqVO.OrderItem> reqVOItems = erpXsddReqVO.getItems();
 
-        List<String> systemSkuList = itemJsonArray.stream().map(JSONObject.class::cast).map(json -> json.getString("erp_sku")).collect(Collectors.toList());
+        // 1. 获取所有商品信息
+        List<String> systemSkuList = reqVOItems.stream().map(ErpXsddReqVO.OrderItem::getErpSku).collect(Collectors.toList());
+        List<MaterialVo4Unit> materialList = materialService.getMaterialBySystemSku(systemSkuList);
+        Map<String, List<MaterialVo4Unit>> skuToMaterialMap = materialList.stream().collect(Collectors.groupingBy(MaterialVo4Unit::getSystemSku));
 
-        Map<String, JSONObject> skuToJsonMap = itemJsonArray.stream().map(JSONObject.class::cast).collect(Collectors.toMap(json -> json.getString("erp_sku"), json -> json));
+        // 2. 处理每个订单项
+        for (ErpXsddReqVO.OrderItem reqVOItem : reqVOItems) {
+            try {
+                processSingleOrderItem(reqVOItem, order, itemList, skuToMaterialMap);
+            } catch (Exception e) {
+                logger.error("处理订单项失败 erp_sku: {}: {}", reqVOItem.getErpSku(), e.getMessage());
+                throw e;
+            }
+        }
 
-        List<MaterialVo4Unit> materialList = materialService.getMaterialBySystemSku(systemSkuList);
+        return itemList;
+    }
 
-        Map<String, List<MaterialVo4Unit>> skuToMaterialMap = materialList.stream().collect(Collectors.groupingBy(MaterialVo4Unit::getSystemSku));
 
-        for (Map.Entry<String, JSONObject> entry : skuToJsonMap.entrySet()) {
-            String erpSku = entry.getKey(); // 获取 erp_sku
-            JSONObject itemJson = entry.getValue(); // 获取对应的 JSONObject
+    /**
+     * 处理单个订单项
+     */
+    private void processSingleOrderItem(ErpXsddReqVO.OrderItem reqVOItem, DepotHeadXsddRequestVO order, List<DepotItemXsddRequestVO> itemList, Map<String, List<MaterialVo4Unit>> skuToMaterialMap) throws Exception {
 
-            Integer quantity = itemJson.getInteger("quantity");
-            BigDecimal unitPrice = itemJson.getBigDecimal("unitPrice");
-            BigDecimal price = itemJson.getBigDecimal("price");
+        // 1. 参数校验
+        validateOrderItem(reqVOItem);
 
-            if (quantity == null || unitPrice == null || price == null) {
-                logger.warn("商品信息不完整,erp_sku: {}", erpSku);
+        // 2. 获取商品信息
+        List<MaterialVo4Unit> materials = skuToMaterialMap.get(reqVOItem.getErpSku());
+        if (CollectionUtils.isEmpty(materials)) {
+            throw new BusinessRunTimeException(ExceptionConstants.MATERIAL_ERP_SKU_NOT_DECIMAL_CODE, String.format(ExceptionConstants.MATERIAL_ERP_SKU_NOT_DECIMAL_MSG, reqVOItem.getErpSku()));
+        }
+
+        // 3. 获取单位信息
+        MaterialVo4Unit primaryMaterial = materials.get(0);
+        Material4UnitPrice material4UnitPrice = getMaterial4UnitPrice(primaryMaterial);
+
+        // 4. 匹配销售单位
+        UnitMatchResult matchResult = matchUnitAndCalculateBaseQuantity(reqVOItem.getUnitPrice(), BigDecimal.valueOf(reqVOItem.getQuantity()), material4UnitPrice);
+
+        // 5. 根据单位类型分配库存
+        if (matchResult.isLargeUnit()) {
+            allocateLargeUnitStock(reqVOItem, order, itemList, materials, matchResult, material4UnitPrice);
+        } else {
+            allocateBasicUnitStock(reqVOItem, order, itemList, materials, matchResult);
+        }
+    }
+
+    /**
+     * 分配大单位库存(不拆分配)
+     */
+    private void allocateLargeUnitStock(ErpXsddReqVO.OrderItem reqVOItem, DepotHeadXsddRequestVO order, List<DepotItemXsddRequestVO> itemList, List<MaterialVo4Unit> materials,
+        UnitMatchResult matchResult, Material4UnitPrice material4UnitPrice) throws Exception {
+
+        String orderUnit = matchResult.getMatchedUnit();
+        BigDecimal unitRatio = getUnitRatio(orderUnit, material4UnitPrice);
+        BigDecimal remainingOrderQty = matchResult.getOrderUnitQuantity();
+
+        // 分配库存
+        for (MaterialVo4Unit m : materials) {
+            if (remainingOrderQty.compareTo(BigDecimal.ZERO) <= 0)
+                break;
+
+            BigDecimal inventory = m.getInventory();
+            if (inventory.compareTo(unitRatio) < 0)
                 continue;
+
+            // 计算可分配数量(向下取整)
+            BigDecimal allocatableUnits = inventory.divideToIntegralValue(unitRatio).min(remainingOrderQty);
+
+            if (allocatableUnits.compareTo(BigDecimal.ZERO) > 0) {
+                BigDecimal allocBaseQty = allocatableUnits.multiply(unitRatio);
+
+                // 创建订单项
+                DepotItemXsddRequestVO item = createOrderItem(order, m, orderUnit, allocatableUnits, allocBaseQty, reqVOItem.getUnitPrice());
+                itemList.add(item);
+
+                // 更新库存
+                m.setInventory(inventory.subtract(allocBaseQty));
+
+                // 更新剩余需求
+                remainingOrderQty = remainingOrderQty.subtract(allocatableUnits);
+
+                logger.info("分配库存:批次[{}] 分配 {} {} (剩余需求: {})", m.getBatchNumber(), allocatableUnits.toPlainString(), orderUnit, remainingOrderQty.toPlainString());
             }
+        }
 
-            List<MaterialVo4Unit> materials = skuToMaterialMap.get(erpSku);
-
-            if (materials != null && !materials.isEmpty()) {
-                BigDecimal remainingQuantity = itemJson.getBigDecimal("quantity"); // 剩余数量
-                for (MaterialVo4Unit material : materials) {
-                    BigDecimal inventory = material.getInventory(); // 当前商品库存
-                    if (inventory.compareTo(BigDecimal.ZERO) <= 0) {
-                        continue; // 如果库存为0,跳过
-                    }
-
-                    DepotItemXsddRequestVO item = new DepotItemXsddRequestVO();
-                    item.setHeaderId(order.getId());
-                    item.setMaterialId(material.getId());
-                    item.setMaterialExtendId(material.getMeId());
-                    item.setMaterialUnit(material.getUnit());
-                    item.setSku(material.getSku());
-                    item.setDepotId(material.getDepotId());
-                    item.setTaxRate(BigDecimal.ONE);
-                    item.setTaxMoney(BigDecimal.ZERO);
-                    item.setBatchNumber("");
-                    item.setUnitPrice(unitPrice); // 设置单价
-                    if (inventory.compareTo(remainingQuantity) >= 0) {
-                        // 如果当前商品库存大于等于剩余数量,直接使用剩余数量
-                        item.setOperNumber(remainingQuantity);
-                        // 计算实付价格:单价 × 剩余数量
-                        BigDecimal taxLastMoney = itemJson.getBigDecimal("unitPrice").multiply(remainingQuantity);
-                        item.setTaxLastMoney(taxLastMoney);
-                        item.setAllPrice(taxLastMoney);
-                        itemList.add(item);
-                        break; // 结束循环
-                    } else {
-                        // 如果当前商品库存小于剩余数量,使用当前商品库存
-                        item.setOperNumber(inventory);
-                        // 计算实付价格:单价 × 剩余数量
-                        BigDecimal taxLastMoney = itemJson.getBigDecimal("unitPrice").multiply(remainingQuantity);
-                        item.setTaxLastMoney(taxLastMoney);
-                        item.setAllPrice(taxLastMoney);
-                        itemList.add(item);
-                        remainingQuantity = remainingQuantity.subtract(inventory); // 减少剩余数量
-                    }
-                }
+        // 检查是否完全分配
+        if (remainingOrderQty.compareTo(BigDecimal.ZERO) > 0) {
+            throw new RuntimeException(buildStockShortageMessage(reqVOItem.getErpSku(), matchResult.getOrderUnitQuantity(), remainingOrderQty, orderUnit, materials, true, // 是大单位
+                material4UnitPrice));
+        }
+    }
+
+    /**
+     * 分配基本单位库存
+     */
+    private void allocateBasicUnitStock(ErpXsddReqVO.OrderItem reqVOItem, DepotHeadXsddRequestVO order, List<DepotItemXsddRequestVO> itemList, List<MaterialVo4Unit> materials, UnitMatchResult matchResult) throws Exception {
+
+        // 获取基本参数
+        BigDecimal remainingQty = matchResult.getBaseQuantity(); // 剩余需求数量(基本单位)
+        String basicUnit = matchResult.getMatchedUnit(); // 基本单位名称
+        String erpSku = reqVOItem.getErpSku();
+        BigDecimal unitPrice = reqVOItem.getUnitPrice();
+
+        // 记录原始需求用于错误提示
+        BigDecimal originalQty = remainingQty;
+
+        // 遍历库存批次进行分配
+        for (MaterialVo4Unit m : materials) {
+            if (remainingQty.compareTo(BigDecimal.ZERO) <= 0) {
+                break; // 需求已满足
+            }
+
+            BigDecimal inventory = m.getInventory();
+            if (inventory.compareTo(BigDecimal.ZERO) <= 0) {
+                continue; // 跳过无库存批次
+            }
+
+            // 计算当前批次可分配数量
+            BigDecimal allocateQty = inventory.min(remainingQty);
+
+            // 创建订单明细项
+            DepotItemXsddRequestVO item = createOrderItem(order, m, basicUnit, allocateQty, allocateQty, unitPrice);
+            itemList.add(item);
+
+            // 更新库存
+            m.setInventory(inventory.subtract(allocateQty));
+
+            // 更新剩余需求
+            remainingQty = remainingQty.subtract(allocateQty);
+
+            logger.info("分配基本单位库存:批次[{}]  分配 {} {} (剩余需求: {})", m.getBatchNumber(), allocateQty.toPlainString(), basicUnit, remainingQty.toPlainString());
+        }
+
+        // 检查是否完全分配
+        if (remainingQty.compareTo(BigDecimal.ZERO) > 0) {
+            // 在allocateBasicUnitStock方法中调用
+            throw new RuntimeException(buildStockShortageMessage(erpSku, originalQty, remainingQty, basicUnit, materials, false, null));
+        }
+    }
+
+
+    /**
+     * 构建库存不足提示信息(通用方法,支持基本单位和大单位)
+     *
+     * @param erpSku 商品SKU
+     * @param totalQty 总需求数量
+     * @param remainingQty 剩余未分配数量
+     * @param orderUnit 订单单位
+     * @param materials 库存列表
+     * @param isLargeUnit 是否为大单位
+     * @param material4UnitPrice 单位价格信息(大单位时需要)
+     * @return 完整的库存不足提示信息
+     */
+    private String buildStockShortageMessage(String erpSku, BigDecimal totalQty, BigDecimal remainingQty, String orderUnit, List<MaterialVo4Unit> materials, boolean isLargeUnit, Material4UnitPrice material4UnitPrice) {
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("商品[").append(erpSku).append("]库存不足!\n");
+        sb.append("需求: ").append(totalQty.toPlainString()).append(" ").append(orderUnit).append("\n");
+        sb.append("未分配: ").append(remainingQty.toPlainString()).append(" ").append(orderUnit).append("\n");
+        sb.append("当前库存:\n");
+
+        // 获取基本单位名称
+        String basicUnit = isLargeUnit ? material4UnitPrice.getBasicUnit() : orderUnit;
+
+        materials.forEach(m -> {
+            // 计算当前批次的显示库存量
+            String stockDisplay;
+            if (isLargeUnit) {
+                BigDecimal unitRatio = getUnitRatio(orderUnit, material4UnitPrice);
+                BigDecimal stockInOrderUnit = m.getInventory().divideToIntegralValue(unitRatio);
+                stockDisplay = String.format("%s %s (%s %s)", stockInOrderUnit.toPlainString(), orderUnit, m.getInventory().toPlainString(), basicUnit);
             } else {
-                // 如果未找到对应的 MaterialVo4Unit,可以记录日志或处理异常
-                logger.warn("未找到 erp_sku: {} 对应的商品信息", erpSku);
+                stockDisplay = m.getInventory().toPlainString() + " " + basicUnit;
             }
+
+            sb.append(String.format("批次[%s] 生产日期[%s] - 库存: %s\n", m.getBatchNumber(), m.getProductionDate(), stockDisplay));
+        });
+
+        // 添加建议提示
+        if (isLargeUnit) {
+            sb.append("\n提示:").append(orderUnit).append("与").append(basicUnit).append("的换算比例为: 1").append(orderUnit).append("=").append(getUnitRatio(orderUnit, material4UnitPrice).toPlainString()).append(basicUnit);
         }
-        depotHeadService.syncOrderToXsdd(order, itemList);
+
+        return sb.toString();
+    }
+
+
+    /**
+     * 订单项参数校验
+     */
+    private void validateOrderItem(ErpXsddReqVO.OrderItem item) throws Exception {
+        if (item.getQuantity() == null || item.getQuantity() <= 0) {
+            throw new RuntimeException("商品数量必须大于0");
+        }
+        if (item.getUnitPrice() == null || item.getUnitPrice().compareTo(BigDecimal.ZERO) <= 0) {
+            throw new RuntimeException("商品单价必须大于0");
+        }
+        if (StringUtils.isBlank(item.getErpSku())) {
+            throw new RuntimeException("商品SKU不能为空");
+        }
+    }
+
+
+
+    
+
+    /**
+     * 创建订单明细项
+     */
+    private DepotItemXsddRequestVO createOrderItem(DepotHeadXsddRequestVO order, MaterialVo4Unit material, String unit, BigDecimal operNumber, BigDecimal basicNumber, BigDecimal unitPrice) {
+        DepotItemXsddRequestVO item = new DepotItemXsddRequestVO();
+        item.setHeaderId(order.getId());
+        item.setMaterialId(material.getId());
+        item.setMaterialExtendId(material.getMeId());
+        item.setMaterialUnit(unit);
+        item.setSku(material.getSku());
+        item.setDepotId(material.getDepotId());
+        item.setOperNumber(operNumber);
+        item.setBasicNumber(basicNumber);
+        item.setUnitPrice(unitPrice);
+        item.setTaxRate(BigDecimal.ONE);
+        item.setTaxMoney(BigDecimal.ZERO);
+        item.setBatchNumber("");
+        item.setTaxLastMoney(unitPrice.multiply(operNumber));
+        item.setAllPrice(unitPrice.multiply(operNumber));
+        return item;
+    }
+
+
+    private Material4UnitPrice getMaterial4UnitPrice(MaterialVo4Unit material) throws Exception {
+        Material4UnitPrice material4UnitPrice = new Material4UnitPrice();
+        Unit unitInfo = new Unit(); // 查询多单位信息
+        unitInfo.setBasicUnit(material.getCommodityUnit());
+        if(material.getUnitId() != null){
+            unitInfo = materialService.findUnit(material.getId());
+        }
+
+        BeanUtils.copyProperties(unitInfo, material4UnitPrice);
+
+        // 设置基础单位价格、基础数量
+        material4UnitPrice.setBasicUnitPrice(material.getWholesaleDecimal());
+        material4UnitPrice.setBasicUnitNumber(BigDecimal.ONE);
+
+        // 设置其他单位价格、其他数量
+        if (StringUtils.isNotEmpty(material4UnitPrice.getOtherUnit())) {
+            material4UnitPrice.setOtherUnitPrice(material.getWholesaleDecimal().multiply(material4UnitPrice.getRatio()));
+            material4UnitPrice.setOtherUnitNumber(material4UnitPrice.getRatio());
+        }
+
+        // 设置其他单位2价格、其他数量2
+        if (StringUtils.isNotEmpty(material4UnitPrice.getOtherUnitTwo())) {
+            material4UnitPrice.setOtherUnitTwoPrice(material.getWholesaleDecimal().multiply(material4UnitPrice.getRatioTwo()));
+            material4UnitPrice.setOtherUnitTwoNumber(material4UnitPrice.getRatioTwo());
+        }
+
+        // 设置其他单位3价格、其他数量3
+        if (StringUtils.isNotEmpty(material4UnitPrice.getOtherUnitThree())) {
+            material4UnitPrice.setOtherUnitThreePrice(material.getWholesaleDecimal().multiply(material4UnitPrice.getRatioThree()));
+            material4UnitPrice.setOtherUnitThreeNumber(material4UnitPrice.getRatioThree());
+        }
+        return material4UnitPrice;
+    }
+
+
+
+    /**
+     * 根据单价匹配单位并计算基本单位数量<br>
+     * 如果订单商品单价和商品最小单位单价相等,则使用最小单位, remainingQuantity = quantity<br>
+     * 如果订单商品单价和商品其他单位单价相等,则使用其他单位, remainingQuantity = quantity * material4UnitPrice.getRatio()<br>
+     * 如果订单商品单价和商品其他单位2单价相等,则使用其他单位2, remainingQuantity = quantity * material4UnitPrice.getRatioTwo()<br>
+     * 如果订单商品单价和商品其他单位3单价相等,则使用其他单位3, remainingQuantity = quantity * material4UnitPrice.getRatioThree()<br>
+     */
+    private UnitMatchResult matchUnitAndCalculateBaseQuantity(BigDecimal orderUnitPrice, BigDecimal orderQuantity, Material4UnitPrice material4UnitPrice) {
+        // 允许的价格误差范围
+        final BigDecimal PRICE_TOLERANCE = new BigDecimal("0.001");
+
+        // 1. 检查是否匹配基本单位价格
+        if (material4UnitPrice.getBasicUnitPrice() != null && orderUnitPrice.subtract(material4UnitPrice.getBasicUnitPrice()).abs().compareTo(PRICE_TOLERANCE) <= 0) {
+            return new UnitMatchResult(material4UnitPrice.getBasicUnit(), orderQuantity, orderQuantity, false);
+        }
+
+        // 2. 检查是否匹配副单位价格
+        if (material4UnitPrice.getOtherUnitPrice() != null && orderUnitPrice.subtract(material4UnitPrice.getOtherUnitPrice()).abs().compareTo(PRICE_TOLERANCE) <= 0) {
+            BigDecimal baseQuantity = orderQuantity.multiply(material4UnitPrice.getRatio());
+            return new UnitMatchResult(material4UnitPrice.getOtherUnit(), orderQuantity, baseQuantity, true);
+        }
+
+        // 3. 检查是否匹配副单位2价格
+        if (material4UnitPrice.getOtherUnitTwoPrice() != null && orderUnitPrice.subtract(material4UnitPrice.getOtherUnitTwoPrice()).abs().compareTo(PRICE_TOLERANCE) <= 0) {
+            BigDecimal baseQuantity = orderQuantity.multiply(material4UnitPrice.getRatioTwo());
+            return new UnitMatchResult(material4UnitPrice.getOtherUnitTwo(), orderQuantity, baseQuantity, true);
+        }
+
+        // 4. 检查是否匹配副单位3价格
+        if (material4UnitPrice.getOtherUnitThreePrice() != null && orderUnitPrice.subtract(material4UnitPrice.getOtherUnitThreePrice()).abs().compareTo(PRICE_TOLERANCE) <= 0) {
+            BigDecimal baseQuantity = orderQuantity.multiply(material4UnitPrice.getRatioThree());
+            return new UnitMatchResult(material4UnitPrice.getOtherUnitThree(), orderQuantity, baseQuantity, true);
+        }
+
+        // 5. 默认返回基本单位(如果无法匹配)
+        return new UnitMatchResult(material4UnitPrice.getBasicUnit(), orderQuantity, orderQuantity, false);
+    }
+
+
+
+    /**
+     * 将基本单位数量转换为订单单位数量
+     */
+    private BigDecimal convertToOrderUnitQuantity(BigDecimal baseQuantity, String orderUnit, Material4UnitPrice material4UnitPrice) {
+        if (orderUnit.equals(material4UnitPrice.getBasicUnit())) {
+            return baseQuantity;
+        } else if (orderUnit.equals(material4UnitPrice.getOtherUnit())) {
+            return baseQuantity.divide(material4UnitPrice.getRatio());
+        } else if (orderUnit.equals(material4UnitPrice.getOtherUnitTwo())) {
+            return baseQuantity.divide(material4UnitPrice.getRatioTwo());
+        } else if (orderUnit.equals(material4UnitPrice.getOtherUnitThree())) {
+            return baseQuantity.divide(material4UnitPrice.getRatioThree());
+        }
+        return baseQuantity;
     }
 
+    /**
+     * 获取单位的换算比例
+     */
+    private BigDecimal getUnitRatio(String unit, Material4UnitPrice material4UnitPrice) {
+        if (unit.equals(material4UnitPrice.getBasicUnit())) {
+            return BigDecimal.ONE;
+        } else if (unit.equals(material4UnitPrice.getOtherUnit())) {
+            return material4UnitPrice.getRatio();
+        } else if (unit.equals(material4UnitPrice.getOtherUnitTwo())) {
+            return material4UnitPrice.getRatioTwo();
+        } else if (unit.equals(material4UnitPrice.getOtherUnitThree())) {
+            return material4UnitPrice.getRatioThree();
+        }
+        return BigDecimal.ONE;
+    }
 
+    /**
+     * 单位匹配结果类
+     */
+    private static class UnitMatchResult {
+        private String matchedUnit;          // 匹配到的单位
+        private BigDecimal orderUnitQuantity; // 订单单位数量
+        private BigDecimal baseQuantity;     // 基本单位数量
+        private boolean isLargeUnit;         // 是否是大单位
+
+        public UnitMatchResult(String matchedUnit, BigDecimal orderUnitQuantity,
+                               BigDecimal baseQuantity, boolean isLargeUnit) {
+            this.matchedUnit = matchedUnit;
+            this.orderUnitQuantity = orderUnitQuantity;
+            this.baseQuantity = baseQuantity;
+            this.isLargeUnit = isLargeUnit;
+        }
+
+        // getter方法
+        public String getMatchedUnit() {
+            return matchedUnit;
+        }
+
+        public BigDecimal getBaseQuantity() {
+            return baseQuantity;
+        }
+
+        public boolean isLargeUnit() {
+            return isLargeUnit;
+        }
+
+        public BigDecimal getOrderUnitQuantity() {
+            return orderUnitQuantity;
+        }
+
+    }
 
 
 }

+ 8 - 0
src/main/java/com/jsh/erp/service/UserBusinessService.java

@@ -138,6 +138,14 @@ public class UserBusinessService {
         return ubValue;
     }
 
+    public String[] getUBValuByTypeAndKeyIdToArray(String type, String keyId) throws Exception {
+        String ubValue = getUBValueByTypeAndKeyId(type, keyId);
+        if (ubValue == null || ubValue.length() <= 2) { // "[x]"最小长度3
+            return new String[0];
+        }
+        return ubValue.substring(1, ubValue.length()-1).split("\\]\\[");
+    }
+
     public Long checkIsValueExist(String type, String keyId)throws Exception {
         UserBusinessExample example = new UserBusinessExample();
         example.createCriteria().andTypeEqualTo(type).andKeyIdEqualTo(keyId)

+ 10 - 1
src/main/java/com/jsh/erp/service/impl/DepotHeadServiceImpl.java

@@ -134,13 +134,17 @@ public class DepotHeadServiceImpl extends ServiceImpl<DepotHeadMapper, DepotHead
         try{
             HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
             Long userId = userService.getUserId(request);
-            String priceLimit = userService.getRoleTypeByUserId(userId).getPriceLimit();
+            Role role = userService.getRoleTypeByUserId(userId);
+            String priceLimit = role.getPriceLimit();
             String billCategory = getBillCategory(subType);
             String [] depotArray = getDepotArray(subType);
             String [] creatorArray = getCreatorArray();
             String [] statusArray = StringUtil.isNotEmpty(status) ? status.split(",") : null;
             String [] purchaseStatusArray = StringUtil.isNotEmpty(purchaseStatus) ? purchaseStatus.split(",") : null;
             String [] organArray = getOrganArray(subType, purchaseStatus);
+            if ("采购订单".equals(subType) && "供应商".equals(role.getName())) {
+                organArray = getOrganArrayByCurrentUser(userId);
+            }
             //以销定购,查看全部数据
             creatorArray = StringUtil.isNotEmpty(purchaseStatus) ? null: creatorArray;
             Map<Long,String> personMap = personService.getPersonMap();
@@ -329,6 +333,11 @@ public class DepotHeadServiceImpl extends ServiceImpl<DepotHeadMapper, DepotHead
         return organArray;
     }
 
+    public String [] getOrganArrayByCurrentUser(Long userId) throws Exception {
+        String[] organArray = userBusinessService.getUBValuByTypeAndKeyIdToArray("UserSupplier", userId.toString());
+        return organArray;
+    }
+
     /**
      * 根据角色类型获取操作员
      * @return

+ 46 - 15
src/main/java/com/jsh/erp/service/impl/DepotItemServiceImpl.java

@@ -269,6 +269,19 @@ public class DepotItemServiceImpl extends ServiceImpl<DepotItemMapper, DepotItem
         return result;
     }
 
+    public int insertDepotItem(DepotItem depotItem)throws Exception {
+        int result =0;
+        try{
+            depotItemMapper.insertSelective(depotItem);
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+        return result;
+    }
+
+
+
+
     @Override
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
     public int updateDepotItemWithObj(DepotItem depotItem)throws Exception {
@@ -751,6 +764,15 @@ public class DepotItemServiceImpl extends ServiceImpl<DepotItemMapper, DepotItem
                         }
                     }
                 }
+                if(BusinessConstants.DEPOTHEAD_TYPE_IN.equals(depotHead.getType())){
+                    //表单入库,修改商品库存
+                    materialExtend.setInventory(materialExtend.getInventory().add(depotItem.getBasicNumber()));
+                    materialExtendService.updateInventory("单据",depotItem.getId(),materialExtend);
+                }else if(BusinessConstants.DEPOTHEAD_TYPE_OUT.equals(depotHead.getType())){
+                    //表单入库,修改商品库存
+                    materialExtend.setInventory(materialExtend.getInventory().subtract(depotItem.getBasicNumber()));
+                    materialExtendService.updateInventory("单据",depotItem.getId(),materialExtend);
+                }
                 this.insertDepotItemWithObj(depotItem);
                 //更新当前库存
                 updateCurrentStock(depotItem);
@@ -801,7 +823,6 @@ public class DepotItemServiceImpl extends ServiceImpl<DepotItemMapper, DepotItem
             for (DepotItemXsddRequestVO item : itemList) {
                 DepotItem depotItem = new DepotItem();
                 BeanUtils.copyProperties(item, depotItem);
-
                 // 以下进行单位换算
                 Unit unitInfo = materialService.findUnit(depotItem.getMaterialId()); // 查询多单位信息
                 if (depotItem.getOperNumber() != null) {
@@ -826,6 +847,8 @@ public class DepotItemServiceImpl extends ServiceImpl<DepotItemMapper, DepotItem
                     }
                 }
                 this.insertDepotItemWithObj(depotItem);
+                depotItem.setHeaderId(depotHead.getId());
+                this.insertDepotItem(depotItem);
                 // 更新当前库存
                 updateCurrentStock(depotItem);
             }
@@ -1150,7 +1173,7 @@ public class DepotItemServiceImpl extends ServiceImpl<DepotItemMapper, DepotItem
             stockSum = inTotal.add(transfInTotal).add(assemInTotal).add(disAssemInTotal)
                     .subtract(outTotal).subtract(transfOutTotal).subtract(assemOutTotal).subtract(disAssemOutTotal);
         }
-        return initStock.add(stockCheckSum).add(inventory).add(stockSum);
+        return initStock.add(stockCheckSum).add(inventory);
     }
 
     /**
@@ -1283,26 +1306,28 @@ public class DepotItemServiceImpl extends ServiceImpl<DepotItemMapper, DepotItem
     @Override
     public void updateCurrentStockFun(Long mId, Long dId) throws Exception {
         if(mId!=null && dId!=null) {
-            MaterialCurrentStockExample example = new MaterialCurrentStockExample();
+//            MaterialCurrentStockExample example = new MaterialCurrentStockExample();
             //条件 添加商品id,仓库id ,删除状态
-            example.createCriteria().andMaterialIdEqualTo(mId).andDepotIdEqualTo(dId)
-                    .andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_EXISTS);
+//            example.createCriteria().andMaterialIdEqualTo(mId).andDepotIdEqualTo(dId)
+//                    .andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED);
             //获取商品当前库存信息
-            List<MaterialCurrentStock> list = materialCurrentStockMapper.selectByExample(example);
+//            List<MaterialCurrentStock> list = materialCurrentStockMapper.selectByExample(example);
+            //-先清除再插入,防止商品仓库变更,数据对不上
+            materialCurrentStockMapper.delete(new LambdaQueryWrapperX<MaterialCurrentStock>().eq(MaterialCurrentStock::getMaterialId,mId).eqIfPresent(MaterialCurrentStock::getDepotId,dId));
             MaterialCurrentStock materialCurrentStock = new MaterialCurrentStock();
             materialCurrentStock.setMaterialId(mId);
             materialCurrentStock.setDepotId(dId);
             //设置当前库存数量
             materialCurrentStock.setCurrentNumber(getStockByParam(dId,mId,null,null));
-            if(list!=null && list.size()>0) {
-                //当前库存信息存在,修改当前库存信息
-                Long mcsId = list.get(0).getId();
-                materialCurrentStock.setId(mcsId);
-                materialCurrentStockMapper.updateByPrimaryKeySelective(materialCurrentStock);
-            } else {
+//            if(list!=null && list.size()>0) {
+//                //当前库存信息存在,修改当前库存信息
+//                Long mcsId = list.get(0).getId();
+//                materialCurrentStock.setId(mcsId);
+//                materialCurrentStockMapper.updateByPrimaryKeySelective(materialCurrentStock);
+//            } else {
                 //当前库存信息不存在,新增当前库存信息
                 materialCurrentStockMapper.insertSelective(materialCurrentStock);
-            }
+//            }
         }
     }
 
@@ -1459,7 +1484,8 @@ public class DepotItemServiceImpl extends ServiceImpl<DepotItemMapper, DepotItem
         //根据批次号获取商品数据
         List<MaterialVo4Unit> list = new ArrayList<>();
         if ("XSDD".equals(prefixNo)){ //销售订单导入
-            List<String> strings = Arrays.asList(batchNumbers.replace("^\"|\"$","").split(","));
+            String systemSku = batchNumbers.replace("'","");
+            List<String> strings = Arrays.asList(systemSku.split(","));
             //根据系统sku查询商品
             for (String str : strings) {
                 MaterialVo4Unit materialVo4Unit = depotItemMapperEx.getDepotMaterialBySystemSku(str);
@@ -1473,7 +1499,11 @@ public class DepotItemServiceImpl extends ServiceImpl<DepotItemMapper, DepotItem
         //仓库集合
         Map<String, Long> depotMap = new HashMap<>();
         for (MaterialVo4Unit material: list) {
-            materialMap.put(material.getBatchNumber(), material);
+            if ("XSDD".equals(prefixNo)){
+                materialMap.put(material.getSystemSku(), material);
+            }else {
+                materialMap.put(material.getBatchNumber(), material);
+            }
         }
         //获取当前用户所有仓库
         JSONArray depotArr = depotService.findDepotByCurrentUser();
@@ -1613,4 +1643,5 @@ public class DepotItemServiceImpl extends ServiceImpl<DepotItemMapper, DepotItem
         }
         return materialOther;
     }
+
 }

+ 12 - 0
src/main/java/com/jsh/erp/service/impl/InventoryLogServiceImpl.java

@@ -0,0 +1,12 @@
+package com.jsh.erp.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jsh.erp.datasource.entities.InventoryLog;
+import com.jsh.erp.datasource.mappers.InventoryLogMapper;
+import com.jsh.erp.service.InventoryLogService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class InventoryLogServiceImpl extends ServiceImpl<InventoryLogMapper, InventoryLog> implements InventoryLogService {
+
+}

+ 316 - 0
src/main/java/com/jsh/erp/service/impl/MaterialCategoryServiceImpl.java

@@ -0,0 +1,316 @@
+package com.jsh.erp.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jsh.erp.constants.BusinessConstants;
+import com.jsh.erp.constants.ExceptionConstants;
+import com.jsh.erp.datasource.entities.*;
+import com.jsh.erp.datasource.mappers.MaterialCategoryMapper;
+import com.jsh.erp.datasource.mappers.MaterialCategoryMapperEx;
+import com.jsh.erp.datasource.mappers.MaterialMapperEx;
+import com.jsh.erp.datasource.vo.TreeNode;
+import com.jsh.erp.exception.BusinessRunTimeException;
+import com.jsh.erp.exception.JshException;
+import com.jsh.erp.service.LogService;
+import com.jsh.erp.service.MaterialCategoryService;
+import com.jsh.erp.service.UserService;
+import com.jsh.erp.utils.PageUtils;
+import com.jsh.erp.utils.StringUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@Service
+public class MaterialCategoryServiceImpl extends ServiceImpl<MaterialCategoryMapper, MaterialCategory> implements MaterialCategoryService {
+    private Logger logger = LoggerFactory.getLogger(MaterialCategoryServiceImpl.class);
+
+    @Resource
+    private MaterialCategoryMapper materialCategoryMapper;
+    @Resource
+    private MaterialCategoryMapperEx materialCategoryMapperEx;
+    @Resource
+    private UserService userService;
+    @Resource
+    private LogService logService;
+    @Resource
+    private MaterialMapperEx materialMapperEx;
+
+    @Override
+    public MaterialCategory getMaterialCategory(long id)throws Exception {
+        MaterialCategory result=null;
+        try{
+            result=materialCategoryMapper.selectByPrimaryKey(id);
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+        return result;
+    }
+
+    @Override
+    public List<MaterialCategory> getMaterialCategoryListByIds(String ids)throws Exception {
+        List<Long> idList = StringUtil.strToLongList(ids);
+        List<MaterialCategory> list = new ArrayList<>();
+        try{
+            MaterialCategoryExample example = new MaterialCategoryExample();
+            example.createCriteria().andIdIn(idList);
+            list = materialCategoryMapper.selectByExample(example);
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+        return list;
+    }
+
+    @Override
+    public List<MaterialCategory> getMaterialCategory()throws Exception {
+        MaterialCategoryExample example = new MaterialCategoryExample();
+        List<MaterialCategory> list=null;
+        try{
+            list=materialCategoryMapper.selectByExample(example);
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+        return list;
+    }
+
+    @Override
+    public List<MaterialCategory> getAllList(Long parentId)throws Exception {
+        List<MaterialCategory> list=null;
+        try{
+            list = getMCList(parentId);
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+        return list;
+    }
+
+    @Override
+    public List<MaterialCategory> getMCList(Long parentId)throws Exception {
+        List<MaterialCategory> res= new ArrayList<MaterialCategory>();
+        List<MaterialCategory> list=null;
+        MaterialCategoryExample example = new MaterialCategoryExample();
+        example.createCriteria().andParentIdEqualTo(parentId).andIdNotEqualTo(1L);
+        example.setOrderByClause("id");
+        list=materialCategoryMapper.selectByExample(example);
+        if(list!=null && list.size()>0) {
+            res.addAll(list);
+            for(MaterialCategory mc : list) {
+                List<MaterialCategory> mcList = getMCList(mc.getId());
+                if(mcList!=null && mcList.size()>0) {
+                    res.addAll(mcList);
+                }
+            }
+        }
+        return res;
+    }
+
+    @Override
+    public List<MaterialCategory> select(String name, Integer parentId) throws Exception{
+        List<MaterialCategory> list=null;
+        try{
+            PageUtils.startPage();
+            list=materialCategoryMapperEx.selectByConditionMaterialCategory(name, parentId);
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+        return list;
+    }
+
+    @Override
+    @Transactional(value = "transactionManager", rollbackFor = Exception.class)
+    public int insertMaterialCategory(JSONObject obj, HttpServletRequest request)throws Exception {
+        MaterialCategory materialCategory = JSONObject.parseObject(obj.toJSONString(), MaterialCategory.class);
+        materialCategory.setCreateTime(new Date());
+        materialCategory.setUpdateTime(new Date());
+        User user = userService.getCurrentUser();
+        materialCategory.setTenantId(user.getId());
+        int result = 0;
+        try{
+            result = materialCategoryMapper.insertSelective(materialCategory);
+            logService.insertLog("商品类型",
+                    new StringBuffer(BusinessConstants.LOG_OPERATION_TYPE_ADD).append(materialCategory.getName()).toString(), request);
+        }catch(Exception e){
+            JshException.writeFail(logger, e);
+        }
+        return result;
+    }
+
+    @Override
+    @Transactional(value = "transactionManager", rollbackFor = Exception.class)
+    public int updateMaterialCategory(JSONObject obj, HttpServletRequest request) throws Exception{
+        MaterialCategory materialCategory = JSONObject.parseObject(obj.toJSONString(), MaterialCategory.class);
+        materialCategory.setUpdateTime(new Date());
+        int result=0;
+        try{
+            result=materialCategoryMapperEx.editMaterialCategory(materialCategory);
+            logService.insertLog("商品类型",
+                    new StringBuffer(BusinessConstants.LOG_OPERATION_TYPE_EDIT).append(materialCategory.getName()).toString(), request);
+        }catch(Exception e){
+            JshException.writeFail(logger, e);
+        }
+        return result;
+    }
+
+    @Override
+    @Transactional(value = "transactionManager", rollbackFor = Exception.class)
+    public int deleteMaterialCategory(Long id, HttpServletRequest request)throws Exception {
+        return batchDeleteMaterialCategoryByIds(id.toString());
+    }
+
+    @Override
+    @Transactional(value = "transactionManager", rollbackFor = Exception.class)
+    public int batchDeleteMaterialCategory(String ids, HttpServletRequest request)throws Exception {
+        return batchDeleteMaterialCategoryByIds(ids);
+    }
+
+    @Override
+    @Transactional(value = "transactionManager", rollbackFor = Exception.class)
+    public int batchDeleteMaterialCategoryByIds(String ids) throws Exception {
+        int result=0;
+        String [] idArray=ids.split(",");
+        //校验产品表	jsh_material
+        List<Material> materialList=null;
+        try{
+            materialList= materialMapperEx.getMaterialListByCategoryIds(idArray);
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+        if(materialList!=null&&materialList.size()>0){
+            logger.error("异常码[{}],异常提示[{}],参数,CategoryIds[{}]",
+                    ExceptionConstants.DELETE_FORCE_CONFIRM_CODE,ExceptionConstants.DELETE_FORCE_CONFIRM_MSG,ids);
+            throw new BusinessRunTimeException(ExceptionConstants.DELETE_FORCE_CONFIRM_CODE,
+                    ExceptionConstants.DELETE_FORCE_CONFIRM_MSG);
+        }
+        StringBuffer sb = new StringBuffer();
+        sb.append(BusinessConstants.LOG_OPERATION_TYPE_DELETE);
+        List<MaterialCategory> list = getMaterialCategoryListByIds(ids);
+        for(MaterialCategory materialCategory: list){
+            sb.append("[").append(materialCategory.getName()).append("]");
+        }
+        logService.insertLog("商品类型", sb.toString(),
+                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
+        //更新时间
+        Date updateDate = new Date();
+        //更新人
+        User userInfo = userService.getCurrentUser();
+        Long updater = userInfo==null ? null : userInfo.getId();
+        String strArray[]=ids.split(",");
+        if(strArray.length<1){
+            return 0;
+        }
+        List<MaterialCategory> mcList = materialCategoryMapperEx.getMaterialCategoryListByCategoryIds(idArray);
+        if(mcList!=null && mcList.size()>0) {
+            logger.error("异常码[{}],异常提示[{}]",
+                    ExceptionConstants.MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_CODE,ExceptionConstants.MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_MSG);
+            throw new BusinessRunTimeException(ExceptionConstants.MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_CODE,
+                    ExceptionConstants.MATERIAL_CATEGORY_CHILD_NOT_SUPPORT_DELETE_MSG);
+        } else {
+            result=materialCategoryMapperEx.batchDeleteMaterialCategoryByIds(updateDate,updater,strArray);
+        }
+        return result;
+    }
+
+    @Override
+    public int checkIsNameExist(Long id, String name)throws Exception {
+        MaterialCategoryExample example = new MaterialCategoryExample();
+        example.createCriteria().andIdNotEqualTo(id).andNameEqualTo(name).andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED);
+        List<MaterialCategory> list=null;
+        try{
+            list= materialCategoryMapper.selectByExample(example);
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+        return list==null?0:list.size();
+    }
+
+    @Override
+    public List<MaterialCategory> findById(Long id)throws Exception {
+        List<MaterialCategory> list=null;
+        if(id!=null) {
+            MaterialCategoryExample example = new MaterialCategoryExample();
+            example.createCriteria().andIdEqualTo(id);
+            try{
+                list=materialCategoryMapper.selectByExample(example);
+            }catch(Exception e){
+                JshException.readFail(logger, e);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * description:
+     * 获取商品类别树数据
+     */
+    @Override
+    public List<TreeNode> getMaterialCategoryTree(Long id) throws Exception{
+        List<TreeNode> list=null;
+        try{
+            list=materialCategoryMapperEx.getNodeTree(id);
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+       return list;
+    }
+    /**
+     * 根据商品类别编号判断商品类别是否已存在
+     * */
+    @Override
+    public void  checkMaterialCategorySerialNo(MaterialCategory mc)throws Exception {
+        if(mc==null){
+            return;
+        }
+        if( mc.getSerialNo() < 0){
+            return;
+        }
+        //根据商品类别编号查询商品类别
+        List<MaterialCategory> mList=null;
+        try{
+            mList= materialCategoryMapperEx.getMaterialCategoryBySerialNo(mc.getSerialNo(), mc.getId());
+        }catch(Exception e){
+            JshException.readFail(logger, e);
+        }
+        if(mList==null||mList.size()<1){
+            //未查询到对应数据,编号可用
+            return;
+        }
+        if(mList.size()>1){
+            //查询到的数据条数大于1,编号已存在
+            throw new BusinessRunTimeException(ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_CODE,
+                    ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_MSG);
+        }
+        if(mc.getId()==null){
+            //新增时,编号已存在
+            throw new BusinessRunTimeException(ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_CODE,
+                    ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_MSG);
+        }
+        /**
+         * 包装类型用equals来比较
+         * */
+        if(mc.getId().equals(mList.get(0).getId())){
+            //修改时,相同编号,id不同
+            throw new BusinessRunTimeException(ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_CODE,
+                    ExceptionConstants.MATERIAL_CATEGORY_SERIAL_ALREADY_EXISTS_MSG);
+        }
+    }
+
+    @Override
+    public Long getCategoryIdByName(String name){
+        Long categoryId = null;
+        MaterialCategoryExample example = new MaterialCategoryExample();
+        example.createCriteria().andNameEqualTo(name).andDeleteFlagNotEqualTo(BusinessConstants.DELETE_FLAG_DELETED);
+        List<MaterialCategory> list = materialCategoryMapper.selectByExample(example);
+        if(list!=null && list.size()>0) {
+            categoryId = list.get(0).getId();
+        }
+        return categoryId;
+    }
+}

+ 29 - 13
src/main/java/com/jsh/erp/service/impl/MaterialExtendServiceImpl.java

@@ -1,22 +1,17 @@
 package com.jsh.erp.service.impl;
-
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.jsh.erp.constants.BusinessConstants;
-import com.jsh.erp.constants.ExceptionConstants;
 import com.jsh.erp.datasource.entities.*;
 import com.jsh.erp.datasource.mappers.MaterialCurrentStockMapper;
 import com.jsh.erp.datasource.mappers.MaterialExtendMapper;
 import com.jsh.erp.datasource.mappers.MaterialExtendMapperEx;
 import com.jsh.erp.datasource.vo.MaterialExtendVo4List;
-import com.jsh.erp.exception.BusinessRunTimeException;
 import com.jsh.erp.exception.JshException;
-import com.jsh.erp.service.MaterialExtendService;
-import com.jsh.erp.service.MaterialService;
-import com.jsh.erp.service.RedisService;
-import com.jsh.erp.service.UserService;
+import com.jsh.erp.service.*;
 import com.jsh.erp.utils.DateUtils;
 import com.jsh.erp.utils.RandomHelper;
 import com.jsh.erp.utils.StringUtil;
@@ -49,9 +44,12 @@ public class MaterialExtendServiceImpl extends ServiceImpl<MaterialExtendMapper,
     private UserService userService;
     @Resource
     private RedisService redisService;
-
     @Resource
     private MaterialService materialService;
+    @Resource
+    private DepotItemService depotItemService;
+    @Resource
+    private InventoryLogService inventoryLogService;
 
     @Override
     public MaterialExtend getMaterialExtend(long id)throws Exception {
@@ -283,7 +281,8 @@ public class MaterialExtendServiceImpl extends ServiceImpl<MaterialExtendMapper,
         int result = 0;
         try{
             result= materialExtendMapper.insertSelective(materialExtend);
-
+            //更新当前库存
+            depotItemService.updateCurrentStockFun(materialExtend.getMaterialId(), materialExtend.getDepotId());
         }catch(Exception e){
             JshException.writeFail(logger, e);
         }
@@ -306,6 +305,8 @@ public class MaterialExtendServiceImpl extends ServiceImpl<MaterialExtendMapper,
         materialExtend.setUpdateSerial(user.getLoginName());
         int res =0;
         try{
+            //修改库存
+            updateInventory("商品修改",null,materialExtend);
             res= materialExtendMapper.updateByPrimaryKeySelective(materialExtend);
         }catch(Exception e){
             JshException.writeFail(logger, e);
@@ -491,11 +492,26 @@ public class MaterialExtendServiceImpl extends ServiceImpl<MaterialExtendMapper,
     }
 
     /**
-     * 设置当前库存
-     * @param depotId 仓库id
-     * @param mId   商品id
-     * @param stock 库存数量
+     * 修改子商品库存
      */
+    @Override
+    public synchronized void updateInventory(String type, Long id, MaterialExtend materialExtend) throws Exception {
+        if (materialExtend.getInventory() != null){
+            User user = userService.getCurrentUser();
+            InventoryLog log = new InventoryLog();
+            log.setUpdateUser(user.getId());
+            log.setUpdateTime(new Date());
+            log.setMaterialId(materialExtend.getMaterialId());
+            log.setMaterialExtendId(materialExtend.getId());
+            log.setOriginalStock(materialExtendMapper.selectByPrimaryKey(materialExtend.getId()).getInventory().intValue());
+            Integer i = materialExtend.getInventory().intValue();
+            log.setCurrentStock(i);
+            log.setItemId(id);
+            log.setType(type);
+            inventoryLogService.save(log);
+            update(new UpdateWrapper<MaterialExtend>().set("inventory",materialExtend.getInventory()).set("position",materialExtend.getPosition()).eq("id",materialExtend.getId()));;
+        }
+    }
     /**
      * 设置当前库存
      * @param depotId 仓库id

+ 49 - 2
src/main/java/com/jsh/erp/service/impl/MaterialServiceImpl.java

@@ -9,11 +9,16 @@ import com.jsh.erp.constants.BusinessConstants;
 import com.jsh.erp.constants.ExceptionConstants;
 import com.jsh.erp.datasource.entities.*;
 import com.jsh.erp.datasource.mappers.*;
+import com.jsh.erp.datasource.pda.dto.PDAInventoryDTO;
+import com.jsh.erp.datasource.pda.vo.PDADepotItemVO;
+import com.jsh.erp.datasource.pda.vo.PDATypeTree;
 import com.jsh.erp.datasource.vo.MaterialVoSearch;
 import com.jsh.erp.datasource.vo.MaterialWarnListVo;
+import com.jsh.erp.datasource.vo.TreeNode;
 import com.jsh.erp.exception.BusinessRunTimeException;
 import com.jsh.erp.exception.JshException;
 import com.jsh.erp.query.LambdaQueryWrapperX;
+import com.jsh.erp.query.QueryWrapperX;
 import com.jsh.erp.service.*;
 import com.jsh.erp.utils.*;
 import jxl.Sheet;
@@ -209,11 +214,14 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialMapper, Material> i
                             //设置初始库
                             insertInitialStockByMaterialAndDepot(depotId, mId, parseBigDecimalEx(number), lowSafeStock, highSafeStock);
                             //设置当前库
-                            insertCurrentStockByMaterialAndDepot(depotId, mId, parseBigDecimalEx(number));
+                            //insertCurrentStockByMaterialAndDepot(depotId, mId, parseBigDecimalEx(number));
+                            //更新当前库存
+                            depotItemService.updateCurrentStockFun(mId, depotId);
                         }
                     }
                 }
             }
+
             logService.insertLog("商品",
                     new StringBuffer(BusinessConstants.LOG_OPERATION_TYPE_ADD).append(m.getName()).toString(), request);
             return 1;
@@ -236,7 +244,6 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialMapper, Material> i
     @Transactional(value = "transactionManager", rollbackFor = Exception.class)
     public int updateMaterial(JSONObject obj, HttpServletRequest request) throws Exception{
         Material material = JSONObject.parseObject(obj.toJSONString(), Material.class);
-
         try{
             //修改商品属性
             materialMapper.updateByPrimaryKeySelective(material);
@@ -1987,6 +1994,46 @@ public class MaterialServiceImpl extends ServiceImpl<MaterialMapper, Material> i
         return info;
     }
 
+    @Override
+    public List<PDADepotItemVO> inventoryInquiry(PDAInventoryDTO pdaInventoryDTO) {
+        return materialMapperEx.inventoryInquiry(pdaInventoryDTO);
+    }
+
+    /**
+     * 查询库位树
+     */
+    @Override
+    public List<PDATypeTree> selectPosition() {
+        List<String> positions = materialExtendMapper.selectPosition();
+        Map<String,List<String>> map = new HashMap<>();
+        for (String s : positions) {
+            String [] str = s.split("-");
+            if (map.get(str[0]) == null){
+                List<String> list = new ArrayList<>();
+                list.add(str[1]);
+                map.put(str[0],list);
+            }else {
+                map.get(str[0]).add(str[1]);
+            }
+        }
+        List<PDATypeTree> typeTrees = new ArrayList<>();
+        map.forEach((key,value) -> {
+            PDATypeTree typeTree = new PDATypeTree();
+            typeTree.setLabel(key);
+            typeTree.setValue(key);
+            List<PDATypeTree> children = new ArrayList<>();
+            for (String s : value) {
+                PDATypeTree childrenTree = new PDATypeTree();
+                childrenTree.setLabel(key + "-" + s);
+                childrenTree.setValue(key + "-" + s);
+                children.add(childrenTree);
+            }
+            typeTree.setChildren(children);
+            typeTrees.add(typeTree);
+        });
+        return typeTrees;
+    }
+
     /**
      * 解析excel表格数据为商品对象
      */

+ 23 - 0
src/main/java/com/jsh/erp/service/impl/SupplierServiceImpl.java

@@ -9,6 +9,7 @@ import com.jsh.erp.datasource.mappers.*;
 import com.jsh.erp.datasource.vo.DepotHeadVo4StatementAccount;
 import com.jsh.erp.exception.BusinessRunTimeException;
 import com.jsh.erp.exception.JshException;
+import com.jsh.erp.query.LambdaQueryWrapperX;
 import com.jsh.erp.service.*;
 import com.jsh.erp.utils.*;
 import jxl.Sheet;
@@ -17,6 +18,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 import org.springframework.web.multipart.MultipartFile;
@@ -748,4 +750,25 @@ public class SupplierServiceImpl extends ServiceImpl<SupplierMapper, Supplier> i
         }
         return res;
     }
+
+    @Override
+    public Supplier getSupplierByPhone(String type, String telephone) {
+        List<Supplier> supplierList = supplierMapper.selectList(new LambdaQueryWrapperX<Supplier>().eq(Supplier::getType, type).eq(Supplier::getTelephone, telephone));
+        if(CollectionUtils.isEmpty(supplierList)){
+            return null;
+        }
+        return supplierList.get(0);
+    }
+
+    @Override
+    public Supplier getCustomerByPhone(String telephone) {
+        return getSupplierByPhone("客户", telephone);
+    }
+
+    @Override
+    public Supplier createCustomer(Supplier supplier) {
+        supplier.setType("客户");
+        supplierMapper.insertSelective(supplier);
+        return supplier;
+    }
 }

+ 37 - 1
src/main/resources/mapper_xml/DepotHeadMapper.xml

@@ -157,7 +157,7 @@
       #{source,jdbcType=VARCHAR}, #{linkNumber,jdbcType=VARCHAR}, #{linkApply,jdbcType=VARCHAR}, 
       #{tenantId,jdbcType=BIGINT}, #{deleteFlag,jdbcType=VARCHAR})
   </insert>
-  <insert id="insertSelective" parameterType="com.jsh.erp.datasource.entities.DepotHead">
+  <insert id="insertSelective" parameterType="com.jsh.erp.datasource.entities.DepotHead" useGeneratedKeys="true" keyProperty="id">
     insert into jsh_depot_head
     <trim prefix="(" suffix=")" suffixOverrides=",">
       <if test="id != null">
@@ -265,6 +265,18 @@
       <if test="goodsTypeCount != null">
         goods_type_count,
       </if>
+      <if test="linkTesco != null">
+        link_tesco,
+      </if>
+      <if test="receiverName != null">
+        receiver_name,
+      </if>
+      <if test="receiverPhone != null">
+        receiver_phone,
+      </if>
+      <if test="receiverAddress != null">
+        receiver_address
+      </if>
     </trim>
     <trim prefix="values (" suffix=")" suffixOverrides=",">
       <if test="id != null">
@@ -372,6 +384,18 @@
       <if test="goodsTypeCount != null">
         #{goodsTypeCount,jdbcType=INTEGER},
       </if>
+      <if test="linkTesco != null">
+        #{linkTesco,jdbcType=VARCHAR},
+      </if>
+      <if test="receiverName != null">
+        #{receiverName,jdbcType=VARCHAR},
+      </if>
+      <if test="receiverPhone != null">
+        #{receiverPhone,jdbcType=VARCHAR},
+      </if>
+      <if test="receiverAddress != null">
+        #{receiverAddress,jdbcType=VARCHAR}
+      </if>
     </trim>
   </insert>
   <select id="countByExample" parameterType="com.jsh.erp.datasource.entities.DepotHeadExample" resultType="java.lang.Long">
@@ -627,6 +651,18 @@
       <if test="goodsTypeCount != null">
         goods_type_count = #{goodsTypeCount,jdbcType=INTEGER},
       </if>
+      <if test="linkTesco != null">
+        link_tesco =#{linkTesco,jdbcType=VARCHAR},
+      </if>
+      <if test="receiverName != null">
+        receiver_name = #{receiverName,jdbcType=VARCHAR}
+      </if>
+      <if test="receiverPhone != null">
+        receiver_phone = #{receiverPhone,jdbcType=VARCHAR}
+      </if>
+      <if test="receiverAddress != null">
+        receiver_address = #{receiverAddress,jdbcType=VARCHAR}
+      </if>
     </set>
     where id = #{id,jdbcType=BIGINT}
   </update>

+ 11 - 5
src/main/resources/mapper_xml/DepotItemMapper.xml

@@ -150,7 +150,7 @@
       #{deleteFlag,jdbcType=VARCHAR})
   </insert>
 
-  <insert id="insertSelective" parameterType="com.jsh.erp.datasource.entities.DepotItem">
+  <insert id="insertSelective" parameterType="com.jsh.erp.datasource.entities.DepotItem" useGeneratedKeys="true" keyProperty="id">
     insert into jsh_depot_item
     <trim prefix="(" suffix=")" suffixOverrides=",">
       <if test="id != null">
@@ -337,7 +337,7 @@
       </if>
     </trim>
   </insert>
-  <select id="countByExample" parameterType="com.jsh.erp.datasource.entities.DepotItemExample" resultType="java.lang.Long">
+    <select id="countByExample" parameterType="com.jsh.erp.datasource.entities.DepotItemExample" resultType="java.lang.Long">
     select count(*) from jsh_depot_item
     <if test="_parameter != null">
       <include refid="Example_Where_Clause" />
@@ -576,7 +576,10 @@
 	  me.bar_code AS bar_code,
 	  di.oper_number AS oper_number,
       me.commodity_unit AS commodity_unit,
-      di.material_unit AS material_unit
+      di.material_unit AS material_unit,
+      di.actual_quantity_in_storage AS actual_quantity_in_storage,
+      di.material_id AS material_id,
+      m.img_name AS img_name
     FROM
       jsh_depot_item di
     LEFT JOIN jsh_material m ON di.material_id = m.id
@@ -598,7 +601,9 @@
 	  me.bar_code AS bar_code,
 	  di.oper_number AS oper_number,
       di.material_unit AS material_unit,
-      me.create_time AS create_time
+      me.create_time AS create_time,
+      di.material_id AS material_id,
+      m.img_name AS img_name
     FROM
       jsh_depot_item di
       LEFT JOIN jsh_material m ON di.material_id = m.id
@@ -617,7 +622,8 @@
       m.standard AS material_standard,
       di.actual_quantity_in_storage AS actual_quantity_in_storage,
       di.warehousing_time AS warehousing_time,
-      me.commodity_unit AS commodity_unit
+      me.commodity_unit AS commodity_unit,
+      m.img_name AS img_name
     FROM
       jsh_depot_item di
       LEFT JOIN jsh_depot_head dh ON di.header_id = dh.id

+ 5 - 0
src/main/resources/mapper_xml/InventoryLogMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jsh.erp.datasource.mappers.InventoryLogMapper">
+
+</mapper>

+ 5 - 6
src/main/resources/mapper_xml/MaterialCategoryMapper.xml

@@ -116,9 +116,11 @@
       #{remark,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}, 
       #{tenantId,jdbcType=BIGINT}, #{deleteFlag,jdbcType=VARCHAR})
   </insert>
+
   <insert id="insertSelective" parameterType="com.jsh.erp.datasource.entities.MaterialCategory">
     insert into jsh_material_category
     <trim prefix="(" suffix=")" suffixOverrides=",">
+      serial_no,
       <if test="id != null">
         id,
       </if>
@@ -134,9 +136,6 @@
       <if test="sort != null">
         sort,
       </if>
-      <if test="serialNo != null">
-        serial_no,
-      </if>
       <if test="remark != null">
         remark,
       </if>
@@ -154,6 +153,7 @@
       </if>
     </trim>
     <trim prefix="values (" suffix=")" suffixOverrides=",">
+      (select ifnull(MAX(id),0) + 10001 from jsh_material_category AS mc),
       <if test="id != null">
         #{id,jdbcType=BIGINT},
       </if>
@@ -169,9 +169,7 @@
       <if test="sort != null">
         #{sort,jdbcType=VARCHAR},
       </if>
-      <if test="serialNo != null">
-        #{serialNo,jdbcType=VARCHAR},
-      </if>
+
       <if test="remark != null">
         #{remark,jdbcType=VARCHAR},
       </if>
@@ -189,6 +187,7 @@
       </if>
     </trim>
   </insert>
+
   <select id="countByExample" parameterType="com.jsh.erp.datasource.entities.MaterialCategoryExample" resultType="java.lang.Long">
     select count(*) from jsh_material_category
     <if test="_parameter != null">

+ 3 - 1
src/main/resources/mapper_xml/MaterialCategoryMapperEx.xml

@@ -102,13 +102,15 @@
         </foreach>
        )
     </update>
+
     <update id="editMaterialCategory">
        update jsh_material_category
        set update_time=#{updateTime},
-        parent_id=#{parentId},sort=#{sort},serial_no=#{serialNo},
+        parent_id=#{parentId},sort=#{sort},
         name=#{name},remark=#{remark}
        where id =#{id}
     </update>
+
     <select  id="getMaterialCategoryBySerialNo" resultMap="com.jsh.erp.datasource.mappers.MaterialCategoryMapper.BaseResultMap">
         select
         <include refid="com.jsh.erp.datasource.mappers.MaterialCategoryMapper.Base_Column_List"/>

+ 4 - 3
src/main/resources/mapper_xml/MaterialExtendMapper.xml

@@ -426,9 +426,6 @@
       <if test="barCode != null">
         bar_code = #{barCode,jdbcType=VARCHAR},
       </if>
-      <if test="inventory != null">
-        inventory = #{inventory,jdbcType=DECIMAL},
-      </if>
       <if test="depotId != null">
         depot_id = #{depotId,jdbcType=BIGINT},
       </if>
@@ -484,4 +481,8 @@
     AND ifnull(me.delete_Flag,'0') !='1'
   </select>
 
+  <select id="selectPosition"  resultType="String">
+    SELECT DISTINCT position FROM jsh_material_extend WHERE position IS NOT NULL AND ifnull(delete_Flag,'0') !='1'
+  </select>
+
 </mapper>

+ 64 - 10
src/main/resources/mapper_xml/MaterialMapperEx.xml

@@ -811,19 +811,73 @@
 
 
     <select id="getMaterialBySystemSku" parameterType="com.jsh.erp.datasource.entities.MaterialExample" resultType="com.jsh.erp.datasource.entities.MaterialVo4Unit">
-        select m.*,u.name unit_name, me.id meId,me.bar_code m_bar_code, me.commodity_unit, me.purchase_decimal, me.commodity_decimal,me.inventory
-        me.wholesale_decimal, me.low_decimal, me.sku, me.production_date, me.expiry_num, me.supplier_id, me.bar_code, me.batch_number, me.depot_id, me.position
+        WITH RankedExtend AS (
+            SELECT
+                me.*,
+                ROW_NUMBER() OVER (PARTITION BY me.material_id ORDER BY me.batch_number DESC) AS rn
+            FROM jsh_material_extend me
+            LEFT JOIN jsh_material m ON m.id = me.material_id
+            WHERE ifnull(me.delete_Flag, '0') != '1'
+              AND m.system_sku IN (
+                <foreach collection="systemSkuArray" item="systemSku" separator=",">
+                    #{systemSku}
+                </foreach>
+            )
+        )
+        SELECT
+            m.*,
+            re.id AS meId,
+            re.bar_code AS m_bar_code,
+            re.commodity_unit,
+            re.purchase_decimal,
+            re.commodity_decimal,
+            re.wholesale_decimal,
+            re.low_decimal,
+            me.sku,
+            me.production_date,
+            me.expiry_num,
+            me.supplier_id,
+            me.bar_code,
+            me.batch_number,
+            me.inventory,
+            me.depot_id,
+            me.POSITION
+        FROM jsh_material m
+        LEFT JOIN RankedExtend re ON m.id = re.material_id AND re.rn = 1
+        LEFT JOIN jsh_material_extend me ON re.bar_code = me.bar_code
+        WHERE ifnull(m.delete_flag, '0') != '1' AND re.id IS NOT NULL
+        ORDER BY m.id DESC, me.default_flag DESC, me.production_date,me.batch_number ASC
+    </select>
+
+    <select id="inventoryInquiry" resultType="com.jsh.erp.datasource.pda.vo.PDADepotItemVO">
+        select m.*,u.name unit_name,mc.name categoryName,me.bar_code,me.id meId,me.commodity_unit,me.sku,
+        me.production_date,me.expiry_num,me.supplier_id,me.batch_number,me.depot_id,me.position,d.`name` depotName,s.supplier supplierName
         from jsh_material m
         left join jsh_material_extend me on m.id=me.material_id and ifnull(me.delete_Flag,'0') !='1'
         left join jsh_unit u on m.unit_id=u.id and ifnull(u.delete_Flag,'0') !='1'
-        where
-        me.system_sku in (
-        <foreach collection="systemSkuArray" item="systemSku" separator=",">
-            #{systemSku}
-        </foreach>
-        )
-        and ifnull(m.delete_flag,'0') !='1'
-        order by m.id desc, me.default_flag desc,me.production_date asc, me.batch_number asc
+        left JOIN jsh_material_category mc on m.category_id = mc.id and ifnull(mc.delete_Flag,'0') !='1'
+        left JOIN jsh_depot d on me.depot_id = d.id and ifnull(d.delete_Flag,'0') !='1'
+        left JOIN jsh_supplier s on me.supplier_id = s.id and ifnull(s.delete_Flag,'0') !='1'
+        where m.enabled = 1
+        and me.id is not null
+        <if test="keyword != null and keyword !=''">
+            <bind name="bindKey" value="'%'+materialParam+'%'"/>
+            and me.batch_number like #{bindKey} or m.name like #{bindKey}
+        </if>
+        <if test="position != null and position !=''">
+            <bind name="bindPosition" value="'%'+position+'%'"/>
+            and me.position like #{bindPosition}
+        </if>
+        <if test="categoryId != null">
+            and m.category_id = #{category_id}
+        </if>
+        <if test="type == 'have'">
+            and me.inventory > 0
+        </if>
+        <if test="type == 'none'">
+            and me.inventory &lt;= 0
+        </if>
+        and ifnull(me.delete_flag,'0') !='1'
     </select>
 
 </mapper>

+ 12 - 12
src/main/resources/mapper_xml/SupplierMapper.xml

@@ -31,7 +31,7 @@
     <result column="settlement_method" jdbcType="VARCHAR" property="settlementMethod" />
     <result column="billing_cycle_days" jdbcType="INTEGER" property="billingCycleDays" />
     <result column="procurement_contact" jdbcType="VARCHAR" property="procurementContact" />
-    <result column="delivery_days" jdbcType="INTEGER" property="deliverydays" />
+    <result column="delivery_days" jdbcType="INTEGER" property="deliveryDays" />
     <result column="invoice_type" jdbcType="VARCHAR" property="invoiceType" />
     <result column="contract_upload" jdbcType="VARCHAR" property="contractUpload" />
   </resultMap>
@@ -146,10 +146,10 @@
             #{bankName,jdbcType=VARCHAR}, #{accountNumber,jdbcType=VARCHAR}, #{taxRate,jdbcType=DECIMAL},
             #{sort,jdbcType=VARCHAR}, #{creator,jdbcType=BIGINT}, #{tenantId,jdbcType=BIGINT},
             #{deleteFlag,jdbcType=VARCHAR}, #{supplierLevel,jdbcType=VARCHAR}, #{settlementMethod,jdbcType=VARCHAR},
-            #{billingCycleDays,jdbcType=INTEGER}, #{procurementContact,jdbcType=VARCHAR}, #{deliverydays,jdbcType=INTEGER},
+            #{billingCycleDays,jdbcType=INTEGER}, #{procurementContact,jdbcType=VARCHAR}, #{deliveryDays,jdbcType=INTEGER},
             #{invoiceType,jdbcType=VARCHAR}, #{contractUpload,jdbcType=VARCHAR})
   </insert>
-  <insert id="insertSelective" parameterType="com.jsh.erp.datasource.entities.Supplier">
+  <insert id="insertSelective" parameterType="com.jsh.erp.datasource.entities.Supplier" useGeneratedKeys="true" keyProperty="id">
     insert into jsh_supplier
     <trim prefix="(" suffix=")" suffixOverrides=",">
       <if test="id != null">
@@ -239,7 +239,7 @@
       <if test="procurementContact != null">
         procurement_contact,
       </if>
-      <if test="deliverydays != null">
+      <if test="deliveryDays != null">
         delivery_days,
       </if>
       <if test="invoiceType != null">
@@ -337,8 +337,8 @@
       <if test="procurementContact != null">
         #{procurementContact,jdbcType=VARCHAR},
       </if>
-      <if test="deliverydays != null">
-        #{deliverydays,jdbcType=INTEGER},
+      <if test="deliveryDays != null">
+        #{deliveryDays,jdbcType=INTEGER},
       </if>
       <if test="invoiceType != null">
         #{invoiceType,jdbcType=VARCHAR},
@@ -444,8 +444,8 @@
       <if test="record.procurementContact != null">
         procurement_contact = #{record.procurementContact,jdbcType=VARCHAR},
       </if>
-      <if test="record.deliverydays != null">
-        delivery_days = #{record.deliverydays,jdbcType=INTEGER},
+      <if test="record.deliveryDays != null">
+        delivery_days = #{record.deliveryDays,jdbcType=INTEGER},
       </if>
       <if test="record.invoiceType != null">
         invoice_type = #{record.invoiceType,jdbcType=VARCHAR},
@@ -489,7 +489,7 @@
       settlement_method = #{record.settlementMethod,jdbcType=VARCHAR},
       billing_cycle_days = #{record.billingCycleDays,jdbcType=INTEGER},
       procurement_contact = #{record.procurementContact,jdbcType=VARCHAR},
-      delivery_days = #{record.deliverydays,jdbcType=INTEGER},
+      delivery_days = #{record.deliveryDays,jdbcType=INTEGER},
       invoice_type = #{record.invoiceType,jdbcType=VARCHAR},
       contract_upload = #{record.contractUpload,jdbcType=VARCHAR}
     <if test="_parameter != null">
@@ -583,8 +583,8 @@
       <if test="procurementContact != null">
         procurement_contact = #{procurementContact,jdbcType=VARCHAR},
       </if>
-      <if test="deliverydays != null">
-        delivery_days = #{deliverydays,jdbcType=INTEGER},
+      <if test="deliveryDays != null">
+        delivery_days = #{deliveryDays,jdbcType=INTEGER},
       </if>
       <if test="invoiceType != null">
         invoice_type = #{invoiceType,jdbcType=VARCHAR},
@@ -625,7 +625,7 @@
       settlement_method = #{settlementMethod,jdbcType=VARCHAR},
       billing_cycle_days = #{billingCycleDays,jdbcType=INTEGER},
       procurement_contact = #{procurementContact,jdbcType=VARCHAR},
-      delivery_days = #{deliverydays,jdbcType=INTEGER},
+      delivery_days = #{deliveryDays,jdbcType=INTEGER},
       invoice_type = #{invoiceType,jdbcType=VARCHAR},
       contract_upload = #{contractUpload,jdbcType=VARCHAR}
     where id = #{id,jdbcType=BIGINT}