0023d3db5bd701864b73e57c0240c219c40c3a4e..ac8813cde64f7bf9882657416a1d102191aae960
2025-07-19 helongyang
Merge branch 'master' of http://115.159.85.185:8098/r/MeiRuiAn/HuaiAn
ac8813 对比 | 目录
2025-07-19 helongyang
成品报废单新增优化
63d187 对比 | 目录
2025-07-19 wangxinhui
1
79c3f9 对比 | 目录
2025-07-17 wangxinhui
1
cb3907 对比 | 目录
已添加2个文件
已修改14个文件
899 ■■■■■ 文件已修改
代码管理/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/成品仓/AGV_CPExtend.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSClient/src/extension/outbound/erpProScrapSheet.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSClient/src/extension/outbound/extend/AddErpProScrapSheet.vue 444 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSClient/src/extension/outbound/extend/ScrapSheet.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSClient/src/views/basic/palletCodeInfo.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/RworkTaskModel.cs 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/ErpProScrapSheetModel.cs 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_IOutboundService/IErpProScrapSheetService.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_IStockService/IProStockInfoService.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_MesRworkOutboundOrder.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_OutboundService/ErpProScrapSheetService.cs 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_StockRepository/ProStockInfoRepository.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_StockService/ProStockInfoService.cs 74 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/MesProductService.cs 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/ErpProScrapSheetController.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
代码管理/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/ProStockInfoController.cs 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
´úÂë¹ÜÀí/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/³ÉÆ·²Ö/AGV_CPExtend.cs
@@ -61,6 +61,10 @@
                            {
                                taskDTO.GroupId=task.GroupId;
                            }
                            if (task.TaskType==TaskTypeEnum.OutMesRworkProduct.ObjToInt())
                            {
                                taskDTO.Priority = "127";
                            }
                            //发送AGV任务
                            WebResponseContent content = _taskService.AgvSendTask(taskDTO, APIEnum.Agv_CPSendTask);
                            if (!content.Status)
´úÂë¹ÜÀí/WMS/WIDESEA_WMSClient/src/extension/outbound/erpProScrapSheet.js
@@ -1,10 +1,11 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
import gridBody from './extend/ScrapSheet.vue'
import gridHeader from './extend/AddErpProScrapSheet.vue'
let extension = {
  components: {
    //查询界面扩展组件
    gridHeader: '',
    gridHeader: gridHeader,
    gridBody: gridBody,
    gridFooter: '',
    //新建、编辑弹出框扩展组件
@@ -17,6 +18,13 @@
  methods: {
    //下面这些方法可以保留也可以删除
    onInit() {
      let addBtn = this.buttons.find(x => x.value == 'Add');
      if (addBtn) {
        addBtn.onClick = function () {
          this.$refs.gridHeader.open();
        }
      };
        this.columns.push({
            field: '操作',
            title: '操作',
´úÂë¹ÜÀí/WMS/WIDESEA_WMSClient/src/extension/outbound/extend/AddErpProScrapSheet.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,444 @@
<template>
  <div>
    <vol-box
      v-model="showDetialBox"
      :lazy="true"
      width="1300px"
      height="700px"
      :padding="20"
      title="添加成品超期报废明细"
    >
      <div style="max-height: 700px; overflow-y: auto;">
        <el-form ref="form" :model="form" label-width="130px">
          <!-- ä»“库选择 -->
          <el-form-item required label="所属仓库:">
            <el-select
              v-model="form.warehouseId"
              filterable
              placeholder="请选择仓库"
              @change="handleWarehouseChange"
              style="width: 100%;"
            >
              <el-option
                v-for="item in warehouses"
                :key="item.key"
                :label="item.value"
                :value="item.key"
              >
                <span style="float: left">{{ item.value }}</span>
                <span style="float: right; color: #8492a6; font-size: 13px">{{ item.key }}</span>
              </el-option>
            </el-select>
          </el-form-item>
          <!-- å•据编号(只读) -->
          <el-form-item required label="单据编号:">
            <el-input
              v-model="form.proScrapSheetOrderNo"
              placeholder="系统将自动生成"
              readonly
              style="width: 100%;"
            ></el-input>
          </el-form-item>
          <!-- æ˜Žç»†åˆ—表 -->
          <el-form-item label="报废明细:">
            <div v-for="(detail, index) in detailList" :key="index" class="detail-item">
              <div class="detail-header">
                <span>明细 {{ index + 1 }}</span>
                <el-button
                  type="text"
                  size="mini"
                  color="#f56c6c"
                  @click="removeDetail(index)"
                  :disabled="detailList.length <= 1"
                >
                  åˆ é™¤
                </el-button>
              </div>
              <el-row :gutter="20" class="detail-row">
                <el-col :span="6">
                  <el-form-item
                    required
                    :prop="'detailList.' + index + '.scrapProCode'"
                    :rules="{ required: true, message: '请选择产品编码', trigger: 'blur' }"
                  >
                    <el-select
                      v-model="detail.scrapProCode"
                      filterable
                      placeholder="产品编码"
                      @change="handleProCodeChange(detail, index)"
                      clearable
                      style="width: 100%;"
                    >
                      <el-option
                        v-for="(code, index) in proCodeOptions"
                        :key="index"
                        :label="code"
                        :value="code"
                      ></el-option>
                    </el-select>
                  </el-form-item>
                </el-col>
                <el-col :span="5">
                  <el-form-item
                    required
                    :prop="'detailList.' + index + '.scrapProVersion'"
                    :rules="{ required: true, message: '请选择版本', trigger: 'blur' }"
                  >
                    <el-select
                      v-model="detail.scrapProVersion"
                      filterable
                      placeholder="版本"
                      clearable
                      style="width: 100%;"
                    >
                      <el-option
                        v-for="item in detail.versionOptions"
                        :key="item"
                        :label="item"
                        :value="item"
                      ></el-option>
                    </el-select>
                  </el-form-item>
                </el-col>
                <el-col :span="5">
                  <el-form-item
                    required
                    :prop="'detailList.' + index + '.scrapProLotNo'"
                    :rules="{ required: true, message: '请选择批次号', trigger: 'blur' }"
                  >
                    <el-select
                      v-model="detail.scrapProLotNo"
                      filterable
                      placeholder="批次号"
                      clearable
                      style="width: 100%;"
                    >
                      <el-option
                        v-for="item in detail.lotNoOptions"
                        :key="item"
                        :label="item"
                        :value="item"
                      ></el-option>
                    </el-select>
                  </el-form-item>
                </el-col>
                <el-col :span="4">
                  <el-form-item
                    required
                    :prop="'detailList.' + index + '.scrapPcsQty'"
                    :rules="{
                      required: true,
                      message: '请输入PCS数量',
                      trigger: 'blur',
                      validator: validateNumber // è‡ªå®šä¹‰æ•°å­—校验
                    }"
                  >
                    <el-input
                      v-model="detail.scrapPcsQty"
                      placeholder="PCS数量"
                      style="width: 100%;"
                      @blur="formatNumber(detail, 'scrapPcsQty')"
                    ></el-input>
                  </el-form-item>
                </el-col>
              </el-row>
              <el-row :gutter="20" class="detail-row">
                <el-col :span="24">
                  <el-form-item label="备注:">
                    <el-input
                      v-model="detail.remark"
                      placeholder="请输入备注信息"
                      type="textarea"
                      rows="2"
                      style="width: 100%;"
                    ></el-input>
                  </el-form-item>
                </el-col>
              </el-row>
            </div>
            <!-- æ·»åŠ æ˜Žç»†æŒ‰é’® -->
            <el-button
              type="dashed"
              size="small"
              class="add-detail-btn"
              @click="addDetail"
              :disabled="detailList.length >= 10"
              style="width: 100%; margin-top: 15px;"
            >
              <i class="el-icon-plus"></i> æ·»åŠ æ˜Žç»†
            </el-button>
          </el-form-item>
        </el-form>
      </div>
      <!-- åº•部按钮 -->
      <template #footer>
        <el-button type="primary" size="mini" @click="submitForm" style="padding: 8px 20px;">确认提交</el-button>
        <el-button type="danger" size="mini" @click="close" style="padding: 8px 20px; margin-left: 10px;">关闭</el-button>
      </template>
    </vol-box>
  </div>
</template>
<script>
import VolBox from "@/components/basic/VolBox.vue";
export default {
  components: { VolBox },
  data() {
    const validateNumber = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('请输入数量'));
      }
      const numberRegex = /^\d+(\.\d+)?$/;
      if (!numberRegex.test(value)) {
        return callback(new Error('请输入有效的数字'));
      }
      if (parseFloat(value) <= 0) {
        return callback(new Error('数量必须大于0'));
      }
      callback();
    };
    return {
      showDetialBox: false,
      warehouses: [],
      proCodeOptions: [],
      form: {
        warehouseId: "",
        proScrapSheetOrderNo: ""
      },
      detailList: [
        {
          scrapProCode: "",
          scrapProVersion: "",
          scrapProLotNo: "",
          scrapPcsQty: "",
          remark: "",
          versionOptions: [],
          lotNoOptions: []
        }
      ],
      validateNumber
    };
  },
  methods: {
    // æ‰“开弹窗
    open() {
      this.initForm();
      this.showDetialBox = true;
    },
    // åˆå§‹åŒ–表单
    initForm() {
      this.form = {
        warehouseId: "",
        proScrapSheetOrderNo: ""
      };
      this.detailList = [this.createEmptyDetail()];
      // åŠ è½½ä»“åº“åˆ—è¡¨
      if (this.warehouses.length === 0) {
        this.getWarehouseList();
      }
    },
    // åˆ›å»ºç©ºæ˜Žç»†
    createEmptyDetail() {
      return {
        scrapProCode: "",
        scrapProVersion: "",
        scrapProLotNo: "",
        scrapPcsQty: "",
        remark: "",
        versionOptions: [],
        lotNoOptions: []
      };
    },
    // èŽ·å–ä»“åº“åˆ—è¡¨
    getWarehouseList() {
      this.http
        .post("api/Warehouse/GetWarehouseDicByUser", null, "加载仓库数据中")
        .then((res) => {
          if (!res.status) return this.$message.error(res.message);
          this.warehouses = res.data || [];
          // è‹¥åªæœ‰ä¸€ä¸ªä»“库,自动选中
          if (this.warehouses.length === 1) {
            this.form.warehouseId = this.warehouses[0].key;
            this.handleWarehouseChange(this.warehouses[0].key);
          }
        });
    },
    // ä»“库变更事件
    handleWarehouseChange(warehouseId) {
      if (!warehouseId) return;
      // æ ¹æ®ä»“库ID加载产品编码列表
      this.http
        .post(`api/ProStockInfo/GetProCodeByWarehouse?warehouseId=${this.form.warehouseId}`,null, "加载产品数据中")
        .then((res) => {
          if (res.status) {
            this.proCodeOptions = [...new Set(res.data)];
          } else {
            this.$message.error(res.message);
          }
        });
    },
    // äº§å“ç¼–码变更事件
    handleProCodeChange(detail, index) {
      if (!detail.scrapProCode) {
        detail.versionOptions = [];
        detail.lotNoOptions = [];
        return;
      }
      // æ ¹æ®äº§å“ç¼–码加载版本列表
      this.http
      .post(
        `api/ProStockInfo/GetProVersionByCode?scrapProCode=${detail.scrapProCode}&warehouseId=${this.form.warehouseId}`,null, "加载版本数据中")
        .then((res) => {
          if (res.status) {
            detail.versionOptions = [...new Set(res.data)];
          }
        });
      // æ ¹æ®äº§å“ç¼–码加载批次号列表
      this.http
        .post(`api/ProStockInfo/GetProLotNoByCode?scrapProCode=${detail.scrapProCode}&warehouseId=${this.form.warehouseId}`,null, "加载批次数据中")
        .then((res) => {
          if (res.status) {
            detail.lotNoOptions = [...new Set(res.data)];
          }
        });
    },
    formatNumber(detail, field) {
      if (!detail[field]) return;
      let value = detail[field].replace(/[^0-9.]/g, '');
      const decimalIndex = value.indexOf('.');
      if (decimalIndex !== -1) {
        value = value.substring(0, decimalIndex + 1) + value.substring(decimalIndex + 1).replace(/\./g, '');
      }
      const parts = value.split('.');
      if (parts.length > 1 && parts[1].length > 2) {
        parts[1] = parts[1].substring(0, 2);
        value = parts.join('.');
      }
      detail[field] = value;
    },
    // æ·»åŠ æ˜Žç»†
    addDetail() {
      this.detailList.push(this.createEmptyDetail());
    },
    // åˆ é™¤æ˜Žç»†
    removeDetail(index) {
      this.detailList.splice(index, 1);
    },
    // æäº¤è¡¨å•
    submitForm() {
  if (!this.form.warehouseId) {
    return this.$message.error("请选择所属仓库");
  }
  const invalidDetail = this.detailList.find(item =>
    !item.scrapProCode || !item.scrapProVersion || !item.scrapProLotNo || !item.scrapPcsQty  || isNaN(parseFloat(item.scrapPcsQty))|| parseFloat(item.scrapPcsQty) <= 0
  );
  if (invalidDetail) {
    return this.$message.error("请为所有明细输入有效的数量值(大于0的数字)");
  }
  const submitData = {
    warehouseId: this.form.warehouseId,
    details: this.detailList.map(item => ({
      scrapProCode: item.scrapProCode,
      scrapProVersion: item.scrapProVersion,
      scrapProLotNo: item.scrapProLotNo,
      scrapPcsQty: parseFloat(item.scrapPcsQty),
      remark: item.remark
    }))
  };
  this.http
    .post("api/ErpProScrapSheet/Save", submitData, "提交中")
    .then((res) => {
          if (!res.status) return this.$message.error(res.message);
          this.$message.success("操作成功");
          this.close();
          this.$emit("parentCall", ($vue) => {
            $vue.refresh();
          });
        });
    },
    // å…³é—­å¼¹çª—
    close() {
      this.showDetialBox = false;
    }
  },
  created() {
    // åˆå§‹åŒ–时预加载仓库数据
    if (this.warehouses.length === 0) {
      this.getWarehouseList();
    }
  }
};
</script>
<style scoped>
.detail-item {
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  padding: 15px;
  margin-bottom: 20px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.detail-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px dashed #e4e7ed;
  font-weight: 500;
}
.detail-row {
  margin-bottom: 15px;
}
.add-detail-btn {
  height: 40px;
  line-height: 38px;
}
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
::-webkit-scrollbar-thumb {
  background-color: #ddd;
  border-radius: 4px;
}
::-webkit-scrollbar-track {
  background-color: #f5f5f5;
}
</style>
´úÂë¹ÜÀí/WMS/WIDESEA_WMSClient/src/extension/outbound/extend/ScrapSheet.vue
@@ -236,20 +236,26 @@
            prop: "overScrapSETQty",
            title: "已报废SET数",
            type: "int",
            width: 180,
            width: 120,
          },
          {
            prop: "overScrapPcsQty",
            title: "已报废PCS数",
            type: "string",
            width: 180,
            width: 120,
          },
          {
            prop: "scrapProDetailStatus",
            title: "订单明细状态",
            type: "string",
            width: 180,
        }
          },
          {
            prop: "remark",
            title: "备注",
            type: "string",
            width: 180,
          }
        ],
      };
    },
´úÂë¹ÜÀí/WMS/WIDESEA_WMSClient/src/views/basic/palletCodeInfo.vue
@@ -29,20 +29,7 @@
    const editFormFields = ref({});
    const editFormOptions = ref([
      [
        {
          title: "仓库",
          field: "warehouseId",
          type: "select",
          dataKey: "warehouses",
          data: [],
          required: true,
        },
        {
          title: "数量",
          field: "count",
          type: "int",
          required: true,
        },
      ],
    ]);
    const searchFormFields = ref({
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/RworkTaskModel.cs
@@ -39,14 +39,26 @@
        [PropertyValidate("周期", NotNullAndEmpty = true)]
        public string DateCode { get; set; }
        /// <summary>
        /// éœ€æ±‚数量
        /// éœ€æ±‚PCS数量
        /// </summary>
        [PropertyValidate("需求数量", NotNullAndEmpty = true)]
        public float RequiredQuantity { get; set; }
        /// <summary>
        /// éœ€æ±‚SET数量
        /// </summary>
        public float RequiredSetCount { get; set; }
        /// <summary>
        /// ä»“库
        /// </summary>
        public string WarehouseCode { get; set; }
        /// <summary>
        /// å·¥åŽ‚
        /// </summary>
        public string FactoryCode { get; set; }
        public string FactoryCode { get; set; } = "HA02";
        /// <summary>
        /// æŽ¥æ”¶
        /// </summary>
        public int ReceiveDown { get; set; }
        /// <summary>
        /// é”€å”®è®¢å•
        /// </summary>
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Outbound/ErpProScrapSheetModel.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core.Attributes;
namespace WIDESEA_DTO.Outbound
{
    /// <summary>
    /// æˆå“æŠ¥åºŸå•新增
    /// </summary>
    [ModelValidate]
    public class ErpProScrapSheetModel
    {
        // <summary>
        /// ä»“库Id
        /// </summary>
        [PropertyValidate("仓库Id", NotNullAndEmpty = true)]
        public int WarehouseId { get; set; }
        /// <summary>
        /// å•据编号
        /// </summary>
        [PropertyValidate("单据编号", NotNullAndEmpty = true)]
        public string ProScrapSheetOrderNo { get; set; }
        /// <summary>
        /// æŠ¥åºŸæ˜Žç»†
        /// </summary>
        [PropertyValidate("报废明细", NotNullAndEmpty = true)]
        public List<ErpProScrapSheetDetailDTO> Details { get; set; }
    }
    [ModelValidate]
    public class ErpProScrapSheetDetailDTO
    {
        /// <summary>
        /// äº§å“ç¼–码
        /// </summary>
        [PropertyValidate("产品编码", NotNullAndEmpty = true)]
        public string ScrapProCode { get; set; }
        /// <summary>
        /// æŠ¥åºŸç‰ˆæœ¬
        /// </summary>
        [PropertyValidate("报废版本", NotNullAndEmpty = true)]
        public string ScrapProVersion { get; set; }
        /// <summary>
        /// æ‰¹æ¬¡å·
        /// </summary>
        [PropertyValidate("批次号", NotNullAndEmpty = true)]
        public string ScrapProLotNo { get; set; }
        /// <summary>
        /// æŠ¥åºŸSET数量
        /// </summary>
        [PropertyValidate("报废SET数量", NotNullAndEmpty = true)]
        public int ScrapSETQty { get; set; }
        /// <summary>
        /// æŠ¥åºŸPCS数
        /// </summary>
        [PropertyValidate("报废PCS数", NotNullAndEmpty = true)]
        public int ScrapPcsQty { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [PropertyValidate("备注", NotNullAndEmpty = false)]
        public string Remark { get; set; }
    }
}
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_IOutboundService/IErpProScrapSheetService.cs
@@ -8,11 +8,13 @@
using WIDESEA_Core;
using WIDESEA_IOutboundRepository;
using WIDESEA_Model.Models;
using WIDESEA_DTO.Outbound;
namespace WIDESEA_IOutboundService
{
    public interface IErpProScrapSheetService : IService<Dt_ErpProScrapSheet>
    {
        IErpProScrapSheetRepository Repository { get; }
        public WebResponseContent Save(ErpProScrapSheetModel addProScrapSheet);
    }
}
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_IStockService/IProStockInfoService.cs
@@ -43,5 +43,23 @@
        /// èŽ·å–æˆå“æŠ¥åºŸçš„åº“å­˜
        /// </summary>
        List<Dt_ProStockInfo> GetOutboundStocks(List<Dt_ProStockInfo> stockInfos, Dt_ErpProScrapSheetDetail outOrderDetail, float needQuantity, out float residueQuantity);
        /// <summary>
        /// æŠ¥åºŸå•库存产品编号查询
        /// </summary>
        /// <param name="warehouseId"></param>
        /// <returns></returns>
        public WebResponseContent GetProCodeByWarehouse(int warehouseId);
        /// <summary>
        /// æŠ¥åºŸå•库存版本查询
        /// </summary>
        /// <param name="scrapProCode"></param>
        /// <returns></returns>
        public WebResponseContent GetProVersionByCode(string scrapProCode,int warehouseId);
        /// <summary>
        /// æŠ¥åºŸå•库存批次号查询
        /// </summary>
        /// <param name="scrapProCode"></param>
        /// <returns></returns>
        public WebResponseContent GetProLotNoByCode(string scrapProCode, int warehouseId);
    }
}
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Outbound/Dt_MesRworkOutboundOrder.cs
@@ -93,11 +93,16 @@
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "周期")]
        public string DateCode { get; set; }
        /// <summary>
        /// éœ€æ±‚数量
        /// éœ€æ±‚PCS数量
        /// </summary>
        [SugarColumn(IsNullable = false, ColumnDescription = "需求数量", DefaultValue = "0")]
        public float RequiredQuantity { get; set; }
        /// <summary>
        /// éœ€æ±‚SET数量
        /// </summary>
        [SugarColumn(IsNullable = false, ColumnDescription = "需求数量", DefaultValue = "0")]
        public float RequiredSetCount { get; set; }
        /// <summary>
        /// å·¥åŽ‚
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "工厂")]
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_OutboundService/ErpProScrapSheetService.cs
@@ -1,4 +1,5 @@
using System;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -9,7 +10,12 @@
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.CodeConfigEnum;
using WIDESEA_Core.DB;
using WIDESEA_Core.Helper;
using WIDESEA_Core.Seed;
using WIDESEA_DTO.Outbound;
using WIDESEA_IBasicService;
using WIDESEA_IOutboundRepository;
using WIDESEA_IOutboundService;
using WIDESEA_Model.Models;
@@ -19,11 +25,14 @@
    public partial class ErpProScrapSheetService : ServiceBase<Dt_ErpProScrapSheet, IErpProScrapSheetRepository>, IErpProScrapSheetService
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly IWarehouseService _warehouseService;
        public IErpProScrapSheetRepository Repository => BaseDal;
        public ErpProScrapSheetService(IErpProScrapSheetRepository BaseDal, IUnitOfWorkManage unitOfWorkManage) : base(BaseDal)
        public ErpProScrapSheetService(IErpProScrapSheetRepository BaseDal, IUnitOfWorkManage unitOfWorkManage,IWarehouseService warehouseService) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _warehouseService = warehouseService;
        }
        public override WebResponseContent AddData(SaveModel saveModel)
        {
@@ -60,5 +69,104 @@
            }
            return base.AddData(saveModel);
        }
        public WebResponseContent Save(ErpProScrapSheetModel addProScrapSheet) {
            try
            {
                List<Dt_ErpProScrapSheetDetail> erpProScrapSheetDetails = new List<Dt_ErpProScrapSheetDetail>();
                if (addProScrapSheet.Details != null)
                {
                    foreach (var model in addProScrapSheet.Details)
                    {
                        Dt_ErpProScrapSheetDetail erpProScrapSheetDetail = new Dt_ErpProScrapSheetDetail()
                        {
                            ScrapProCode = model.ScrapProCode,
                            ScrapProVersion = model.ScrapProVersion,
                            ScrapProLotNo = model.ScrapProLotNo,
                            ScrapPcsQty = model.ScrapPcsQty,
                            ScrapSETQty = 0,
                        };
                        erpProScrapSheetDetails.Add(erpProScrapSheetDetail);
                    }
                }
                Dt_ErpProScrapSheet erpProScrapSheet = new Dt_ErpProScrapSheet()
                {
                    WarehouseId = addProScrapSheet.WarehouseId,
                    ProScrapSheetOrderNo = CreateCodeByRule(nameof(RuleCodeEnum.ProScrapSheetRule)),
                    ProScrapStatus = ProScrapSheetStatusEnum.TOChecked.ObjToInt(),
                    Details = erpProScrapSheetDetails
                };
                _unitOfWorkManage.BeginTran();
                Db.InsertNav(erpProScrapSheet).Include(x => x.Details).ExecuteCommand();
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK();
            }
            catch(Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        static object lock_code = new object();
        public string CreateCodeByRule(string ruleCode)
        {
            lock (lock_code)
            {
                string code = string.Empty;
                DateTime dateTime = DateTime.Now;
                DateTime now = DateTime.Now;
                try
                {
                    if (string.IsNullOrEmpty(ruleCode))
                        throw new ArgumentNullException(nameof(ruleCode));
                    SqlSugarClient sugarClient = new SqlSugarClient(new ConnectionConfig
                    {
                        IsAutoCloseConnection = true,
                        DbType = DbType.SqlServer,
                        ConnectionString = DBContext.ConnectionString
                    });
                    Dt_CodeRuleConfig codeRuleConfig = sugarClient.Queryable<Dt_CodeRuleConfig>().Where(x => x.RuleCode == ruleCode).First();
                    if (codeRuleConfig == null)
                        throw new ArgumentNullException(nameof(codeRuleConfig));
                    if (codeRuleConfig.ModifyDate != null)
                    {
                        dateTime = Convert.ToDateTime(codeRuleConfig.ModifyDate);
                    }
                    else
                    {
                        dateTime = Convert.ToDateTime(codeRuleConfig.CreateDate);
                    }
                    if (now.Year == dateTime.Year && now.Month == dateTime.Month && now.Day == dateTime.Day)
                    {
                        now = dateTime;
                        codeRuleConfig.CurrentVal = Convert.ToInt32(codeRuleConfig.CurrentVal) + 1;
                    }
                    else
                    {
                        codeRuleConfig.CurrentVal = 1;
                    }
                    codeRuleConfig.ModifyDate = DateTime.Now;
                    code = codeRuleConfig.Format;
                    code = code.Replace($"[{CodeFormatTypeEnum.YYYY}]", now.Year.ToString().PadLeft(4, '0'));
                    code = code.Replace($"[{CodeFormatTypeEnum.MM}]", now.Month.ToString().PadLeft(2, '0'));
                    code = code.Replace($"[{CodeFormatTypeEnum.DD}]", now.Day.ToString().PadLeft(2, '0'));
                    code = code.Replace($"[{CodeFormatTypeEnum.ST}]", codeRuleConfig.StartStr?.ToString() ?? "");
                    code = code.Replace($"[{CodeFormatTypeEnum.NUM}]", codeRuleConfig.CurrentVal.ToString().PadLeft(codeRuleConfig.Length, '0'));
                    Dictionary<string, object> keyValuePairs = new Dictionary<string, object>() { { nameof(codeRuleConfig.CurrentVal), codeRuleConfig.CurrentVal }, { nameof(codeRuleConfig.Id), codeRuleConfig.Id }, { nameof(codeRuleConfig.ModifyDate), DateTime.Now } };
                    sugarClient.Updateable(keyValuePairs).AS(MainDb.CodeRuleConfig).WhereColumns(nameof(codeRuleConfig.Id)).ExecuteCommand();
                    sugarClient.Updateable(codeRuleConfig);
                }
                catch (Exception ex)
                {
                }
                return code;
            }
        }
    }
}
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_StockRepository/ProStockInfoRepository.cs
@@ -77,8 +77,7 @@
            proStockInfos = Db.Queryable<Dt_ProStockInfo>().Where(x => locationInfos.Contains(x.LocationCode))
                .Includes(x => x.proStockInfoDetails)
                .Where(x => x.proStockInfoDetails
                .Any(v => v.SaleOrder == mesRworkOutboundOrder.SaleOrder
                && v.ProductCode == mesRworkOutboundOrder.ProductCode
                .Any(v => v.ProductCode == mesRworkOutboundOrder.ProductCode
                && v.ProductVersion == mesRworkOutboundOrder.ProductVersion
                && (isCanDate ? isCanDate : v.DateCode == mesRworkOutboundOrder.DateCode)
                ))
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_StockService/ProStockInfoService.cs
@@ -109,7 +109,7 @@
        public List<Dt_ProStockInfo> GetUseableStocks(Dt_MesRworkOutboundOrder mesRworkOutboundOrder)
        {
            //转换成 æˆå“ä»“仓库信息获取尾数属性的货位
            Dt_Warehouse warehouse = _basicRepository.WarehouseRepository.QueryFirst(x=>x.WarehouseCode==WarehouseEnum.HA71.ToString());
            Dt_Warehouse warehouse = _basicRepository.WarehouseRepository.QueryFirst(x=>x.WarehouseId== mesRworkOutboundOrder.WarehouseId);
            List<string> locationCodes = _basicRepository.LocationInfoRepository.GetCanOutLocationCodes(warehouse.WarehouseId);
            return BaseDal.GetProStocks(mesRworkOutboundOrder, locationCodes);
        }
@@ -125,10 +125,14 @@
        public List<Dt_ProStockInfo> GetOutboundStocks(List<Dt_ProStockInfo> stockInfos, Dt_ProOutOrderDetail outOrderDetail, float needQuantity, out float residueQuantity)
        {
            List<Dt_ProStockInfo> assignOutStocks =new List<Dt_ProStockInfo>();
            float stockTotalQuantity = stockInfos.Select(x => x.proStockInfoDetails.Sum(v => v.StockPcsQty - v.OutboundQuantity)).Sum(x => x);
            //stockInfos = stockInfos.OrderBy(x => x.Id).ToList();
            bool isCanLot = string.IsNullOrEmpty(outOrderDetail.PLot);
            bool isCanDate = string.IsNullOrEmpty(outOrderDetail.DateCode);
            float stockTotalQuantity = stockInfos.Select(x => x.proStockInfoDetails.Where(x => x.ProductCode == outOrderDetail.PCode && x.ProductVersion.StartsWith(outOrderDetail.PVer.Substring(0, 1))
                            && (isCanLot ? isCanLot : x.BagNo == outOrderDetail.PLot)
                            && (isCanDate ? isCanDate : x.DateCode == outOrderDetail.DateCode))
                        .Sum(v => v.StockPcsQty - v.OutboundQuantity)).Sum(x => x);
            //stockInfos = stockInfos.OrderBy(x => x.Id).ToList();
            if (stockTotalQuantity >= needQuantity)//库存够
            {
                int index = 0;
@@ -233,7 +237,10 @@
        public List<Dt_ProStockInfo> GetOutboundStocks(List<Dt_ProStockInfo> stockInfos, Dt_ErpProScrapSheetDetail outOrderDetail, float needQuantity, out float residueQuantity)
        {
            List<Dt_ProStockInfo> assignOutStocks = new List<Dt_ProStockInfo>();
            float stockTotalQuantity = stockInfos.Select(x => x.proStockInfoDetails.Sum(v => v.StockPcsQty - v.OutboundQuantity)).Sum(x => x);
            float stockTotalQuantity = stockInfos.Select(x => x.proStockInfoDetails.Where(x =>
                            x.ProductCode == outOrderDetail.ScrapProCode
                            && x.ProductVersion == outOrderDetail.ScrapProVersion
                            && x.LotNumber == outOrderDetail.ScrapProLotNo).Sum(v => v.StockPcsQty - v.OutboundQuantity)).Sum(x => x);
            //stockInfos = stockInfos.OrderBy(x => x.Id).ToList();
            if (stockTotalQuantity >= needQuantity)//库存够
            {
@@ -293,9 +300,12 @@
        public List<Dt_ProStockInfo> GetOutboundStocks(List<Dt_ProStockInfo> stockInfos, Dt_MesRworkOutboundOrder mesRworkOutboundOrder, float needQuantity, out float residueQuantity)
        {
            List<Dt_ProStockInfo> assignOutStocks = new List<Dt_ProStockInfo>();
            float stockTotalQuantity = stockInfos.Select(x => x.proStockInfoDetails.Sum(v => v.StockPcsQty - v.OutboundQuantity)).Sum(x => x);
            //stockInfos = stockInfos.OrderBy(x => x.Id).ToList();
            bool isCanDate = string.IsNullOrEmpty(mesRworkOutboundOrder.DateCode);
            float stockTotalQuantity = stockInfos.Select(x => x.proStockInfoDetails.Where(x => x.ProductCode == mesRworkOutboundOrder.ProductCode
                            && x.ProductVersion == mesRworkOutboundOrder.ProductVersion
                            && (isCanDate ? isCanDate : x.DateCode == mesRworkOutboundOrder.DateCode))
                        .Sum(v => v.StockPcsQty - v.OutboundQuantity)).Sum(x => x);
            //stockInfos = stockInfos.OrderBy(x => x.Id).ToList();
            if (stockTotalQuantity >= needQuantity)//库存够
            {
                int index = 0;
@@ -303,8 +313,7 @@
                {
                    Dt_ProStockInfo stockInfo = stockInfos[index];
                    float useableStockQuantity = stockInfo.proStockInfoDetails
                        .Where(x => x.SaleOrder == mesRworkOutboundOrder.SaleOrder
                            && x.ProductCode == mesRworkOutboundOrder.ProductCode
                        .Where(x => x.ProductCode == mesRworkOutboundOrder.ProductCode
                            && x.ProductVersion == mesRworkOutboundOrder.ProductVersion
                            && (isCanDate? isCanDate: x.DateCode == mesRworkOutboundOrder.DateCode))
                        .Sum(x => x.StockPcsQty - x.OutboundQuantity);
@@ -317,7 +326,7 @@
                    {
                        stockInfo.proStockInfoDetails.ForEach(x =>
                        {
                            if ((x.StockPcsQty > x.OutboundQuantity) && x.SaleOrder == mesRworkOutboundOrder.SaleOrder
                            if ((x.StockPcsQty > x.OutboundQuantity)
                                && x.ProductCode == mesRworkOutboundOrder.ProductCode 
                                && x.ProductVersion == mesRworkOutboundOrder.ProductVersion
                                && (isCanDate ? isCanDate : x.DateCode == mesRworkOutboundOrder.DateCode))
@@ -362,5 +371,52 @@
        //    }
        //    return (deleteStockDetails, updateStockDetails);
        //}
        public WebResponseContent GetProCodeByWarehouse(int warehouseId)
        {
            try
            {
                List<Dt_ProStockInfo> proStockInfo = BaseDal.QueryData(x => x.WarehouseId == warehouseId);
                List<int> proStockId = proStockInfo.Select(x => x.Id).ToList();
                List<Dt_ProStockInfoDetail> proStockInfoDetails = BaseDal.Db.Queryable<Dt_ProStockInfoDetail>().Where(x => proStockId.Contains(x.OutDetailId)).ToList();
                List<string> proCode = proStockInfoDetails.Select(x => x.ProductCode).ToList();
                return WebResponseContent.Instance.OK(data: proCode);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        public WebResponseContent GetProVersionByCode(string scrapProCode, int warehouseId)
        {
            try
            {
                List<Dt_ProStockInfo> proStockInfo = BaseDal.QueryData(x => x.WarehouseId == warehouseId);
                List<int> proStockId = proStockInfo.Select(x => x.Id).ToList();
                List<Dt_ProStockInfoDetail> proStockInfoDetails = BaseDal.Db.Queryable<Dt_ProStockInfoDetail>().Where(x => scrapProCode.Contains(x.ProductCode) && proStockId.Contains(x.OutDetailId)).ToList();
                List<string> productVersion = proStockInfoDetails.Select(x => x.ProductVersion).ToList();
                return WebResponseContent.Instance.OK(data: productVersion);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        public WebResponseContent GetProLotNoByCode(string scrapProCode, int warehouseId)
        {
            try
            {
                List<Dt_ProStockInfo> proStockInfo = BaseDal.QueryData(x => x.WarehouseId == warehouseId);
                List<int> proStockId = proStockInfo.Select(x => x.Id).ToList();
                List<Dt_ProStockInfoDetail> proStockInfoDetails = BaseDal.Db.Queryable<Dt_ProStockInfoDetail>().Where(x => scrapProCode.Contains(x.ProductCode) && proStockId.Contains(x.OutDetailId)).ToList();
                List<string> lotNumber = proStockInfoDetails.Select(x => x.LotNumber).ToList();
                return WebResponseContent.Instance.OK(data: lotNumber);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
    }
}
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/MesProductService.cs
@@ -531,7 +531,7 @@
            MesResponseContent content = new MesResponseContent();
            try
            {
                Dt_Warehouse warehouse = _basicRepository.WarehouseRepository.QueryFirst(x => x.WarehouseCode == WarehouseEnum.HA72.ToString());
                Dt_Warehouse warehouse = _basicRepository.WarehouseRepository.QueryFirst(x => x.WarehouseCode == model.WarehouseCode);
                if (warehouse == null)
                {
                    return content.Error($"尾数仓信息未配置");
@@ -546,17 +546,58 @@
                {
                    WarehouseId = warehouse.WarehouseId,
                    TaskNo = model.TaskNo,
                    OrderStatus = OutOrderStatusEnum.未开始.ObjToInt(),
                    OrderStatus = OutOrderStatusEnum.出库中.ObjToInt(),
                    CreateType = OrderCreateTypeEnum.UpperSystemPush.ObjToInt(),
                    ProductCode = model.ProductCode,
                    ProductName = model.ProductName,
                    ProductName = model.ProductCode,
                    ProductVersion = model.ProductVersion,
                    DateCode = model.DateCode,
                    RequiredQuantity = model.RequiredQuantity,
                    RequiredSetCount=model.RequiredSetCount,
                    FactoryCode = model.FactoryCode,
                    SaleOrder = model.SaleOrder,
                    SaleOrder = model.SaleOrder ?? "",
                    OrderType = model.InventoryType
                };
                if (model.DateCode.IndexOf("平库")>0 || warehouse.WarehouseCode==WarehouseEnum.HA101.ToString())
                {
                    Dt_Warehouse warehousePing = _basicRepository.WarehouseRepository.QueryFirst(x => x.WarehouseCode == WarehouseEnum.HA101.ToString());
                    mesRworkOutboundOrder.WarehouseId = warehousePing.WarehouseId;
                    mesRworkOutboundOrder.OrderStatus = OutOrderStatusEnum.出库完成.ObjToInt();
                    _unitOfWorkManage.BeginTran();
                    _outboundService.RworkOutboundOrderService.Repository.AddData(mesRworkOutboundOrder);
                    MesInventoryInfo mesInventoryInfo = new MesInventoryInfo()
                    {
                        Warhouseno = warehousePing.WarehouseCode,
                        InternalPackageNumber = model.ProductCode,
                        SetCount = (int)model.RequiredSetCount,
                        EligiblePcsCount = (int)model.RequiredQuantity
                    };
                    MesProductOutBound mesProductOutBound = new MesProductOutBound()
                    {
                        TaskNo = mesRworkOutboundOrder.TaskNo,
                        ProductCode = mesRworkOutboundOrder.ProductCode,
                        ProductVersion = mesRworkOutboundOrder.ProductVersion,
                        DateCode = mesRworkOutboundOrder.DateCode,
                        SaleOrder = mesRworkOutboundOrder.SaleOrder,
                        InventoryInfo = new List<MesInventoryInfo> { mesInventoryInfo  }
                    };
                    if (model.ReceiveDown==EnableEnum.Enable.ObjToInt())
                    {
                        _unitOfWorkManage.RollbackTran();
                    }
                    else
                    {
                        //MES成品库存板出库同步
                        WebResponseContent responseContentPing = _outboundService.RworkOutboundOrderService.ProductOutBoundSync(mesProductOutBound);
                        if (!responseContentPing.Status)
                        {
                            throw new Exception("同步MES库存板出库失败,错误:" + responseContentPing.Message);
                        }
                        _unitOfWorkManage.CommitTran();
                    }
                    return content.OK($"提供返库单接收成功,ReceiveDown:{model.ReceiveDown}");
                }
                List<Dt_Task> tasks = new List<Dt_Task>();
                List<Dt_ProStockInfo>? proStockInfos = null;
                List<Dt_OutProStockInfo>? outProStockInfos = null;
@@ -605,19 +646,25 @@
                    if (!updateContent.Status)
                    {
                        _unitOfWorkManage.RollbackTran();
                        return content.Error(updateContent.Message);
                        throw new Exception(updateContent.Message);
                    }
                }
                _outboundService.RworkOutboundOrderService.Repository.AddData(mesRworkOutboundOrder);
                //MES成品库存板出库同步
                WebResponseContent responseContent = _outboundService.RworkOutboundOrderService.ProductOutBoundSync(_outboundService.RworkOutboundOrderService.MesProOutBound(mesRworkOutboundOrder, proStockInfoDetails));
                if (!responseContent.Status)
                if (model.ReceiveDown == EnableEnum.Enable.ObjToInt())
                {
                    throw new Exception("同步MES库存板出库失败,错误:" + responseContent.Message);
                    _unitOfWorkManage.RollbackTran();
                }
                _unitOfWorkManage.CommitTran();
                return content.OK("提供返库单接收成功");
                else
                {
                    //MES成品库存板出库同步
                    WebResponseContent responseContent = _outboundService.RworkOutboundOrderService.ProductOutBoundSync(_outboundService.RworkOutboundOrderService.MesProOutBound(mesRworkOutboundOrder, proStockInfoDetails));
                    if (!responseContent.Status)
                    {
                        throw new Exception("同步MES库存板出库失败,错误:" + responseContent.Message);
                    }
                    _unitOfWorkManage.CommitTran();
                }
                return content.OK($"提供返库单接收成功,ReceiveDown:{model.ReceiveDown}");
            }
            catch (Exception ex)
            {
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Outbound/ErpProScrapSheetController.cs
@@ -4,6 +4,7 @@
using WIDESEA_Core;
using WIDESEA_IOutboundService;
using WIDESEA_Model.Models;
using WIDESEA_DTO.Outbound;
namespace WIDESEA_WMSServer.Controllers.Outbound
{
@@ -17,5 +18,10 @@
        public ErpProScrapSheetController(IErpProScrapSheetService service) : base(service)
        {
        }
        [HttpGet,HttpPost,Route("Save"),AllowAnonymous]
        public WebResponseContent Save([FromBody] ErpProScrapSheetModel addProScrapSheet)
        {
            return Service.Save(addProScrapSheet);
        }
    }
}
´úÂë¹ÜÀí/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/ProStockInfoController.cs
@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WIDESEA_Core;
using WIDESEA_Core.BaseController;
using WIDESEA_IStockService;
using WIDESEA_Model.Models;
@@ -15,5 +17,37 @@
        public ProStockInfoController(IProStockInfoService service) : base(service)
        {
        }
        /// <summary>
        /// æŠ¥åºŸå•库存产品编号查询
        /// </summary>
        /// <param name="warehouseId"></param>
        /// <returns></returns>
        [HttpPost,HttpGet,Route("GetProCodeByWarehouse"),AllowAnonymous]
        public WebResponseContent GetProCodeByWarehouse(int warehouseId)
        {
            return Service.GetProCodeByWarehouse(warehouseId);
        }
        /// <summary>
        /// æŠ¥åºŸå•库存版本查询
        /// </summary>
        /// <param name="warehouseId"></param>
        /// <returns></returns>
        [HttpPost, HttpGet, Route("GetProVersionByCode"), AllowAnonymous]
        public WebResponseContent GetProVersionByCode(string scrapProCode,int warehouseId)
        {
            return Service.GetProVersionByCode(scrapProCode,warehouseId);
        }
        /// <summary>
        /// æŠ¥åºŸå•库存版本查询
        /// </summary>
        /// <param name="warehouseId"></param>
        /// <returns></returns>
        [HttpPost, HttpGet, Route("GetProLotNoByCode"), AllowAnonymous]
        public WebResponseContent GetProLotNoByCode(string scrapProCode, int warehouseId)
        {
            return Service.GetProLotNoByCode(scrapProCode, warehouseId);
        }
    }
}