Forráskód Böngészése

feat: 合同负责人下拉框改造 & 6模块租户隔离治理

- 合同评审表单合同负责人改为租户人员下拉选择

- Order/ProcurementExecution/Production/Supply/Universal/WorkOrder 6模块增加租户ID过滤

- LineSkillMaster移除冲突的SugarIndex唯一索引

- 升级前端版本到2.4.174,后端版本到1.0.142
Pengxy 5 hónapja
szülő
commit
790e17a888
52 módosított fájl, 796 hozzáadás és 322 törlés
  1. 1 1
      Web/package.json
  2. 6 0
      Web/src/views/aidop/api/contractReview.ts
  3. 35 1
      Web/src/views/aidop/business/contractReviewForm.vue
  4. 17 0
      doc/migrations/2026-06-01_add_tenant_id_to_modules.sql
  5. 5 0
      doc/migrations/2026-06-01_custmaster_tenant_id.sql
  6. 3 3
      server/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj
  7. 1 1
      server/Plugins/Admin.NET.Plugin.AiDOP/Entity/S0/Manufacturing/AdoS0LineSkillDetail.cs
  8. 0 1
      server/Plugins/Admin.NET.Plugin.AiDOP/Entity/S0/Manufacturing/AdoS0LineSkillMaster.cs
  9. 25 17
      server/Plugins/Admin.NET.Plugin.AiDOP/Order/AsnShipperService.cs
  10. 32 0
      server/Plugins/Admin.NET.Plugin.AiDOP/Order/ContractReviewService.cs
  11. 19 10
      server/Plugins/Admin.NET.Plugin.AiDOP/Order/MdpMonitorService.cs
  12. 64 60
      server/Plugins/Admin.NET.Plugin.AiDOP/Order/OrderDeliveryService.cs
  13. 14 8
      server/Plugins/Admin.NET.Plugin.AiDOP/Order/ProductDesignService.cs
  14. 6 3
      server/Plugins/Admin.NET.Plugin.AiDOP/Order/RequirementExamineDetailService.cs
  15. 14 7
      server/Plugins/Admin.NET.Plugin.AiDOP/Order/S1MdpMonitorService.cs
  16. 9 6
      server/Plugins/Admin.NET.Plugin.AiDOP/Order/ShippingPlanService.cs
  17. 6 0
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/PurOrdRctDetail.cs
  18. 6 0
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/PurOrdRctMaster.cs
  19. 6 0
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/ScmJhjhJq.cs
  20. 6 0
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/ScmShd.cs
  21. 6 0
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/ScmShdzb.cs
  22. 5 3
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/IqcReturnQueryService.cs
  23. 49 22
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/PurchaseReturnService.cs
  24. 18 6
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/SupplierDeliveryManagementService.cs
  25. 35 16
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/SupplierShipmentService.cs
  26. 5 3
      server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/SupplierShortageKanbanService.cs
  27. 12 5
      server/Plugins/Admin.NET.Plugin.AiDOP/Production/ExecutableDailyPlanService.cs
  28. 22 13
      server/Plugins/Admin.NET.Plugin.AiDOP/Production/QualityLineWorkDetailService.cs
  29. 21 13
      server/Plugins/Admin.NET.Plugin.AiDOP/Production/ResourceOvertimeService.cs
  30. 15 8
      server/Plugins/Admin.NET.Plugin.AiDOP/Production/ScheduleExceptionService.cs
  31. 24 15
      server/Plugins/Admin.NET.Plugin.AiDOP/Production/ShopCalendarWorkCtrService.cs
  32. 7 3
      server/Plugins/Admin.NET.Plugin.AiDOP/Production/WorkOrderProgressDashboardService.cs
  33. 4 2
      server/Plugins/Admin.NET.Plugin.AiDOP/Production/WorkOrderSchedulingService.cs
  34. 8 1
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/DeliveryExceptionService.cs
  35. 15 4
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/DeliveryScheduleService.cs
  36. 31 19
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/DemandOrderService.cs
  37. 10 5
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/DemandScheduleService.cs
  38. 6 0
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/Entity/PurOrdDetail.cs
  39. 6 0
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/Entity/PurOrdMaster.cs
  40. 24 8
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/NumberRuleService.cs
  41. 52 19
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/OutsourceOrderService.cs
  42. 24 12
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/ProcessOutsourceOrderService.cs
  43. 13 1
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/PurchaseOrderService.cs
  44. 32 14
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/PurchaseRequestService.cs
  45. 24 4
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/S3MdpMonitorService.cs
  46. 23 1
      server/Plugins/Admin.NET.Plugin.AiDOP/Supply/WorkOrderMaterialReadinessService.cs
  47. 4 0
      server/Plugins/Admin.NET.Plugin.AiDOP/Universal/Entity/CustMaster.cs
  48. 5 1
      server/Plugins/Admin.NET.Plugin.AiDOP/Universal/UniversalCustomerService.cs
  49. 5 1
      server/Plugins/Admin.NET.Plugin.AiDOP/Universal/UniversalItemService.cs
  50. 7 1
      server/Plugins/Admin.NET.Plugin.AiDOP/Universal/UniversalSourceListService.cs
  51. 6 2
      server/Plugins/Admin.NET.Plugin.AiDOP/Universal/UniversalWorkOrderService.cs
  52. 3 2
      server/Plugins/Admin.NET.Plugin.AiDOP/WorkOrder/WorkOrderDispatchService.cs

+ 1 - 1
Web/package.json

@@ -1,7 +1,7 @@
 {
 	"name": "admin.net",
 	"type": "module",
-	"version": "2.4.173",
+	"version": "2.4.174",
 	"packageManager": "pnpm@10.32.1",
 	"lastBuildTime": "2026.03.15",
 	"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",

+ 6 - 0
Web/src/views/aidop/api/contractReview.ts

@@ -116,3 +116,9 @@ export function deleteContractReview(recID: number) {
 		.post<unknown>('/api/Order/contract/delete', { recID })
 		.then((r) => unwrapFurionBody<unknown>(r.data));
 }
+
+export function fetchResponsibleUsers(keyword?: string) {
+	return service
+		.get<unknown>('/api/Order/contract/responsible-users', { params: { keyword } })
+		.then((r) => unwrapFurionBody<{ value: string; label: string }[]>(r.data));
+}

+ 35 - 1
Web/src/views/aidop/business/contractReviewForm.vue

@@ -34,7 +34,9 @@
 				</div>
 				<div class="cr-label">合同负责人</div>
 				<div class="cr-value">
-					<el-input v-model="form.responsibleName" :disabled="!canEdit" placeholder="请输入姓名" />
+					<el-select v-model="form.responsibleAccount" filterable remote :remote-method="searchResponsibleUsers" placeholder="请选择合同负责人" clearable :disabled="!canEdit" style="width: 100%" @change="onResponsibleChange">
+						<el-option v-for="item in responsibleUserOptions" :key="item.value" :label="item.label" :value="item.value" />
+					</el-select>
 				</div>
 				<div class="cr-label">合同开始时间</div>
 				<div class="cr-value">
@@ -194,6 +196,7 @@ import ApprovalPanel from '/@/views/approvalFlow/component/ApprovalPanel.vue';
 import { useUserInfo } from '/@/stores/userInfo';
 import {
 	fetchContractReviewDetail,
+	fetchResponsibleUsers,
 	saveContractReview,
 	type ContractReviewDetail,
 	type ContractReviewFlowNode,
@@ -215,6 +218,33 @@ const currentUserId = computed(() => (userInfo.userInfos?.id as number | undefin
 const loading = ref(false);
 const saving = ref(false);
 
+const responsibleUserOptions = ref<{ value: string; label: string }[]>([]);
+
+async function searchResponsibleUsers(query: string) {
+	if (!query) return;
+	try {
+		const list = await fetchResponsibleUsers(query);
+		responsibleUserOptions.value = list ?? [];
+	} catch {
+		responsibleUserOptions.value = [];
+	}
+}
+
+function onResponsibleChange(val: string) {
+	const found = responsibleUserOptions.value.find((item) => item.value === val);
+	form.responsibleName = found?.label ?? '';
+}
+
+async function initResponsibleOptions() {
+	if (!form.responsibleAccount) return;
+	try {
+		const list = await fetchResponsibleUsers(form.responsibleAccount);
+		responsibleUserOptions.value = list ?? [];
+	} catch {
+		responsibleUserOptions.value = [];
+	}
+}
+
 const detail = ref<ContractReviewDetail | null>(null);
 const flows = ref<ContractReviewFlowNode[]>([]);
 
@@ -317,6 +347,8 @@ async function loadDetail() {
 			projectRequirement: d.projectRequirement ?? '',
 			remark: d.remark ?? '',
 		});
+		// 编辑回显:初始化合同负责人下拉选项
+		await initResponsibleOptions();
 	} catch (e: any) {
 		ElMessage.error(e?.message || '加载合同评审详情失败');
 		detail.value = null;
@@ -387,6 +419,8 @@ async function loadDetailById(id: number) {
 			projectRequirement: d.projectRequirement ?? '',
 			remark: d.remark ?? '',
 		});
+		// 编辑回显:初始化合同负责人下拉选项
+		await initResponsibleOptions();
 	} catch (e: any) {
 		ElMessage.error(e?.message || '加载合同评审详情失败');
 	} finally {

+ 17 - 0
doc/migrations/2026-06-01_add_tenant_id_to_modules.sql

@@ -0,0 +1,17 @@
+-- 为各模块实体表补充 tenant_id 字段
+-- 执行前请确认表中是否已存在该列
+
+-- ============================
+-- ProcurementExecution 模块
+-- ============================
+ALTER TABLE `PurOrdRctDetail` ADD COLUMN `tenant_id` BIGINT NULL COMMENT '租户Id';
+ALTER TABLE `PurOrdRctMaster` ADD COLUMN `tenant_id` BIGINT NULL COMMENT '租户Id';
+ALTER TABLE `scm_jhjh_jq` ADD COLUMN `tenant_id` BIGINT NULL COMMENT '租户Id';
+ALTER TABLE `scm_shd` ADD COLUMN `tenant_id` BIGINT NULL COMMENT '租户Id';
+ALTER TABLE `scm_shdzb` ADD COLUMN `tenant_id` BIGINT NULL COMMENT '租户Id';
+
+-- ============================
+-- Supply 模块
+-- ============================
+ALTER TABLE `PurOrdDetail` ADD COLUMN `tenant_id` BIGINT NULL COMMENT '租户Id';
+ALTER TABLE `PurOrdMaster` ADD COLUMN `tenant_id` BIGINT NULL COMMENT '租户Id';

+ 5 - 0
doc/migrations/2026-06-01_custmaster_tenant_id.sql

@@ -0,0 +1,5 @@
+-- CustMaster 表添加 tenant_id 列(多租户隔离)
+-- 执行:mysql -h HOST -P 3306 -u USER -p aidopdev < 2026-06-01_custmaster_tenant_id.sql
+
+ALTER TABLE CustMaster
+  ADD COLUMN IF NOT EXISTS `tenant_id` bigint NULL DEFAULT NULL COMMENT '租户ID(多租户隔离)' AFTER `BankAcct`;

+ 3 - 3
server/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj

@@ -11,9 +11,9 @@
     <GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
     <Copyright>Admin.NET</Copyright>
     <Description>Admin.NET 通用权限开发平台</Description>
-    <AssemblyVersion>1.0.141</AssemblyVersion>
-    <FileVersion>1.0.141</FileVersion>
-    <Version>1.0.141</Version>
+    <AssemblyVersion>1.0.142</AssemblyVersion>
+    <FileVersion>1.0.142</FileVersion>
+    <Version>1.0.142</Version>
   </PropertyGroup>
 
   <ItemGroup>

+ 1 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Entity/S0/Manufacturing/AdoS0LineSkillDetail.cs

@@ -6,7 +6,7 @@ namespace Admin.NET.Plugin.AiDOP.Entity.S0.Manufacturing;
 [SugarTable("LineSkillDetail", "产线岗位技能明细")]
 public class AdoS0LineSkillDetail : ITenantIdFilter
 {
-    [SugarColumn(ColumnName = "id", ColumnDescription = "明细主键", IsPrimaryKey = true, IsIdentity = true, ColumnDataType = "bigint")]
+    [SugarColumn(ColumnName = "id", ColumnDescription = "明细主键", IsPrimaryKey = true, IsIdentity = false, ColumnDataType = "bigint")]
     public long Id { get; set; }
 
     [SugarColumn(ColumnName = "line_skill_master_id", ColumnDescription = "产线岗位主表ID", ColumnDataType = "bigint")]

+ 0 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Entity/S0/Manufacturing/AdoS0LineSkillMaster.cs

@@ -4,7 +4,6 @@ namespace Admin.NET.Plugin.AiDOP.Entity.S0.Manufacturing;
 /// 产线岗位维护(源平台 LineSkillMaster 语义,头表)。
 /// </summary>
 [SugarTable("LineSkillMaster", "产线岗位主表")]
-[SugarIndex("uk_LineSkillMaster_domain_job", nameof(Domain), OrderByType.Asc, nameof(JOBNo), OrderByType.Asc, IsUnique = true)]
 public class AdoS0LineSkillMaster : ITenantIdFilter
 {
     [SugarColumn(ColumnName = "RecID", ColumnDescription = "产线岗位主键", IsPrimaryKey = true, IsIdentity = true, ColumnDataType = "bigint")]

+ 25 - 17
server/Plugins/Admin.NET.Plugin.AiDOP/Order/AsnShipperService.cs

@@ -38,12 +38,14 @@ public class AsnShipperService : IDynamicApiController, ITransient
     [HttpGet("asnshipper/list")]
     public async Task<object> GetAsnShipperList([FromQuery] AsnShipperListInput input)
     {
-        var pars = new List<SugarParameter>();
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
         var conditions = new List<string>
         {
             "a.shtype = 'SH'",
             "a.Typed <> 'S'",
-            "a.IsActive = 1"
+            "a.IsActive = 1",
+            "a.tenant_id = @TenantId"
         };
 
         if (!string.IsNullOrWhiteSpace(input.Id))
@@ -102,36 +104,37 @@ public class AsnShipperService : IDynamicApiController, ITransient
     [HttpGet("asnshipper/{id}")]
     public async Task<object> GetAsnShipperDetail(int id)
     {
-        var master = await _masterRep.GetFirstAsync(u => u.RecID == id)
+        var tenantId = _userManager.TenantId;
+        var master = await _masterRep.GetFirstAsync(u => u.RecID == id && u.TenantId == tenantId)
                      ?? throw Oops.Oh("发货单不存在");
 
         // 查询客户名称,用于前端下拉回显"编号+名称"
         var soldToName = (await _db.Queryable<CustMaster>()
-            .Where(u => u.Cust == master.SoldTo)
+            .Where(u => u.Cust == master.SoldTo && u.TenantId == tenantId)
             .Select(u => u.SortName)
             .FirstAsync()) ?? string.Empty;
 
         // 查询销售单客户名称,用于前端下拉回显"编号_客户名称"
         var ordNbrName = string.IsNullOrWhiteSpace(master.OrdNbr) ? string.Empty
             : ((await _db.Queryable<SeOrder>()
-                .Where(u => u.BillNo == master.OrdNbr)
+                .Where(u => u.BillNo == master.OrdNbr && u.TenantId == tenantId)
                 .Select(u => u.CustomName)
                 .FirstAsync()) ?? string.Empty);
 
         // 查询部门描述,用于前端下拉回显"编号+描述"
         var deptName = string.IsNullOrWhiteSpace(master.Department) ? string.Empty
             : ((await _db.Queryable<AdoS0DepartmentMaster>()
-                .Where(u => u.Department == master.Department)
+                .Where(u => u.Department == master.Department && u.TenantId == tenantId)
                 .Select(u => u.Descr)
                 .FirstAsync()) ?? string.Empty);
 
         // 主键关联:ASNBOLShipperDetail.ASNBOLShipperRecID = 主表 RecID
-        var details = await _detailRep.GetListAsync(u => u.AsnShipperRecID == id);
+        var details = await _detailRep.GetListAsync(u => u.AsnShipperRecID == id && u.TenantId == tenantId);
         // 兼容历史数据:若外键未写入或曾用错误方式取 RecID,则按业务单号 Id + 销售单号 OrdNbr 兜底
         if (details.Count == 0 && !string.IsNullOrWhiteSpace(master.Id) && !string.IsNullOrWhiteSpace(master.OrdNbr))
         {
             details = await _detailRep.GetListAsync(u =>
-                u.Id == master.Id && u.OrdNbr == master.OrdNbr);
+                u.Id == master.Id && u.OrdNbr == master.OrdNbr && u.TenantId == tenantId);
         }
 
         return new
@@ -213,7 +216,8 @@ public class AsnShipperService : IDynamicApiController, ITransient
         else
         {
             // ── 编辑:参照 SysJobService.UpdateJobDetail ──
-            var entity = await _masterRep.GetFirstAsync(u => u.RecID == input.RecID.Value)
+            var tenantId = _userManager.TenantId;
+            var entity = await _masterRep.GetFirstAsync(u => u.RecID == input.RecID.Value && u.TenantId == tenantId)
                          ?? throw Oops.Oh("发货单不存在");
 
             entity.Id = input.Id;
@@ -242,7 +246,7 @@ public class AsnShipperService : IDynamicApiController, ITransient
         List<AsnShipperDetailInput> details, string user, DateTime now, bool isNew)
     {
         var dbDetails = isNew ? new List<AsnShipperDetail>()
-            : await _detailRep.GetListAsync(u => u.AsnShipperRecID == masterRecId);
+            : await _detailRep.GetListAsync(u => u.AsnShipperRecID == masterRecId && u.TenantId == _userManager.TenantId);
         var dbById = dbDetails.ToDictionary(u => u.RecID);
         var inputIds = new HashSet<int>(details.Where(d => d.RecID is > 0).Select(d => d.RecID!.Value));
 
@@ -316,7 +320,8 @@ public class AsnShipperService : IDynamicApiController, ITransient
     public async Task<object> DeleteAsnShipper([FromBody] AsnShipperDeleteInput input)
     {
         // 参照 SysJobService.DeleteJobDetail:先查再删
-        var entity = await _masterRep.GetFirstAsync(u => u.RecID == input.RecID)
+        var tenantId = _userManager.TenantId;
+        var entity = await _masterRep.GetFirstAsync(u => u.RecID == input.RecID && u.TenantId == tenantId)
                      ?? throw Oops.Oh("发货单不存在");
 
         if (entity.Status == "C")
@@ -336,8 +341,9 @@ public class AsnShipperService : IDynamicApiController, ITransient
     [HttpGet("asnshipper/options/salesords")]
     public async Task<object> GetSalesOrdOptions([FromQuery] string? keyword)
     {
-        var pars = new List<SugarParameter>();
-        var where = "s.IsDeleted = 0";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "s.IsDeleted = 0 AND s.tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(keyword))
         {
             where += " AND (s.bill_no LIKE @kw OR s.custom_name LIKE @kw)";
@@ -366,8 +372,9 @@ public class AsnShipperService : IDynamicApiController, ITransient
     [HttpGet("asnshipper/options/customers")]
     public async Task<object> GetCustomerOptions([FromQuery] string? keyword)
     {
-        var pars = new List<SugarParameter>();
-        var where = "1=1";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(keyword))
         {
             where += " AND (Cust LIKE @kw OR SortName LIKE @kw)";
@@ -395,8 +402,9 @@ public class AsnShipperService : IDynamicApiController, ITransient
     [HttpGet("asnshipper/options/departments")]
     public async Task<object> GetDepartmentOptions([FromQuery] string? keyword)
     {
-        var pars = new List<SugarParameter>();
-        var where = "1=1";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(keyword))
         {
             where += " AND (Department LIKE @kw OR Descr LIKE @kw)";

+ 32 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Order/ContractReviewService.cs

@@ -246,8 +246,40 @@ public class ContractReviewService : IDynamicApiController, ITransient
         return new { message = "删除成功" };
     }
 
+    // ══════════════════════════════════════════════════════════════
+    // 合同负责人下拉框 GET /api/Order/contract/responsible-users
+    // ══════════════════════════════════════════════════════════════
+    /// <summary>获取合同负责人下拉选项(当前租户用户列表)📋</summary>
+    [DisplayName("获取合同负责人下拉选项")]
+    [HttpGet("contract/responsible-users")]
+    public async Task<List<object>> GetResponsibleUsers([FromQuery] string? keyword)
+    {
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var conditions = new List<string> { "tenant_id = @TenantId" };
+
+        if (!string.IsNullOrWhiteSpace(keyword))
+        {
+            conditions.Add("(Account LIKE @Keyword OR RealName LIKE @Keyword)");
+            pars.Add(new SugarParameter("@Keyword", $"%{keyword.Trim()}%"));
+        }
+
+        var whereClause = "WHERE " + string.Join(" AND ", conditions);
+        var sql = $"SELECT Account, RealName FROM sys_user {whereClause} ORDER BY Account LIMIT 100";
+
+        var rows = await _db.Ado.SqlQueryAsync<ResponsibleUserRow>(sql, pars);
+
+        return rows.Select(r => (object)new { value = r.Account, label = r.RealName }).ToList();
+    }
+
     // ──────────────── 内部查询结果映射类 ────────────────
 
+    private sealed class ResponsibleUserRow
+    {
+        public string? Account { get; set; }
+        public string? RealName { get; set; }
+    }
+
     private sealed class ContractReviewListRow
     {
         public int RecID { get; set; }

+ 19 - 10
server/Plugins/Admin.NET.Plugin.AiDOP/Order/MdpMonitorService.cs

@@ -16,10 +16,12 @@ public class MdpMonitorService : IDynamicApiController, ITransient
     };
 
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public MdpMonitorService(ISqlSugarClient db)
+    public MdpMonitorService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     [DisplayName("MDP模块选项")]
@@ -36,7 +38,8 @@ public class MdpMonitorService : IDynamicApiController, ITransient
     [HttpGet("mdp-monitor/latest")]
     public async Task<object> GetLatest([FromQuery] MdpMonitorQueryInput input)
     {
-        var (whereSql, pars) = BuildWhere(input);
+        var tenantId = _userManager.TenantId;
+        var (whereSql, pars) = BuildWhere(input, tenantId);
         return await _db.Ado.SqlQuerySingleAsync<MdpMonitorRunLogRow>(
             $"""
             {SelectColumnsSql()}
@@ -53,10 +56,11 @@ public class MdpMonitorService : IDynamicApiController, ITransient
     [HttpGet("mdp-monitor/list")]
     public async Task<object> GetList([FromQuery] MdpMonitorListInput input)
     {
+        var tenantId = _userManager.TenantId;
         var page = input.Page <= 0 ? 1 : input.Page;
         var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
         var offset = (page - 1) * pageSize;
-        var (whereSql, pars) = BuildWhere(input);
+        var (whereSql, pars) = BuildWhere(input, tenantId);
 
         var total = await _db.Ado.GetIntAsync($"SELECT COUNT(1) FROM mdp_transform_run_log WHERE {whereSql}", pars);
         var list = await _db.Ado.SqlQueryAsync<MdpMonitorRunLogRow>(
@@ -76,7 +80,8 @@ public class MdpMonitorService : IDynamicApiController, ITransient
     [HttpGet("mdp-monitor/detail/{id}")]
     public async Task<object> GetDetail(long id, [FromQuery] MdpMonitorQueryInput input)
     {
-        var (whereSql, pars) = BuildWhere(input);
+        var tenantId = _userManager.TenantId;
+        var (whereSql, pars) = BuildWhere(input, tenantId);
         pars.Add(new SugarParameter("@Id", id));
 
         var row = await _db.Ado.SqlQuerySingleAsync<MdpMonitorRunLogRow>(
@@ -94,6 +99,7 @@ public class MdpMonitorService : IDynamicApiController, ITransient
     [HttpGet("mdp-monitor/lineage")]
     public async Task<object> GetLineage([FromQuery] MdpMonitorLineageInput input)
     {
+        var tenantId = _userManager.TenantId;
         var moduleCode = ResolveModuleCode(input.ModuleCode, input.JobCode);
         if (string.IsNullOrWhiteSpace(moduleCode))
             throw Oops.Oh("请选择 MDP 模块");
@@ -115,10 +121,11 @@ public class MdpMonitorService : IDynamicApiController, ITransient
                    e.incr_column AS IncrColumn, e.status AS Status
             FROM mdp_entity e
             LEFT JOIN mdp_source s ON s.id = e.source_id
-            WHERE e.entity_code LIKE @EntityPrefix
+            WHERE e.entity_code LIKE @EntityPrefix AND e.tenant_id = @TenantId
             ORDER BY e.entity_code
             """,
-            new SugarParameter("@EntityPrefix", entityPrefix));
+            new SugarParameter("@EntityPrefix", entityPrefix),
+            new SugarParameter("@TenantId", tenantId));
 
         if (entities.Count == 0)
         {
@@ -156,13 +163,15 @@ public class MdpMonitorService : IDynamicApiController, ITransient
                        error_msg AS ErrorMsg
                 FROM mdp_sync_log
                 WHERE sync_batch_id = @BatchId
+                  AND tenant_id = @TenantId
                   AND entity_id IN (
                       SELECT id FROM mdp_entity WHERE entity_code LIKE @EntityPrefix
                   )
                 ORDER BY sync_start, id
                 """,
                 new SugarParameter("@BatchId", input.BatchId.Trim()),
-                new SugarParameter("@EntityPrefix", entityPrefix));
+                new SugarParameter("@EntityPrefix", entityPrefix),
+                new SugarParameter("@TenantId", tenantId));
             syncLogsByEntity = syncLogs
                 .GroupBy(u => u.EntityId)
                 .ToDictionary(u => u.Key, u => u.OrderByDescending(x => x.SyncStart).First());
@@ -192,10 +201,10 @@ public class MdpMonitorService : IDynamicApiController, ITransient
         };
     }
 
-    private static (string WhereSql, List<SugarParameter> Parameters) BuildWhere(MdpMonitorQueryInput input)
+    private static (string WhereSql, List<SugarParameter> Parameters) BuildWhere(MdpMonitorQueryInput input, long tenantId)
     {
-        var where = new List<string> { "IFNULL(job_code, '') LIKE '%MDP%'" };
-        var pars = new List<SugarParameter>();
+        var where = new List<string> { "IFNULL(job_code, '') LIKE '%MDP%'", "tenant_id = @TenantId" };
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
 
         var jobCode = ResolveJobCode(input.ModuleCode, input.JobCode);
         if (!string.IsNullOrWhiteSpace(jobCode))

+ 64 - 60
server/Plugins/Admin.NET.Plugin.AiDOP/Order/OrderDeliveryService.cs

@@ -128,22 +128,24 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
     [HttpGet("delivery/flow/{entryId}")]
     public async Task<object> GetDeliveryFlow(long entryId)
     {
+        var tenantId = _userManager.TenantId;
+
         // 同一 ISqlSugarClient 底层共用一条连接,不能对 _db.Ado 并发执行多查询(MySqlConnector 会报 Cannot Open when State is Connecting)
-        var basic = await QueryBasic(entryId);
-        var orderInfo = await QueryOrderInfo(entryId);
-        var review = await QueryReview(entryId);
-        var changes = await QueryChanges(entryId);
-        var schedule = await QuerySchedule(entryId);
-        var material = await QueryMaterials(entryId);
-        var po = await QueryPo(entryId);
-        var pr = await QueryPr(entryId);
-        var deliverySchedule = await QueryDeliverySchedule(entryId);
-        var nbr = await QueryNbr(entryId);
-        var prodReport = await QueryProdReport(entryId);
-        var iqc = await QueryIqc(entryId);
-        var fqc = await QueryFqc(entryId);
-        var receipt = await QueryReceipt(entryId);
-        var shipment = await QueryShipment(entryId);
+        var basic = await QueryBasic(entryId, tenantId);
+        var orderInfo = await QueryOrderInfo(entryId, tenantId);
+        var review = await QueryReview(entryId, tenantId);
+        var changes = await QueryChanges(entryId, tenantId);
+        var schedule = await QuerySchedule(entryId, tenantId);
+        var material = await QueryMaterials(entryId, tenantId);
+        var po = await QueryPo(entryId, tenantId);
+        var pr = await QueryPr(entryId, tenantId);
+        var deliverySchedule = await QueryDeliverySchedule(entryId, tenantId);
+        var nbr = await QueryNbr(entryId, tenantId);
+        var prodReport = await QueryProdReport(entryId, tenantId);
+        var iqc = await QueryIqc(entryId, tenantId);
+        var fqc = await QueryFqc(entryId, tenantId);
+        var receipt = await QueryReceipt(entryId, tenantId);
+        var shipment = await QueryShipment(entryId, tenantId);
 
         return new
         {
@@ -160,7 +162,7 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
     }
 
     // ── 基础信息 ──
-    private async Task<FlowBasicRow?> QueryBasic(long entryId)
+    private async Task<FlowBasicRow?> QueryBasic(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -174,13 +176,13 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
                 entry.update_time   AS Mrptime
             FROM crm_seorderentry entry
             LEFT JOIN crm_seorder sorder ON entry.seorder_id = sorder.Id
-            WHERE entry.Id = @Id AND entry.IsDeleted = 0
+            WHERE entry.Id = @Id AND entry.IsDeleted = 0 AND entry.tenant_id = @TenantId
             """;
-        return (await _db.Ado.SqlQueryAsync<FlowBasicRow>(sql, new { Id = entryId })).FirstOrDefault();
+        return (await _db.Ado.SqlQueryAsync<FlowBasicRow>(sql, new { Id = entryId, TenantId = tenantId })).FirstOrDefault();
     }
 
     // ── Tab1 订单信息 ──
-    private async Task<FlowOrderInfoRow?> QueryOrderInfo(long entryId)
+    private async Task<FlowOrderInfoRow?> QueryOrderInfo(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -198,16 +200,16 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
                 sorder.emp_no           AS EmpNo
             FROM crm_seorderentry entry
             LEFT JOIN crm_seorder sorder ON entry.seorder_id = sorder.Id
-            WHERE entry.Id = @Id AND entry.IsDeleted = 0
+            WHERE entry.Id = @Id AND entry.IsDeleted = 0 AND entry.tenant_id = @TenantId
             """;
-        return (await _db.Ado.SqlQueryAsync<FlowOrderInfoRow>(sql, new { Id = entryId })).FirstOrDefault();
+        return (await _db.Ado.SqlQueryAsync<FlowOrderInfoRow>(sql, new { Id = entryId, TenantId = tenantId })).FirstOrDefault();
     }
 
     // ── Tab2 订单评审 ──
     /// <remarks>
     /// 查询最新评审记录(num=1 的首行物料)的预计交期评估信息。
     /// </remarks>
-    private async Task<FlowReviewRow?> QueryReview(long entryId)
+    private async Task<FlowReviewRow?> QueryReview(long entryId, long tenantId)
     {
         //测试提交
         const string sql = """
@@ -221,20 +223,20 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
             FROM b_examine_result a
             LEFT JOIN b_bom_child_examine b ON a.id = b.examine_id
             LEFT JOIN mes_moentry c ON a.sentry_id = c.soentry_id
-            LEFT JOIN mes_morder d ON c.moentry_mono = d.morder_no            WHERE a.create_time = (
+            LEFT JOIN mes_morder d ON c.moentry_mono = d.morder_no            WHERE a.tenant_id = @TenantId AND a.create_time = (
                 SELECT MAX(create_time)
                 FROM b_examine_result
-                WHERE sentry_id = @EntryId
+                WHERE sentry_id = @EntryId AND tenant_id = @TenantId
             )
             AND b.num = 1
             AND a.sentry_id = @EntryId
             LIMIT 1
             """;
-        return (await _db.Ado.SqlQueryAsync<FlowReviewRow>(sql, new { EntryId = entryId })).FirstOrDefault();
+        return (await _db.Ado.SqlQueryAsync<FlowReviewRow>(sql, new { EntryId = entryId, TenantId = tenantId })).FirstOrDefault();
     }
 
     // ── Tab2 变更记录(MySQL:按订单行关联变更单)──
-    private async Task<List<FlowChangeRow>> QueryChanges(long entryId)
+    private async Task<List<FlowChangeRow>> QueryChanges(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -245,14 +247,14 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
                 a.change_content AS ChangeContent,
                 a.update_time AS UpdateTime
             FROM crm_seorder_change a
-            LEFT JOIN crm_seorderentry b ON a.bill_no = b.bill_no            WHERE a.bill_no IS NOT NULL AND b.id = @Id
+            LEFT JOIN crm_seorderentry b ON a.bill_no = b.bill_no            WHERE a.bill_no IS NOT NULL AND b.id = @Id AND b.tenant_id = @TenantId
             ORDER BY a.id
             """;
-        return await _db.Ado.SqlQueryAsync<FlowChangeRow>(sql, new { Id = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowChangeRow>(sql, new { Id = entryId, TenantId = tenantId });
     }
 
     // ── Tab3 计划排程1(MySQL:按分录 Id 关联工单排程 + 物料主档)──
-    private async Task<List<FlowScheduleRow>> QuerySchedule(long entryId)
+    private async Task<List<FlowScheduleRow>> QuerySchedule(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -269,14 +271,14 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
             FROM PeriodSequenceDet sch
             LEFT JOIN ItemMaster im ON sch.ItemNum = im.ItemNum            LEFT JOIN mes_morder mo ON mo.morder_no = sch.WorkOrds            INNER JOIN mes_moentry me ON mo.Id = me.moentry_moid
             LEFT JOIN crm_seorderentry se ON se.Id = me.soentry_id
-            WHERE se.id = @EntryId AND mo.IsDeleted = 0
+            WHERE se.id = @EntryId AND se.tenant_id = @TenantId AND mo.IsDeleted = 0
             ORDER BY sch.PlanDate
             """;
-        return await _db.Ado.SqlQueryAsync<FlowScheduleRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowScheduleRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab4 物料需求(MySQL:最新评审结果 + BOM 子件明细,同需求明细核验口径)──
-    private async Task<List<FlowMaterialRow>> QueryMaterials(long entryId)
+    private async Task<List<FlowMaterialRow>> QueryMaterials(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -316,19 +318,19 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
             LEFT JOIN b_examine_result ber ON ber.Id = (
                 SELECT br.Id
                 FROM b_examine_result br
-                WHERE br.sorderid = se.id AND br.sentry_id = sen.id
+                WHERE br.sorderid = se.id AND br.sentry_id = sen.id AND br.tenant_id = @TenantId
                 ORDER BY br.create_time DESC
                 LIMIT 1
             )
             INNER JOIN b_bom_child_examine bce ON ber.Id = bce.examine_id AND bce.is_use = 1
-            WHERE sen.id = @EntryId
+            WHERE sen.id = @EntryId AND sen.tenant_id = @TenantId
             ORDER BY bce.id ASC
             """;
-        return await _db.Ado.SqlQueryAsync<FlowMaterialRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowMaterialRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab5 采购订单(MySQL:经占用/工单关联到订单分录)──
-    private async Task<List<FlowPoRow>> QueryPo(long entryId)
+    private async Task<List<FlowPoRow>> QueryPo(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -361,15 +363,15 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
                 LEFT JOIN srm_po_occupy occ ON pl.Id = occ.polist_id AND CAST(pm.factory_id AS CHAR(64)) = CAST(occ.factory_id AS CHAR(64))                LEFT JOIN mes_morder mo ON mo.id = occ.morder_id
                 LEFT JOIN mes_moentry me ON mo.id = me.moentry_moid
                 LEFT JOIN crm_seorderentry se ON me.soentry_id = se.id
-                WHERE se.id = @EntryId AND pm.IsDeleted = 0
+                WHERE se.id = @EntryId AND se.tenant_id = @TenantId AND pm.IsDeleted = 0
             ) AS t
             ORDER BY t.PoBillNo
             """;
-        return await _db.Ado.SqlQueryAsync<FlowPoRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowPoRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab5 采购申请(MySQL)──
-    private async Task<List<FlowPrRow>> QueryPr(long entryId)
+    private async Task<List<FlowPrRow>> QueryPr(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -390,14 +392,14 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
             LEFT JOIN mes_morder mo ON mo.id = occ.morder_id
             LEFT JOIN mes_moentry me ON mo.id = me.moentry_moid
             LEFT JOIN crm_seorderentry se ON me.soentry_id = se.id
-            WHERE se.id = @EntryId AND pm.state <> 0 AND pm.IsDeleted = 0
+            WHERE se.id = @EntryId AND se.tenant_id = @TenantId AND pm.state <> 0 AND pm.IsDeleted = 0
             ORDER BY pm.pr_billno
             """;
-        return await _db.Ado.SqlQueryAsync<FlowPrRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowPrRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab5 物料交货单(MySQL:srm_polist_ds)──
-    private async Task<List<FlowDeliveryScheduleRow>> QueryDeliverySchedule(long entryId)
+    private async Task<List<FlowDeliveryScheduleRow>> QueryDeliverySchedule(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -431,15 +433,15 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
                 LEFT JOIN srm_po_occupy occ ON pl.Id = occ.polist_id AND CAST(pm.factory_id AS CHAR(64)) = CAST(occ.factory_id AS CHAR(64))                LEFT JOIN mes_morder mo ON mo.id = occ.morder_id
                 LEFT JOIN mes_moentry me ON mo.id = me.moentry_moid
                 LEFT JOIN crm_seorderentry se ON me.soentry_id = se.id
-                LEFT JOIN srm_polist_ds ds ON pl.po_billno = ds.ponumber AND pl.ItemNum = ds.itemnum                LEFT JOIN ItemMaster im ON ds.itemnum = im.ItemNum                WHERE se.id = @EntryId AND pm.IsDeleted = 0
+                LEFT JOIN srm_polist_ds ds ON pl.po_billno = ds.ponumber AND pl.ItemNum = ds.itemnum                LEFT JOIN ItemMaster im ON ds.itemnum = im.ItemNum                WHERE se.id = @EntryId AND se.tenant_id = @TenantId AND pm.IsDeleted = 0
             ) AS t
             ORDER BY t.DsNum
             """;
-        return await _db.Ado.SqlQueryAsync<FlowDeliveryScheduleRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowDeliveryScheduleRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab6 生产备料(MySQL:备料明细经工单关联分录)──
-    private async Task<List<FlowNbrRow>> QueryNbr(long entryId)
+    private async Task<List<FlowNbrRow>> QueryNbr(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -459,14 +461,14 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
                 nd.WorkOrd AS WorkOrd
             FROM NbrDetail nd
             LEFT JOIN NbrMaster nm ON nd.nbr = nm.nbr            LEFT JOIN mes_morder mo ON mo.morder_no = nm.WorkOrd            INNER JOIN mes_moentry me ON mo.Id = me.moentry_moid
-            LEFT JOIN crm_seorderentry se ON se.Id = me.soentry_id AND mo.product_code = se.item_number            LEFT JOIN ItemMaster im ON nd.ItemNum = im.ItemNum            WHERE se.id = @EntryId AND mo.IsDeleted = 0 AND nm.Type = 'SM'
+            LEFT JOIN crm_seorderentry se ON se.Id = me.soentry_id AND mo.product_code = se.item_number            LEFT JOIN ItemMaster im ON nd.ItemNum = im.ItemNum            WHERE se.id = @EntryId AND se.tenant_id = @TenantId AND mo.IsDeleted = 0 AND nm.Type = 'SM'
             ORDER BY nm.Nbr
             """;
-        return await _db.Ado.SqlQueryAsync<FlowNbrRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowNbrRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab7 生产报工(OpTransEmployee + 销售订单行)──
-    private async Task<List<FlowProdReportRow>> QueryProdReport(long entryId)
+    private async Task<List<FlowProdReportRow>> QueryProdReport(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -485,14 +487,14 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
             FROM OpTransEmployee ote
             LEFT JOIN mes_morder mo ON mo.morder_no = ote.WorkOrd            INNER JOIN mes_moentry me ON mo.Id = me.moentry_moid
             LEFT JOIN crm_seorderentry se ON se.Id = me.soentry_id
-            LEFT JOIN ItemMaster im ON ote.ItemNum = im.ItemNum            WHERE se.id = @EntryId AND mo.IsDeleted = 0
+            LEFT JOIN ItemMaster im ON ote.ItemNum = im.ItemNum            WHERE se.id = @EntryId AND se.tenant_id = @TenantId AND mo.IsDeleted = 0
             ORDER BY ote.ProdDate DESC
             """;
-        return await _db.Ado.SqlQueryAsync<FlowProdReportRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowProdReportRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab7 IQC信息(请购/采购/检验链路)──
-    private async Task<List<FlowIqcRow>> QueryIqc(long entryId)
+    private async Task<List<FlowIqcRow>> QueryIqc(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -526,13 +528,14 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
             ) iqcjy ON pod.PurOrd = iqcjy.po_bill AND CAST(pod.Line AS CHAR(32)) = CAST(iqcjy.po_billline AS CHAR(32))            WHERE jq.flag = '1'
               AND pr.sentry_id IS NOT NULL
               AND pr.sentry_id = @EntryId
+              AND pr.tenant_id = @TenantId
             ORDER BY iqcjy.FAPPLYTIME DESC
             """;
-        return await _db.Ado.SqlQueryAsync<FlowIqcRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowIqcRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab8 FQC信息 ──
-    private async Task<List<FlowFqcRow>> QueryFqc(long entryId)
+    private async Task<List<FlowFqcRow>> QueryFqc(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -547,14 +550,14 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
                 CAST(a.FRINSQTY AS DECIMAL(18,2)) AS FRinsQty,
                 a.FINSPEENDDATE AS FInspeEndDate
             FROM qms_qcpp_inspbill a
-            LEFT JOIN WorkOrdMaster b ON a.sczld = b.Batch            LEFT JOIN mes_moentry c ON b.WorkOrd = c.moentry_mono            WHERE c.soentry_id = @EntryId
+            LEFT JOIN WorkOrdMaster b ON a.sczld = b.Batch            LEFT JOIN mes_moentry c ON b.WorkOrd = c.moentry_mono            WHERE c.soentry_id = @EntryId AND c.TenantId = @TenantId
             ORDER BY a.FBILLNO
             """;
-        return await _db.Ado.SqlQueryAsync<FlowFqcRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowFqcRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab8 生产入库 ──
-    private async Task<List<FlowReceiptRow>> QueryReceipt(long entryId)
+    private async Task<List<FlowReceiptRow>> QueryReceipt(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -587,14 +590,14 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
                 GROUP BY WorkOrds
             ) compp ON c.WorkOrd = compp.WorkOrds            LEFT JOIN mes_morder mo ON mo.morder_no = c.WorkOrd AND mo.IsDeleted = 0
             LEFT JOIN mes_moentry motry ON motry.moentry_moid = mo.Id AND motry.IsDeleted = 0
-            WHERE motry.soentry_id = @EntryId
+            WHERE motry.soentry_id = @EntryId AND motry.TenantId = @TenantId
             ORDER BY mo.morder_no
             """;
-        return await _db.Ado.SqlQueryAsync<FlowReceiptRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowReceiptRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 
     // ── Tab8 成品发运(与订单行 OrdNbr + 行物料一致)──
-    private async Task<List<FlowShipmentRow>> QueryShipment(long entryId)
+    private async Task<List<FlowShipmentRow>> QueryShipment(long entryId, long tenantId)
     {
         const string sql = """
             SELECT
@@ -610,8 +613,9 @@ public class OrderDeliveryService : IDynamicApiController, ITransient
             LEFT JOIN LocationMaster lm ON ad.location = lm.Location            INNER JOIN crm_seorderentry se ON se.id = @EntryId
                 AND ad.ContainerItem = se.item_number            INNER JOIN crm_seorder so ON so.Id = se.seorder_id AND ad.OrdNbr = so.bill_no            WHERE am.shtype = 'SH'
               AND am.typed <> 'S'
+              AND am.tenant_id = @TenantId
             ORDER BY ad.Id
             """;
-        return await _db.Ado.SqlQueryAsync<FlowShipmentRow>(sql, new { EntryId = entryId });
+        return await _db.Ado.SqlQueryAsync<FlowShipmentRow>(sql, new { EntryId = entryId, TenantId = tenantId });
     }
 }

+ 14 - 8
server/Plugins/Admin.NET.Plugin.AiDOP/Order/ProductDesignService.cs

@@ -37,7 +37,9 @@ public class ProductDesignService : IDynamicApiController, ITransient
     [HttpGet("productdesign/list")]
     public async Task<object> GetProductDesignList([FromQuery] ProductDesignListInput input)
     {
+        var tenantId = _userManager.TenantId;
         var q = _db.Queryable<ProductDesign>()
+            .Where(u => u.TenantId == tenantId)
             .WhereIF(!string.IsNullOrWhiteSpace(input.BillNo), u => u.BillNo.Contains(input.BillNo!.Trim()))
             .WhereIF(!string.IsNullOrWhiteSpace(input.ContractNo), u => u.ContractNo != null && u.ContractNo.Contains(input.ContractNo!.Trim()))
             .WhereIF(input.ProductKind is 1 or 2, u => u.ProductKind == input.ProductKind!.Value)
@@ -75,11 +77,12 @@ public class ProductDesignService : IDynamicApiController, ITransient
     [HttpGet("productdesign/{id:long}")]
     public async Task<object> GetProductDesignDetail(long id)
     {
-        var m = await _designRep.GetFirstAsync(u => u.Id == id)
+        var tenantId = _userManager.TenantId;
+        var m = await _designRep.GetFirstAsync(u => u.Id == id && u.TenantId == tenantId)
                 ?? throw Oops.Oh("产品设计记录不存在");
 
-        var boms = await _bomRep.GetListAsync(u => u.ProductDesignId == id);
-        var routings = await _routingRep.GetListAsync(u => u.ProductDesignId == id);
+        var boms = await _bomRep.GetListAsync(u => u.ProductDesignId == id && u.TenantId == tenantId);
+        var routings = await _routingRep.GetListAsync(u => u.ProductDesignId == id && u.TenantId == tenantId);
 
         return new
         {
@@ -139,6 +142,7 @@ public class ProductDesignService : IDynamicApiController, ITransient
 
         var now = DateTime.Now;
         var user = _userManager.Account ?? "system";
+        var tenantId = _userManager.TenantId;
 
         await _db.Ado.BeginTranAsync();
         try
@@ -148,7 +152,8 @@ public class ProductDesignService : IDynamicApiController, ITransient
             {
                 var month = now.ToString("yyyyMM");
                 var maxSeq = await _db.Ado.GetIntAsync(
-                    $"SELECT IFNULL(MAX(CAST(SUBSTRING(BillNo, 9) AS UNSIGNED)), 0) FROM ado_product_design WHERE BillNo LIKE 'PD{month}%'");
+                    $"SELECT IFNULL(MAX(CAST(SUBSTRING(BillNo, 9) AS UNSIGNED)), 0) FROM ado_product_design WHERE BillNo LIKE 'PD{month}%' AND tenant_id = @TenantId",
+                    new SugarParameter("@TenantId", tenantId));
                 var billNo = $"PD{month}{(maxSeq + 1):D4}";
 
                 designId = YitIdHelper.NextId();
@@ -162,7 +167,7 @@ public class ProductDesignService : IDynamicApiController, ITransient
                 return new { id = designId, billNo, message = "新增成功" };
             }
 
-            var existing = await _designRep.GetFirstAsync(u => u.Id == input.Id!.Value)
+            var existing = await _designRep.GetFirstAsync(u => u.Id == input.Id!.Value && u.TenantId == tenantId)
                            ?? throw Oops.Oh("产品设计记录不存在");
 
             designId = existing.Id;
@@ -186,7 +191,8 @@ public class ProductDesignService : IDynamicApiController, ITransient
     [ApiDescriptionSettings(Name = "DeleteProductDesign"), HttpPost("productdesign/delete")]
     public async Task<object> DeleteProductDesign([FromBody] ProductDesignDeleteInput input)
     {
-        var entity = await _designRep.GetFirstAsync(u => u.Id == input.Id)
+        var tenantId = _userManager.TenantId;
+        var entity = await _designRep.GetFirstAsync(u => u.Id == input.Id && u.TenantId == tenantId)
                      ?? throw Oops.Oh("产品设计记录不存在");
 
         await _db.Ado.BeginTranAsync();
@@ -298,7 +304,7 @@ FROM RoutingOpDetail WHERE RoutingCode=@itemNum";
     private async Task SaveBomsAsync(long designId, List<ProductDesignBomInput> items, bool isNew)
     {
         var dbRows = isNew ? new List<ProductDesignBom>()
-            : await _bomRep.GetListAsync(u => u.ProductDesignId == designId);
+            : await _bomRep.GetListAsync(u => u.ProductDesignId == designId && u.TenantId == _userManager.TenantId);
         var dbById = dbRows.ToDictionary(u => u.Id);
 
         if (items.Any(x => !x.Id.HasValue))
@@ -406,7 +412,7 @@ FROM RoutingOpDetail WHERE RoutingCode=@itemNum";
     private async Task SaveRoutingsAsync(long designId, List<ProductDesignRoutingInput> items, bool isNew)
     {
         var dbRows = isNew ? new List<ProductDesignRouting>()
-            : await _routingRep.GetListAsync(u => u.ProductDesignId == designId);
+            : await _routingRep.GetListAsync(u => u.ProductDesignId == designId && u.TenantId == _userManager.TenantId);
         var dbById = dbRows.ToDictionary(u => u.Id);
         var inputIds = new HashSet<long>(items.Where(d => d.Id is > 0).Select(d => d.Id!.Value));
 

+ 6 - 3
server/Plugins/Admin.NET.Plugin.AiDOP/Order/RequirementExamineDetailService.cs

@@ -11,10 +11,12 @@ namespace Admin.NET.Plugin.AiDOP.Order;
 public class RequirementExamineDetailService : IDynamicApiController, ITransient
 {
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public RequirementExamineDetailService(ISqlSugarClient db)
+    public RequirementExamineDetailService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     /// <summary>
@@ -24,8 +26,9 @@ public class RequirementExamineDetailService : IDynamicApiController, ITransient
     [HttpGet("examine-detail/list")]
     public async Task<object> PageRequirementExamineDetail([FromQuery] RequirementExamineDetailListInput input)
     {
-        var pars = new List<SugarParameter>();
-        var where = new List<string> { "bce.is_use = 1" };
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = new List<string> { "bce.is_use = 1", "ber.tenant_id = @TenantId" };
 
         if (!string.IsNullOrWhiteSpace(input.BillNo))
         {

+ 14 - 7
server/Plugins/Admin.NET.Plugin.AiDOP/Order/S1MdpMonitorService.cs

@@ -11,19 +11,23 @@ public class S1MdpMonitorService : IDynamicApiController, ITransient
 {
     private const string JobCode = "S1_MDP_SYNC_TRANSFORM";
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public S1MdpMonitorService(ISqlSugarClient db)
+    public S1MdpMonitorService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     [DisplayName("S1 MDP最近运行状态")]
     [HttpGet("s1-mdp-monitor/latest")]
     public async Task<object> GetLatest()
     {
+        var tenantId = _userManager.TenantId;
         return await _db.Ado.SqlQuerySingleAsync<S1MdpRunLogRow>(
-            $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE job_code=@JobCode ORDER BY start_time DESC, id DESC LIMIT 1",
-            new SugarParameter("@JobCode", JobCode))
+            $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE job_code=@JobCode AND tenant_id=@TenantId ORDER BY start_time DESC, id DESC LIMIT 1",
+            new SugarParameter("@JobCode", JobCode),
+            new SugarParameter("@TenantId", tenantId))
             ?? new S1MdpRunLogRow();
     }
 
@@ -31,11 +35,12 @@ public class S1MdpMonitorService : IDynamicApiController, ITransient
     [HttpGet("s1-mdp-monitor/list")]
     public async Task<object> GetList([FromQuery] S1MdpMonitorListInput input)
     {
+        var tenantId = _userManager.TenantId;
         var page = input.Page <= 0 ? 1 : input.Page;
         var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
         var offset = (page - 1) * pageSize;
-        var where = new List<string> { "job_code=@JobCode" };
-        var pars = new List<SugarParameter> { new("@JobCode", JobCode) };
+        var where = new List<string> { "job_code=@JobCode", "tenant_id=@TenantId" };
+        var pars = new List<SugarParameter> { new("@JobCode", JobCode), new("@TenantId", tenantId) };
 
         if (!string.IsNullOrWhiteSpace(input.BatchId))
         {
@@ -77,10 +82,12 @@ public class S1MdpMonitorService : IDynamicApiController, ITransient
     [HttpGet("s1-mdp-monitor/detail/{id}")]
     public async Task<object> GetDetail(long id)
     {
+        var tenantId = _userManager.TenantId;
         var row = await _db.Ado.SqlQuerySingleAsync<S1MdpRunLogRow>(
-            $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE id=@Id AND job_code=@JobCode LIMIT 1",
+            $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE id=@Id AND job_code=@JobCode AND tenant_id=@TenantId LIMIT 1",
             new SugarParameter("@Id", id),
-            new SugarParameter("@JobCode", JobCode));
+            new SugarParameter("@JobCode", JobCode),
+            new SugarParameter("@TenantId", tenantId));
         return row ?? throw Oops.Oh("运行日志不存在");
     }
 

+ 9 - 6
server/Plugins/Admin.NET.Plugin.AiDOP/Order/ShippingPlanService.cs

@@ -41,8 +41,9 @@ public class ShippingPlanService : IDynamicApiController, ITransient
     [HttpGet("shippingplan/list")]
     public async Task<object> GetShippingPlanList([FromQuery] ShippingPlanListInput input)
     {
-        var pars = new List<SugarParameter>();
-        var conditions = new List<string>();
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var conditions = new List<string> { "a.tenant_id = @TenantId" };
 
         if (!string.IsNullOrWhiteSpace(input.OrdNbr))
         {
@@ -129,10 +130,11 @@ public class ShippingPlanService : IDynamicApiController, ITransient
     [HttpGet("shippingplan/{id}")]
     public async Task<object> GetShippingPlanDetail(int id)
     {
-        var plan = await _planRep.GetFirstAsync(u => u.RecID == id)
+        var tenantId = _userManager.TenantId;
+        var plan = await _planRep.GetFirstAsync(u => u.RecID == id && u.TenantId == tenantId)
                    ?? throw Oops.Oh("出货计划不存在");
 
-        var details = await _detailRep.GetListAsync(u => u.PlanId == id);
+        var details = await _detailRep.GetListAsync(u => u.PlanId == id && u.TenantId == tenantId);
 
         return new
         {
@@ -204,7 +206,8 @@ public class ShippingPlanService : IDynamicApiController, ITransient
         else
         {
             // ── 编辑:参照 SysJobService.UpdateJobDetail ──
-            var entity = await _planRep.GetFirstAsync(u => u.RecID == input.RecID.Value)
+            var tenantId = _userManager.TenantId;
+            var entity = await _planRep.GetFirstAsync(u => u.RecID == input.RecID.Value && u.TenantId == tenantId)
                          ?? throw Oops.Oh("出货计划不存在");
 
             entity.LotSerial = input.LotSerial;
@@ -233,7 +236,7 @@ public class ShippingPlanService : IDynamicApiController, ITransient
         string user, DateTime now, bool isNew)
     {
         var dbDetails = isNew ? new List<ShippingPlanDetail>()
-            : await _detailRep.GetListAsync(u => u.PlanId == planId);
+            : await _detailRep.GetListAsync(u => u.PlanId == planId && u.TenantId == _userManager.TenantId);
         var dbById = dbDetails.ToDictionary(u => u.RecID);
         var inputIds = new HashSet<int>(details.Where(d => d.RecID is > 0).Select(d => d.RecID!.Value));
 

+ 6 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/PurOrdRctDetail.cs

@@ -179,4 +179,10 @@ public class PurOrdRctDetail
 
     [SugarColumn(ColumnName = "ERPfld2", Length = 200, IsNullable = true)]
     public string ERPfld2 { get; set; }
+
+    /// <summary>
+    /// 租户Id
+    /// </summary>
+    [SugarColumn(ColumnName = "tenant_id", ColumnDescription = "租户Id")]
+    public long? TenantId { get; set; }
 }

+ 6 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/PurOrdRctMaster.cs

@@ -125,4 +125,10 @@ public class PurOrdRctMaster
 
     [SugarColumn(ColumnName = "ERPfld1", Length = 200, IsNullable = true)]
     public string ERPfld1 { get; set; }
+
+    /// <summary>
+    /// 租户Id
+    /// </summary>
+    [SugarColumn(ColumnName = "tenant_id", ColumnDescription = "租户Id")]
+    public long? TenantId { get; set; }
 }

+ 6 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/ScmJhjhJq.cs

@@ -86,5 +86,11 @@ public class ScmJhjhJq
 
     [SugarColumn(ColumnName = "glid1", IsNullable = true, Length = 50)]
     public string? Glid1 { get; set; }
+
+    /// <summary>
+    /// 租户Id
+    /// </summary>
+    [SugarColumn(ColumnName = "tenant_id", ColumnDescription = "租户Id")]
+    public long? TenantId { get; set; }
 }
 

+ 6 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/ScmShd.cs

@@ -89,5 +89,11 @@ public class ScmShd
 
     [SugarColumn(ColumnName = "dycs", IsNullable = true)]
     public int? Dycs { get; set; }
+
+    /// <summary>
+    /// 租户Id
+    /// </summary>
+    [SugarColumn(ColumnName = "tenant_id", ColumnDescription = "租户Id")]
+    public long? TenantId { get; set; }
 }
 

+ 6 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/Entity/ScmShdzb.cs

@@ -92,5 +92,11 @@ public class ScmShdzb
 
     [SugarColumn(ColumnName = "po_billno", IsNullable = true, Length = 255)]
     public string? PoBillNo { get; set; }
+
+    /// <summary>
+    /// 租户Id
+    /// </summary>
+    [SugarColumn(ColumnName = "tenant_id", ColumnDescription = "租户Id")]
+    public long? TenantId { get; set; }
 }
 

+ 5 - 3
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/IqcReturnQueryService.cs

@@ -13,8 +13,9 @@ namespace Admin.NET.Plugin.AiDOP.ProcurementExecution;
 public class IqcReturnQueryService : IDynamicApiController, ITransient
 {
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public IqcReturnQueryService(ISqlSugarClient db) => _db = db;
+    public IqcReturnQueryService(ISqlSugarClient db, UserManager userManager) { _db = db; _userManager = userManager; }
 
     /// <summary>
     /// 退货相关处理方式:NULL 视作 0;与 aidopdev 中 clfs 枚举一致时可再收紧为仅 clfs=3。
@@ -56,8 +57,9 @@ public class IqcReturnQueryService : IDynamicApiController, ITransient
         var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
         var offset = (page - 1) * pageSize;
 
-        var cond = new List<string> { ReturnClfsPredicate };
-        var pars = new List<SugarParameter>();
+        var tenantId = _userManager.TenantId;
+        var cond = new List<string> { ReturnClfsPredicate, "c.tenant_id = @TenantId" };
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
 
         if (!string.IsNullOrWhiteSpace(input.OrdNbr))
         {

+ 49 - 22
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/PurchaseReturnService.cs

@@ -61,8 +61,9 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
         var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
         var offset = (page - 1) * pageSize;
 
-        var cond = new List<string> { "p.RctType='pt'", "p.IsActive=1" };
-        var pars = new List<SugarParameter>();
+        var tenantId = _userManager.TenantId;
+        var cond = new List<string> { "p.RctType='pt'", "p.IsActive=1", "p.tenant_id = @TenantId" };
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
         if (!string.IsNullOrWhiteSpace(input.Receiver))
         {
             cond.Add("p.Receiver LIKE @Receiver");
@@ -128,13 +129,16 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
     [HttpGet("purchase-return/options/suppliers")]
     public async Task<object> GetSuppliers()
     {
+        var tenantId = _userManager.TenantId;
         var rows = await _db.Ado.SqlQueryAsync<PurchaseReturnKvItem>(
             """
             SELECT Supp AS `Value`,
                    TRIM(CONCAT(TRIM(IFNULL(Supp,'')),' ',TRIM(IFNULL(SortName,'')))) AS `Label`
             FROM SuppMaster
+            WHERE tenant_id = @TenantId
             ORDER BY Supp
-            """);
+            """,
+            new SugarParameter("@TenantId", tenantId));
         return rows;
     }
 
@@ -144,6 +148,7 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
     {
         if (string.IsNullOrWhiteSpace(supp))
             return Array.Empty<object>();
+        var tenantId = _userManager.TenantId;
         var rows = await _db.Ado.SqlQueryAsync<PurchaseReturnKvItem>(
             """
             SELECT p.Receiver AS `Value`,
@@ -156,10 +161,12 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
               ON p.RctType = d.RctType AND p.Receiver = d.Receiver
             LEFT JOIN ItemMaster i ON d.ItemNum = i.ItemNum
             WHERE p.RctType = 'rc' AND p.Supp = @Supp AND d.RecID > 0 AND IFNULL(p.TermsofTrade,'') <> ''
+              AND p.tenant_id = @TenantId
             GROUP BY p.Receiver, d.LotSerial, d.ItemNum, i.Descr, p.Domain
             ORDER BY p.Receiver DESC
             """,
-            new SugarParameter("@Supp", supp.Trim()));
+            new SugarParameter("@Supp", supp.Trim()),
+            new SugarParameter("@TenantId", tenantId));
         return rows;
     }
 
@@ -169,6 +176,7 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
     {
         if (string.IsNullOrWhiteSpace(receiver))
             throw Oops.Oh("请先选择收货单号");
+        var tenantId = _userManager.TenantId;
         var rows = await _db.Ado.SqlQueryAsync<PurchaseReturnRcLineRow>(
             """
             SELECT
@@ -204,9 +212,11 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
             LEFT JOIN PurOrdRctDetail d
               ON p.RctType = d.RctType AND p.Receiver = d.Receiver
             WHERE p.RctType = 'rc' AND p.Receiver = @Receiver AND d.RecID > 0
+              AND p.tenant_id = @TenantId
             ORDER BY d.Line
             """,
-            new SugarParameter("@Receiver", receiver.Trim()));
+            new SugarParameter("@Receiver", receiver.Trim()),
+            new SugarParameter("@TenantId", tenantId));
 
         PurchaseReturnRcLineRow head = null;
         if (rows.Count > 0)
@@ -218,33 +228,39 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
     [HttpGet("purchase-return/options/departments")]
     public async Task<object> GetDepartments()
     {
+        var tenantId = _userManager.TenantId;
         return await _db.Ado.SqlQueryAsync<PurchaseReturnKvItem>(
             """
             SELECT Department AS `Value`,
                    TRIM(CONCAT(TRIM(IFNULL(Department,'')),' ',TRIM(IFNULL(Descr,'')))) AS `Label`
             FROM DepartmentMaster
+            WHERE tenant_id = @TenantId
             ORDER BY Department
-            """);
+            """,
+            new SugarParameter("@TenantId", tenantId));
     }
 
     [DisplayName("库位下拉")]
     [HttpGet("purchase-return/options/locations")]
     public async Task<object> GetLocations()
     {
+        var tenantId = _userManager.TenantId;
         return await _db.Ado.SqlQueryAsync<PurchaseReturnKvItem>(
             """
             SELECT Location AS `Value`,
                    TRIM(CONCAT(TRIM(IFNULL(Location,'')),' ',TRIM(IFNULL(Descr,'')))) AS `Label`
             FROM LocationMaster
-            WHERE IFNULL(Typed,'') <> 'Supp'
+            WHERE IFNULL(Typed,'') <> 'Supp' AND tenant_id = @TenantId
             ORDER BY Location
-            """);
+            """,
+            new SugarParameter("@TenantId", tenantId));
     }
 
     [DisplayName("退货原因下拉")]
     [HttpGet("purchase-return/options/qc-reasons")]
     public async Task<object> GetQcReasons()
     {
+        var tenantId = _userManager.TenantId;
         return await _db.Ado.SqlQueryAsync<PurchaseReturnKvItem>(
             """
             SELECT Val AS `Value`,
@@ -253,8 +269,10 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
             WHERE FldName = 'SAPTransReason'
               AND IFNULL(Ufld1,'') <> ''
               AND LOCATE('122', IFNULL(Ufld1,'')) > 0
+              AND tenant_id = @TenantId
             ORDER BY Val
-            """);
+            """,
+            new SugarParameter("@TenantId", tenantId));
     }
 
     [DisplayName("物料选择分页")]
@@ -264,8 +282,9 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
         var page = input.Page <= 0 ? 1 : input.Page;
         var pageSize = input.PageSize <= 0 ? 20 : input.PageSize;
         var offset = (page - 1) * pageSize;
-        var pars = new List<SugarParameter>();
-        var where = "1=1";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "1=1 AND tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(input.Keyword))
         {
             where += " AND (ItemNum LIKE @Kw OR Descr LIKE @Kw OR Descr1 LIKE @Kw)";
@@ -290,7 +309,8 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
     [HttpGet("purchase-return/{id:int}")]
     public async Task<object> GetDetail(int id)
     {
-        var master = await _masterRep.GetFirstAsync(m => m.RecID == id && m.RctType == "pt")
+        var tenantId = _userManager.TenantId;
+        var master = await _masterRep.GetFirstAsync(m => m.RecID == id && m.RctType == "pt" && m.TenantId == tenantId)
                      ?? throw Oops.Oh("单据不存在");
 
         var m = await _db.Ado.SqlQueryAsync<PurchaseReturnMasterDto>(
@@ -311,14 +331,15 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
               IFNULL(m.Remark,'') AS Remark,
               IFNULL(m.IsPlan, 0) AS IsPlan
             FROM PurOrdRctMaster m
-            WHERE m.RecID = @Id
+            WHERE m.RecID = @Id AND m.tenant_id = @TenantId
             LIMIT 1
             """,
-            new SugarParameter("@Id", id));
+            new SugarParameter("@Id", id),
+            new SugarParameter("@TenantId", tenantId));
         var head = m.FirstOrDefault() ?? throw Oops.Oh("单据不存在");
 
         var detailRows = await _db.Queryable<PurOrdRctDetail>()
-            .Where(d => d.PurOrdRctRecID == id && d.RctType == "pt" && d.IsActive)
+            .Where(d => d.PurOrdRctRecID == id && d.RctType == "pt" && d.IsActive && d.TenantId == tenantId)
             .OrderBy(d => d.Line)
             .ToListAsync();
 
@@ -375,6 +396,7 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
 
         var now = DateTime.Now;
         var account = _userManager.Account ?? "system";
+        var tenantId = _userManager.TenantId;
 
         var domain = string.IsNullOrWhiteSpace(input.Domain)
             ? await ResolveRcDomainAsync(input.OrdNbr.Trim())
@@ -431,7 +453,7 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
             }
         }
 
-        var existing = await _masterRep.GetFirstAsync(m => m.RecID == input.Id!.Value && m.RctType == "pt")
+        var existing = await _masterRep.GetFirstAsync(m => m.RecID == input.Id!.Value && m.RctType == "pt" && m.TenantId == tenantId)
                        ?? throw Oops.Oh("单据不存在");
         if (!existing.IsPlan)
             throw Oops.Oh("该单据不允许修改");
@@ -466,8 +488,9 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
         string account,
         DateTime now)
     {
+        var tenantId = _userManager.TenantId;
         var dbRows = await _detailRep.GetListAsync(d =>
-            d.PurOrdRctRecID == masterRecId && d.RctType == rctType);
+            d.PurOrdRctRecID == masterRecId && d.RctType == rctType && d.TenantId == tenantId);
         var dbById = dbRows.ToDictionary(d => d.RecID);
         var inputIds = new HashSet<int>(entries.Where(e => e.RecID is > 0).Select(e => e.RecID!.Value));
 
@@ -555,7 +578,8 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
     [HttpPost("purchase-return/delete/{id:int}")]
     public async Task<object> SoftDelete(int id)
     {
-        var m = await _masterRep.GetFirstAsync(x => x.RecID == id && x.RctType == "pt")
+        var tenantId = _userManager.TenantId;
+        var m = await _masterRep.GetFirstAsync(x => x.RecID == id && x.RctType == "pt" && x.TenantId == tenantId)
                 ?? throw Oops.Oh("单据不存在");
         if (!m.IsPlan)
             throw Oops.Oh("该单据不允许删除");
@@ -566,19 +590,22 @@ public class PurchaseReturnService : IDynamicApiController, ITransient
         await _masterRep.UpdateAsync(m);
 
         await _db.Ado.ExecuteCommandAsync(
-            "UPDATE PurOrdRctDetail SET IsActive=0, UpdateUser=@U, UpdateTime=@T WHERE PurOrdRctRecID=@Id AND RctType='pt'",
+            "UPDATE PurOrdRctDetail SET IsActive=0, UpdateUser=@U, UpdateTime=@T WHERE PurOrdRctRecID=@Id AND RctType='pt' AND tenant_id=@TenantId",
             new SugarParameter("@U", m.UpdateUser),
             new SugarParameter("@T", m.UpdateTime),
-            new SugarParameter("@Id", id));
+            new SugarParameter("@Id", id),
+            new SugarParameter("@TenantId", tenantId));
 
         return new { message = "已删除" };
     }
 
     private async Task<string> ResolveRcDomainAsync(string rcReceiver)
     {
+        var tenantId = _userManager.TenantId;
         var d = await _db.Ado.GetStringAsync(
-            "SELECT Domain FROM PurOrdRctMaster WHERE RctType='rc' AND Receiver=@R LIMIT 1",
-            new SugarParameter("@R", rcReceiver));
+            "SELECT Domain FROM PurOrdRctMaster WHERE RctType='rc' AND Receiver=@R AND tenant_id=@TenantId LIMIT 1",
+            new SugarParameter("@R", rcReceiver),
+            new SugarParameter("@TenantId", tenantId));
         return d;
     }
 

+ 18 - 6
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/SupplierDeliveryManagementService.cs

@@ -24,7 +24,8 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
     [HttpGet("supplier-delivery/list")]
     public async Task<object> GetList([FromQuery] SupplierDeliveryListInput input)
     {
-        var pars = new List<SugarParameter>();
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
         var conditions = new List<string>();
         if (!string.IsNullOrWhiteSpace(input.Cgdd))
         {
@@ -63,6 +64,7 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
     [HttpPost("supplier-delivery/publish")]
     public async Task<object> Publish([FromBody] SupplierDeliveryBatchInput input)
     {
+        var tenantId = _userManager.TenantId;
         var userId = _userManager.UserId.ToString();
         var userName = _userManager.Account ?? "system";
         var sql = """
@@ -111,6 +113,7 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
               ON a.cgdd = ds.ponumber
              AND a.ddhh = ds.poline
             WHERE FIND_IN_SET(CAST(ds.id AS CHAR(50)), REPLACE(IFNULL(@ids, ''), ' ', '')) > 0
+              AND ds.tenant_id = @TenantId
               AND NOT EXISTS (
                 SELECT 1 FROM scm_jhjh_jq x
                 WHERE x.glid1 = ds.id
@@ -121,7 +124,8 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
         {
             new("@ids", input.Ids),
             new("@hfrid", userId),
-            new("@hfrxm", userName)
+            new("@hfrxm", userName),
+            new("@TenantId", tenantId)
         });
         return new { message = "发布成功" };
     }
@@ -133,6 +137,7 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
         if (string.IsNullOrWhiteSpace(input.Ids))
             throw Oops.Oh("缺少勾选行ID(ids)");
 
+        var tenantId = _userManager.TenantId;
         var userId = _userManager.UserId.ToString();
         var userName = _userManager.Account ?? "system";
 
@@ -182,7 +187,8 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
              AND a.ddhh = ds.poline
             WHERE FIND_IN_SET(CAST(ds.id AS CHAR(50)), REPLACE(IFNULL(@ids, ''), ' ', '')) > 0
               AND ds.isactive = 1
-              AND ds.status = 'P';
+              AND ds.status = 'P'
+              AND ds.tenant_id = @TenantId;
             """;
 
         var affected = await _db.Ado.ExecuteCommandAsync(sql, new List<SugarParameter>
@@ -190,6 +196,7 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
             new("@ids", input.Ids),
             new("@userid", userId),
             new("@username", userName),
+            new("@TenantId", tenantId),
         });
 
         if (affected <= 0)
@@ -207,6 +214,7 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
         if (string.IsNullOrWhiteSpace(input.Jqhf))
             throw Oops.Oh("缺少交期回复日期(jqhf)");
 
+        var tenantId = _userManager.TenantId;
         var userId = _userManager.UserId.ToString();
         var userName = _userManager.Account ?? "system";
 
@@ -258,7 +266,8 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
              AND a.ddhh = ds.poline
             WHERE FIND_IN_SET(CAST(ds.id AS CHAR(50)), REPLACE(IFNULL(@ids, ''), ' ', '')) > 0
               AND ds.isactive = 1
-              AND ds.status = 'P';
+              AND ds.status = 'P'
+              AND ds.tenant_id = @TenantId;
             """;
 
         var affected = await _db.Ado.ExecuteCommandAsync(sql, new List<SugarParameter>
@@ -267,6 +276,7 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
             new("@jqhf", input.Jqhf.Trim()),
             new("@userid", userId),
             new("@username", userName),
+            new("@TenantId", tenantId),
         });
 
         if (affected <= 0)
@@ -279,9 +289,10 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
     [HttpPost("supplier-delivery/close")]
     public async Task<object> CloseDelivery([FromBody] DeliveryCloseInput input)
     {
+        var tenantId = _userManager.TenantId;
         await _db.Ado.ExecuteCommandAsync(
-            "UPDATE srm_polist_ds SET status='C' WHERE DSNum=@jhdbh",
-            new List<SugarParameter> { new("@jhdbh", input.DsNum) });
+            "UPDATE srm_polist_ds SET status='C' WHERE DSNum=@jhdbh AND tenant_id=@TenantId",
+            new List<SugarParameter> { new("@jhdbh", input.DsNum), new("@TenantId", tenantId) });
         return new { message = "交货单关闭成功" };
     }
 
@@ -445,6 +456,7 @@ public class SupplierDeliveryManagementService : IDynamicApiController, ITransie
               AND ds.schedqty >= 0
               AND ds.isactive = 1
               AND ds.status = 'P'
+              AND p.tenant_id = @TenantId
         ) v
         """;
 

+ 35 - 16
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/SupplierShipmentService.cs

@@ -36,7 +36,8 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
     [HttpGet("supplier-shipment/list")]
     public async Task<object> GetList([FromQuery] SupplierShipmentListInput input)
     {
-        var pars = new List<SugarParameter>();
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
         var conditions = new List<string> { "IFNULL(m.state, 1) <> 0" };
         if (!string.IsNullOrWhiteSpace(input.JhshrqFrom))
         {
@@ -95,8 +96,9 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
     [HttpGet("supplier-shipment/{id:long}")]
     public async Task<object> GetDetail(long id)
     {
-        var master = await _masterRep.GetFirstAsync(x => x.Id == id) ?? throw Oops.Oh("发货单不存在");
-        var details = await _detailRep.AsQueryable().Where(x => x.Glid == id.ToString()).OrderBy(x => x.Hh).ToListAsync();
+        var tenantId = _userManager.TenantId;
+        var master = await _masterRep.GetFirstAsync(x => x.Id == id && x.TenantId == tenantId) ?? throw Oops.Oh("发货单不存在");
+        var details = await _detailRep.AsQueryable().Where(x => x.Glid == id.ToString() && x.TenantId == tenantId).OrderBy(x => x.Hh).ToListAsync();
         return new
         {
             id = master.Id,
@@ -139,7 +141,8 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
     [HttpGet("supplier-shipment/create-draft")]
     public async Task<object> GetCreateDraft([FromQuery] string ids)
     {
-        var pars = new List<SugarParameter> { new("@ids", ids) };
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@ids", ids), new("@TenantId", tenantId) };
         var rows = await _db.Ado.SqlQueryAsync<SupplierShipmentDraftRow>(
             """
             SELECT
@@ -166,6 +169,7 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
             LEFT JOIN srm_polist_ds ds ON p.PurOrd = ds.ponumber AND p.Line = ds.poline
             LEFT JOIN ItemMaster im ON p.ItemNum = im.ItemNum
             WHERE FIND_IN_SET(CAST(IFNULL(ds.id, p.RecID) AS CHAR(50)), REPLACE(IFNULL(@ids, ''), ' ', '')) > 0
+              AND p.tenant_id = @TenantId
             ORDER BY p.PurOrd, p.Line
             """, pars);
 
@@ -213,6 +217,7 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
     public async Task<object> Save([FromBody] SupplierShipmentSaveInput input)
     {
         var now = DateTime.Now;
+        var tenantId = _userManager.TenantId;
         var userId = _userManager.UserId.ToString();
         var userName = _userManager.Account ?? "system";
         var shipDate = string.IsNullOrWhiteSpace(input.Jhshrq) ? now.ToString("yyyy-MM-dd") : input.Jhshrq!.Trim();
@@ -245,7 +250,7 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
             return new { id = newId, message = "新增成功", shddh = entity.Shddh };
         }
 
-        var master = await _masterRep.GetFirstAsync(x => x.Id == input.Id.Value) ?? throw Oops.Oh("发货单不存在");
+        var master = await _masterRep.GetFirstAsync(x => x.Id == input.Id.Value && x.TenantId == tenantId) ?? throw Oops.Oh("发货单不存在");
         master.Jhshrq = shipDate;
         master.Wlsc = input.Wlsc;
         master.Yjdhrq = input.Yjdhrq;
@@ -264,7 +269,8 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
     [ApiDescriptionSettings(Name = "DeleteSupplierShipment"), HttpPost("supplier-shipment/delete")]
     public async Task<object> Delete([FromBody] SupplierShipmentDeleteInput input)
     {
-        var master = await _masterRep.GetFirstAsync(x => x.Id == input.Id) ?? throw Oops.Oh("发货单不存在");
+        var tenantId = _userManager.TenantId;
+        var master = await _masterRep.GetFirstAsync(x => x.Id == input.Id && x.TenantId == tenantId) ?? throw Oops.Oh("发货单不存在");
         master.State = 0;
         await _masterRep.UpdateAsync(master);
         return new { message = "删除成功" };
@@ -277,9 +283,10 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
         if (input.Id <= 0)
             throw Oops.Oh("缺少发货单ID(id)");
 
+        var tenantId = _userManager.TenantId;
         var userName = _userManager.Account ?? "system";
 
-        var master = await _masterRep.GetFirstAsync(x => x.Id == input.Id) ?? throw Oops.Oh("发货单不存在");
+        var master = await _masterRep.GetFirstAsync(x => x.Id == input.Id && x.TenantId == tenantId) ?? throw Oops.Oh("发货单不存在");
         if (string.IsNullOrWhiteSpace(master.Shddh))
             throw Oops.Oh("发货单缺少发货单编号(shddh)");
 
@@ -289,7 +296,8 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
 
         // Domain(工厂编码)
         var domain = await _db.Ado.GetStringAsync(
-            "SELECT Domain FROM GeneralizedCodeMaster WHERE FldName='SystemConfig' AND Val='CompanyCode' LIMIT 1");
+            "SELECT Domain FROM GeneralizedCodeMaster WHERE FldName='SystemConfig' AND Val='CompanyCode' AND tenant_id=@TenantId LIMIT 1",
+            new List<SugarParameter> { new("@TenantId", tenantId) });
         domain = string.IsNullOrWhiteSpace(domain) ? string.Empty : domain.Trim();
 
         string? lockKey = null;
@@ -326,9 +334,10 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
                     INNER JOIN scm_shdzb b ON CAST(a.id AS CHAR) = b.glid
                     WHERE a.shddh = @shddh
                       AND IFNULL(b.sh_material_code, '') <> ''
-                      AND IFNULL(b.shpc, '') = '';
+                      AND IFNULL(b.shpc, '') = ''
+                      AND a.tenant_id = @TenantId;
                     """,
-                    new List<SugarParameter> { new("@shddh", shddh) });
+                    new List<SugarParameter> { new("@shddh", shddh), new("@TenantId", tenantId) });
 
                 if (needShpc.Count > 0)
                 {
@@ -467,9 +476,10 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
                     LEFT JOIN PurOrdMaster pm ON pm.PurOrd = b.po_bill
                     LEFT JOIN PurOrdDetail pd ON pd.PurOrd = b.po_bill AND pd.Line = b.po_billline
                     LEFT JOIN ItemMaster im ON im.ItemNum = b.sh_material_code
-                    WHERE a.shddh = @shddh;
+                    WHERE a.shddh = @shddh
+                      AND a.tenant_id = @TenantId;
                     """,
-                    new List<SugarParameter> { new("@shddh", shddh) });
+                    new List<SugarParameter> { new("@shddh", shddh), new("@TenantId", tenantId) });
 
                 foreach (var row in sourceRows)
                 {
@@ -697,6 +707,7 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
     /// </summary>
     private async Task<string> AllocateShddhAsync(string supplierCode)
     {
+        var tenantId = _userManager.TenantId;
         var code = (supplierCode ?? string.Empty).Trim().Replace("-", string.Empty);
         if (string.IsNullOrEmpty(code))
             throw Oops.Oh("请先填写供应商编号,保存时将用于生成发货单号");
@@ -720,8 +731,9 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
                 WHERE shddh LIKE CONCAT(@pfx, '%')
                   AND CHAR_LENGTH(shddh) = CHAR_LENGTH(@pfx) + 4
                   AND RIGHT(shddh, 4) REGEXP '^[0-9]{4}$'
+                  AND tenant_id = @TenantId
                 """,
-                new List<SugarParameter> { new("@pfx", prefix) });
+                new List<SugarParameter> { new("@pfx", prefix), new("@TenantId", tenantId) });
 
             var next = maxSeq + 1;
             if (next > 9999)
@@ -857,7 +869,8 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
         if (string.IsNullOrWhiteSpace(shddh))
             throw Oops.Oh("缺少发货单编号(shddh)");
 
-        var pars = new List<SugarParameter> { new("@shddh", shddh.Trim()) };
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@shddh", shddh.Trim()), new("@TenantId", tenantId) };
 
         const string masterSql = """
             SELECT
@@ -888,6 +901,7 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
                 chbg
             FROM scm_shd
             WHERE shddh = @shddh
+              AND tenant_id = @TenantId
             LIMIT 1
             """;
 
@@ -922,6 +936,7 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
                 WHERE p.IsActive = 1
             ) c ON c.PurOrd = b.po_bill AND CAST(c.Line AS CHAR) = TRIM(CAST(IFNULL(b.po_billline, '') AS CHAR))
             WHERE a.shddh = @shddh
+              AND a.tenant_id = @TenantId
             ORDER BY b.hh, b.id
             """;
 
@@ -985,7 +1000,8 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
         if (string.IsNullOrWhiteSpace(shddh))
             throw Oops.Oh("缺少发货单编号(shddh)");
 
-        var pars = new List<SugarParameter> { new("@shddh", shddh.Trim()) };
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@shddh", shddh.Trim()), new("@TenantId", tenantId) };
         const string sql = """
                            SELECT DISTINCT
                                glid,
@@ -1011,6 +1027,7 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
                                shpc
                            FROM scm_shbq
                            WHERE shdh = @shddh
+                             AND tenant_id = @TenantId
                            """;
 
         var list = await _db.Ado.SqlQueryAsync<SupplierShipmentLabelRow>(sql, pars);
@@ -1019,7 +1036,8 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
 
     private async Task SaveDetailsAsync(long masterId, List<SupplierShipmentDetailInput> inputDetails)
     {
-        var dbDetails = await _detailRep.AsQueryable().Where(x => x.Glid == masterId.ToString()).ToListAsync();
+        var tenantId = _userManager.TenantId;
+        var dbDetails = await _detailRep.AsQueryable().Where(x => x.Glid == masterId.ToString() && x.TenantId == tenantId).ToListAsync();
         var dbById = dbDetails.ToDictionary(x => x.Id);
         var inputIds = new HashSet<long>(inputDetails.Where(d => d.Id is > 0).Select(d => d.Id!.Value));
 
@@ -1174,6 +1192,7 @@ public class SupplierShipmentService : IDynamicApiController, ITransient
             FROM scm_shd a
             LEFT JOIN scm_shdzb b ON CAST(a.id AS CHAR) = b.glid
             LEFT JOIN (SELECT DISTINCT glid, shpc FROM scm_shbq) c ON CAST(b.id AS CHAR) = c.glid
+            WHERE a.tenant_id = @TenantId
         ) m
         LEFT JOIN
         (

+ 5 - 3
server/Plugins/Admin.NET.Plugin.AiDOP/ProcurementExecution/SupplierShortageKanbanService.cs

@@ -15,8 +15,9 @@ namespace Admin.NET.Plugin.AiDOP.ProcurementExecution;
 public class SupplierShortageKanbanService : IDynamicApiController, ITransient
 {
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public SupplierShortageKanbanService(ISqlSugarClient db) => _db = db;
+    public SupplierShortageKanbanService(ISqlSugarClient db, UserManager userManager) { _db = db; _userManager = userManager; }
 
     private static string NormalizeOrderBy(string field, string order)
     {
@@ -59,8 +60,9 @@ public class SupplierShortageKanbanService : IDynamicApiController, ITransient
         var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
         var offset = (page - 1) * pageSize;
 
-        var cond = new List<string> { "1=1" };
-        var pars = new List<SugarParameter>();
+        var tenantId = _userManager.TenantId;
+        var cond = new List<string> { "1=1", "t.tenant_id = @TenantId" };
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
 
         if (!string.IsNullOrWhiteSpace(input.ItemNum))
         {

+ 12 - 5
server/Plugins/Admin.NET.Plugin.AiDOP/Production/ExecutableDailyPlanService.cs

@@ -24,13 +24,15 @@ public class ExecutableDailyPlanService : IDynamicApiController, ITransient
     [HttpGet("daily-plan/list")]
     public async Task<object> GetList([FromQuery] ExecutableDailyPlanListInput input)
     {
-        var pars = new List<SugarParameter>();
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
 
         var innerWhere = new List<string>
         {
             "p.OrdQty > 0",
             "p.IsActive = 1",
-            "LOWER(IFNULL(w.Status,'')) <> 'c'"
+            "LOWER(IFNULL(w.Status,'')) <> 'c'",
+            "p.tenant_id = @TenantId"
         };
         if (!string.IsNullOrWhiteSpace(input.PlanDateMin))
         {
@@ -126,6 +128,7 @@ public class ExecutableDailyPlanService : IDynamicApiController, ITransient
 
         var account = _userManager.Account ?? "system";
         var now = DateTime.Now;
+        var tenantId = _userManager.TenantId;
         const string releasedFlag = "Y";
 
         var n = await _db.Ado.ExecuteCommandAsync(
@@ -136,13 +139,15 @@ public class ExecutableDailyPlanService : IDynamicApiController, ITransient
                 UpdateTime = @UpdateTime
             WHERE RecID IN ({string.Join(",", ids)})
               AND `Domain` = @Domain
+              AND tenant_id = @TenantId
             """,
             new List<SugarParameter>
             {
                 new("@Flag", releasedFlag),
                 new("@UpdateUser", account),
                 new("@UpdateTime", now),
-                new("@Domain", domain)
+                new("@Domain", domain),
+                new("@TenantId", tenantId)
             });
 
         return new { message = "下达成功", affected = n };
@@ -157,13 +162,14 @@ public class ExecutableDailyPlanService : IDynamicApiController, ITransient
         if (st is not ("w" or "r" or "c" or "p"))
             throw Oops.Oh("状态不合法");
 
+        var tenantId = _userManager.TenantId;
         var n = await _db.Ado.ExecuteCommandAsync(
             $"""
             UPDATE WorkOrdMaster
             SET `Status` = @St,
                 UpdateTime = @Now,
                 UpdateUser = @User
-            WHERE WorkOrd = @WorkOrd AND `Domain` = @Domain
+            WHERE WorkOrd = @WorkOrd AND `Domain` = @Domain AND tenant_id = @TenantId
             """,
             new List<SugarParameter>
             {
@@ -171,7 +177,8 @@ public class ExecutableDailyPlanService : IDynamicApiController, ITransient
                 new("@Now", DateTime.Now),
                 new("@User", _userManager.Account ?? "system"),
                 new("@WorkOrd", input.WorkOrd.Trim()),
-                new("@Domain", input.Domain.Trim())
+                new("@Domain", input.Domain.Trim()),
+                new("@TenantId", tenantId)
             });
         if (n == 0)
             throw Oops.Oh("工单不存在");

+ 22 - 13
server/Plugins/Admin.NET.Plugin.AiDOP/Production/QualityLineWorkDetailService.cs

@@ -23,8 +23,9 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
     [HttpGet("line-rest/list")]
     public async Task<object> GetList([FromQuery] QualityLineRestListInput input)
     {
-        var pars = new List<SugarParameter>();
-        var where = "qd.IsActive = 1";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "qd.IsActive = 1 AND qd.tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(input.ProdLine))
         {
             where += " AND qd.ProdLine = @ProdLine";
@@ -51,6 +52,7 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
             LEFT JOIN LineMaster lm
                 ON qd.`Domain` COLLATE utf8mb4_general_ci = lm.`Domain` COLLATE utf8mb4_general_ci
                AND qd.ProdLine COLLATE utf8mb4_general_ci = lm.`Line` COLLATE utf8mb4_general_ci
+               AND lm.tenant_id = @TenantId
             WHERE {where}
             """;
 
@@ -65,14 +67,15 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
     [HttpGet("line-rest/{id:long}")]
     public async Task<object> GetDetail(long id)
     {
+        var tenantId = _userManager.TenantId;
         var row = (await _db.Ado.SqlQueryAsync<QualityLineRestDetailRow>(
             """
             SELECT RecID AS Id, `Domain`, Site, ProdLine, WorkShift, Line, RestTimePoint, RestTime,
                    Ufld1 AS Remark, Descr1, Descr2, Period, EndDateTime
             FROM QualityLineWorkDetail
-            WHERE RecID = @Id
+            WHERE RecID = @Id AND tenant_id = @TenantId
             """,
-            new List<SugarParameter> { new("@Id", id) })).FirstOrDefault()
+            new List<SugarParameter> { new("@Id", id), new("@TenantId", tenantId) })).FirstOrDefault()
             ?? throw Oops.Oh("记录不存在");
         return row;
     }
@@ -92,6 +95,8 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
         const string defaultWorkShift = "-";
         const string defaultEnd = "2999-12-31";
 
+        var tenantId = _userManager.TenantId;
+
         if (input.Id is null or 0)
         {
             await _db.Ado.ExecuteCommandAsync(
@@ -99,11 +104,11 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
                 INSERT INTO QualityLineWorkDetail (
                     `Domain`, Site, ProdLine, WorkShift, Line, RestTimePoint, RestTime, Descr1, Descr2, Period, EndDateTime, Ufld1,
                     IsActive, IsConfirm, BusinessID,
-                    CreateUser, CreateTime, UpdateUser, UpdateTime
+                    CreateUser, CreateTime, UpdateUser, UpdateTime, tenant_id
                 ) VALUES (
                     @Domain, @Site, @ProdLine, @WorkShift, 0, @RestTimePoint, @RestTime, NULL, NULL, 0, @EndDateTime, @Ufld1,
                     1, 0, 0,
-                    @User, @Now, @User, @Now
+                    @User, @Now, @User, @Now, @TenantId
                 )
                 """,
                 new List<SugarParameter>
@@ -117,7 +122,8 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
                     new("@EndDateTime", defaultEnd),
                     new("@Ufld1", (object?)remark ?? DBNull.Value),
                     new("@User", account),
-                    new("@Now", now)
+                    new("@Now", now),
+                    new("@TenantId", tenantId)
                 });
 
             var newId = await _db.Ado.GetIntAsync("SELECT LAST_INSERT_ID()");
@@ -135,7 +141,7 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
                 Ufld1 = @Ufld1,
                 UpdateUser = @User,
                 UpdateTime = @Now
-            WHERE RecID = @Id
+            WHERE RecID = @Id AND tenant_id = @TenantId
             """,
             new List<SugarParameter>
             {
@@ -147,7 +153,8 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
                 new("@RestTime", input.RestTime),
                 new("@Ufld1", (object?)remark ?? DBNull.Value),
                 new("@User", account),
-                new("@Now", now)
+                new("@Now", now),
+                new("@TenantId", tenantId)
             });
         if (n == 0)
             throw Oops.Oh("记录不存在或未变更");
@@ -158,9 +165,10 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
     [HttpPost("line-rest/delete/{id:long}")]
     public async Task<object> Delete(long id)
     {
+        var tenantId = _userManager.TenantId;
         var n = await _db.Ado.ExecuteCommandAsync(
-            "UPDATE QualityLineWorkDetail SET IsActive = 0, UpdateTime = @Now WHERE RecID = @Id",
-            new List<SugarParameter> { new("@Id", id), new("@Now", DateTime.Now) });
+            "UPDATE QualityLineWorkDetail SET IsActive = 0, UpdateTime = @Now WHERE RecID = @Id AND tenant_id = @TenantId",
+            new List<SugarParameter> { new("@Id", id), new("@Now", DateTime.Now), new("@TenantId", tenantId) });
         if (n == 0)
             throw Oops.Oh("记录不存在");
         return new { message = "已删除" };
@@ -170,8 +178,9 @@ public class QualityLineWorkDetailService : IDynamicApiController, ITransient
     [HttpGet("line-rest/lines")]
     public async Task<object> GetLines([FromQuery] string? domain)
     {
-        var pars = new List<SugarParameter>();
-        var where = "IsActive = 1";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "IsActive = 1 AND tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(domain))
         {
             where += " AND `Domain` = @Domain";

+ 21 - 13
server/Plugins/Admin.NET.Plugin.AiDOP/Production/ResourceOvertimeService.cs

@@ -23,8 +23,9 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
     [HttpGet("overtime/list")]
     public async Task<object> GetList([FromQuery] ResourceOvertimeListInput input)
     {
-        var pars = new List<SugarParameter>();
-        var where = "r.IsActive = 1";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "r.IsActive = 1 AND r.tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(input.Resource))
         {
             where += " AND r.Resource = @Resource";
@@ -87,6 +88,7 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
     [HttpGet("overtime/{id:long}")]
     public async Task<object> GetDetail(long id)
     {
+        var tenantId = _userManager.TenantId;
         var row = (await _db.Ado.SqlQueryAsync<ResourceOvertimeDetailRow>(
             """
             SELECT RecID AS Id, `Domain`, Site, ResourceType, Resource, StartTime, EndTime, Descr,
@@ -94,9 +96,9 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
                    ROUND(CAST(IFNULL(Ufld1, 0) AS DECIMAL(20, 10)) * 60, 0) AS WorkMinutes,
                    ROUND(CAST(IFNULL(Ufld2, 0) AS DECIMAL(20, 10)) * 60, 0) AS RestMinutes
             FROM ResourceOccupancyTime
-            WHERE RecID = @Id
+            WHERE RecID = @Id AND tenant_id = @TenantId
             """,
-            new List<SugarParameter> { new("@Id", id) })).FirstOrDefault()
+            new List<SugarParameter> { new("@Id", id), new("@TenantId", tenantId) })).FirstOrDefault()
             ?? throw Oops.Oh("记录不存在");
         return row;
     }
@@ -116,6 +118,8 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
         var ufld1Hours = input.WorkMinutes.HasValue ? input.WorkMinutes.Value / 60m : (decimal?)null;
         var ufld2Hours = input.RestMinutes.HasValue ? input.RestMinutes.Value / 60m : (decimal?)null;
 
+        var tenantId = _userManager.TenantId;
+
         if (input.Id is null or 0)
         {
             await _db.Ado.ExecuteCommandAsync(
@@ -123,11 +127,11 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
                 INSERT INTO ResourceOccupancyTime (
                     `Domain`, Site, BusinessID, ResourceType, Resource, StartTime, EndTime, Descr,
                     IsRest, IsActive, IsConfirm, IsChanged, Ufld1, Ufld2,
-                    CreateUser, CreateTime, UpdateUser, UpdateTime
+                    CreateUser, CreateTime, UpdateUser, UpdateTime, tenant_id
                 ) VALUES (
                     @Domain, @Site, 0, @ResourceType, @Resource, @StartTime, @EndTime, @Descr,
                     0, 1, 0, 0, @Ufld1, @Ufld2,
-                    @User, @Now, @User, @Now
+                    @User, @Now, @User, @Now, @TenantId
                 )
                 """,
                 new List<SugarParameter>
@@ -142,7 +146,8 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
                     new("@Ufld1", (object?)ufld1Hours ?? DBNull.Value),
                     new("@Ufld2", (object?)ufld2Hours ?? DBNull.Value),
                     new("@User", account),
-                    new("@Now", now)
+                    new("@Now", now),
+                    new("@TenantId", tenantId)
                 });
 
             var newId = await _db.Ado.GetIntAsync("SELECT LAST_INSERT_ID()");
@@ -163,7 +168,7 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
                 Ufld2 = @Ufld2,
                 UpdateUser = @User,
                 UpdateTime = @Now
-            WHERE RecID = @Id
+            WHERE RecID = @Id AND tenant_id = @TenantId
             """,
             new List<SugarParameter>
             {
@@ -178,7 +183,8 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
                 new("@Ufld1", (object?)ufld1Hours ?? DBNull.Value),
                 new("@Ufld2", (object?)ufld2Hours ?? DBNull.Value),
                 new("@User", account),
-                new("@Now", now)
+                new("@Now", now),
+                new("@TenantId", tenantId)
             });
         if (n == 0)
             throw Oops.Oh("记录不存在或未变更");
@@ -189,9 +195,10 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
     [HttpPost("overtime/delete/{id:long}")]
     public async Task<object> Delete(long id)
     {
+        var tenantId = _userManager.TenantId;
         var n = await _db.Ado.ExecuteCommandAsync(
-            "UPDATE ResourceOccupancyTime SET IsActive = 0, UpdateTime = @Now WHERE RecID = @Id",
-            new List<SugarParameter> { new("@Id", id), new("@Now", DateTime.Now) });
+            "UPDATE ResourceOccupancyTime SET IsActive = 0, UpdateTime = @Now WHERE RecID = @Id AND tenant_id = @TenantId",
+            new List<SugarParameter> { new("@Id", id), new("@Now", DateTime.Now), new("@TenantId", tenantId) });
         if (n == 0)
             throw Oops.Oh("记录不存在");
         return new { message = "已删除" };
@@ -201,8 +208,9 @@ public class ResourceOvertimeService : IDynamicApiController, ITransient
     [HttpGet("overtime/lines")]
     public async Task<object> GetLines([FromQuery] string? domain)
     {
-        var pars = new List<SugarParameter>();
-        var where = "IsActive = 1";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "IsActive = 1 AND tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(domain))
         {
             where += " AND `Domain` = @Domain";

+ 15 - 8
server/Plugins/Admin.NET.Plugin.AiDOP/Production/ScheduleExceptionService.cs

@@ -16,11 +16,13 @@ public class ScheduleExceptionService : IDynamicApiController, ITransient
 
     private readonly ISqlSugarClient _db;
     private readonly SqlSugarRepository<ScheduleExceptionMaster> _rep;
+    private readonly UserManager _userManager;
 
-    public ScheduleExceptionService(ISqlSugarClient db, SqlSugarRepository<ScheduleExceptionMaster> rep)
+    public ScheduleExceptionService(ISqlSugarClient db, SqlSugarRepository<ScheduleExceptionMaster> rep, UserManager userManager)
     {
         _db = db;
         _rep = rep;
+        _userManager = userManager;
     }
 
     // ══════════════════════════════════════════════════════════════
@@ -31,8 +33,9 @@ public class ScheduleExceptionService : IDynamicApiController, ITransient
     [HttpGet("schedule-exception/list")]
     public async Task<object> GetList([FromQuery] ScheduleExceptionListInput input)
     {
-        var pars = new List<SugarParameter>();
-        var inner = new List<string> { "1=1" };
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var inner = new List<string> { "sm.tenant_id = @TenantId" };
 
         if (!string.IsNullOrWhiteSpace(input.OptTime))
         {
@@ -89,7 +92,8 @@ public class ScheduleExceptionService : IDynamicApiController, ITransient
     [HttpGet("schedule-exception/{id:long}")]
     public async Task<object> GetDetail(long id)
     {
-        var e = await _rep.GetFirstAsync(u => u.RecID == id)
+        var tenantId = _userManager.TenantId;
+        var e = await _rep.GetFirstAsync(u => u.RecID == id && u.TenantId == tenantId)
                 ?? throw Oops.Oh("记录不存在");
         return new
         {
@@ -112,6 +116,7 @@ public class ScheduleExceptionService : IDynamicApiController, ITransient
     [ApiDescriptionSettings(Name = "SaveScheduleException"), HttpPost("schedule-exception/save")]
     public async Task<object> Save([FromBody] ScheduleExceptionSaveInput input)
     {
+        var tenantId = _userManager.TenantId;
         if (input.Id is null or 0)
         {
             var entity = new ScheduleExceptionMaster
@@ -123,13 +128,14 @@ public class ScheduleExceptionService : IDynamicApiController, ITransient
                 Remark = input.Remark?.Trim(),
                 Type = input.Type?.Trim(),
                 OptTime = input.OptTime ?? DateTime.Now,
-                CreateTime = input.CreateTime ?? DateTime.Now
+                CreateTime = input.CreateTime ?? DateTime.Now,
+                TenantId = tenantId
             };
             await _rep.InsertAsync(entity);
             return new { id = entity.RecID, message = "新增成功" };
         }
 
-        var exist = await _rep.GetFirstAsync(u => u.RecID == input.Id!.Value)
+        var exist = await _rep.GetFirstAsync(u => u.RecID == input.Id!.Value && u.TenantId == tenantId)
                     ?? throw Oops.Oh("记录不存在");
         exist.Domain = input.Domain.Trim();
         exist.WorkOrd = input.WorkOrd.Trim();
@@ -150,9 +156,10 @@ public class ScheduleExceptionService : IDynamicApiController, ITransient
     [HttpPost("schedule-exception/delete/{id:long}")]
     public async Task<object> Delete(long id)
     {
+        var tenantId = _userManager.TenantId;
         var n = await _db.Ado.ExecuteCommandAsync(
-            "DELETE FROM ScheduleExceptionMaster WHERE RecID = @Id",
-            new List<SugarParameter> { new("@Id", id) });
+            "DELETE FROM ScheduleExceptionMaster WHERE RecID = @Id AND tenant_id = @TenantId",
+            new List<SugarParameter> { new("@Id", id), new("@TenantId", tenantId) });
         if (n == 0)
             throw Oops.Oh("记录不存在");
         return new { message = "删除成功" };

+ 24 - 15
server/Plugins/Admin.NET.Plugin.AiDOP/Production/ShopCalendarWorkCtrService.cs

@@ -23,8 +23,9 @@ public class ShopCalendarWorkCtrService : IDynamicApiController, ITransient
     [HttpGet("shop-calendar/list")]
     public async Task<object> GetList([FromQuery] ShopCalendarWorkCtrListInput input)
     {
-        var pars = new List<SugarParameter>();
-        var where = "sc.IsActive = 1";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "sc.IsActive = 1 AND sc.tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(input.ProdLine))
         {
             where += " AND sc.ProdLine = @ProdLine";
@@ -73,8 +74,9 @@ public class ShopCalendarWorkCtrService : IDynamicApiController, ITransient
     [HttpGet("shop-calendar/lines")]
     public async Task<object> GetLines([FromQuery] string? domain)
     {
-        var pars = new List<SugarParameter>();
-        var where = "IsActive = 1";
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+        var where = "IsActive = 1 AND tenant_id = @TenantId";
         if (!string.IsNullOrWhiteSpace(domain))
         {
             where += " AND `Domain` = @Domain";
@@ -89,15 +91,16 @@ public class ShopCalendarWorkCtrService : IDynamicApiController, ITransient
     [HttpGet("shop-calendar/{id:long}")]
     public async Task<object> GetDetail(long id)
     {
+        var tenantId = _userManager.TenantId;
         var row = (await _db.Ado.SqlQueryAsync<ShopCalendarDetailRow>(
             """
             SELECT RecID AS Id, ProdLine, WeekDay, ShiftsStart1, ShiftsHours1, ShiftsStart2, ShiftsHours2,
                    ShiftsStart3, ShiftsHours3, ShiftsStart4, ShiftsHours4,
                    Ufld1 AS Descr, `Domain`, Site, WorkCtr, TeamType, AllowOverTime, IsWorkDay
             FROM ShopCalendarWorkCtr
-            WHERE RecID = @Id
+            WHERE RecID = @Id AND tenant_id = @TenantId
             """,
-            new List<SugarParameter> { new("@Id", id) })).FirstOrDefault()
+            new List<SugarParameter> { new("@Id", id), new("@TenantId", tenantId) })).FirstOrDefault()
             ?? throw Oops.Oh("记录不存在");
 
         row.ShiftsStart1Text = DecimalHoursToTimeString(row.ShiftsStart1);
@@ -123,17 +126,20 @@ public class ShopCalendarWorkCtrService : IDynamicApiController, ITransient
         var h1 = input.ShiftsHours1 ?? 0m;
         var h2 = input.ShiftsHours2 ?? 0m;
 
+        var tenantId = _userManager.TenantId;
+
         if (input.Id is null or 0)
         {
             var dup = await _db.Ado.GetIntAsync(
                 """
                 SELECT COUNT(*) FROM ShopCalendarWorkCtr
-                WHERE IsActive = 1 AND ProdLine = @ProdLine AND WeekDay = @WeekDay
+                WHERE IsActive = 1 AND ProdLine = @ProdLine AND WeekDay = @WeekDay AND tenant_id = @TenantId
                 """,
                 new List<SugarParameter>
                 {
                     new("@ProdLine", prodLine),
-                    new("@WeekDay", input.WeekDay)
+                    new("@WeekDay", input.WeekDay),
+                    new("@TenantId", tenantId)
                 });
             if (dup > 0)
                 throw Oops.Oh("该生产线与星期组合已存在");
@@ -146,14 +152,14 @@ public class ShopCalendarWorkCtrService : IDynamicApiController, ITransient
                     ShiftsStart3, ShiftsHours3, ShiftsStart4, ShiftsHours4,
                     AllowOverTime, IsChanged, IsWorkDay,
                     IsActive, IsConfirm, BusinessID,
-                    CreateUser, CreateTime, UpdateUser, UpdateTime
+                    CreateUser, CreateTime, UpdateUser, UpdateTime, tenant_id
                 ) VALUES (
                     @Domain, @Site, @ProdLine, @WeekDay, @WorkCtr, @Ufld1,
                     @S1, @H1, @S2, @H2,
                     0, 0, 0, 0,
                     0, 0, 1,
                     1, 0, 0,
-                    @User, @Now, @User, @Now
+                    @User, @Now, @User, @Now, @TenantId
                 )
                 """,
                 new List<SugarParameter>
@@ -169,7 +175,8 @@ public class ShopCalendarWorkCtrService : IDynamicApiController, ITransient
                     new("@S2", s2),
                     new("@H2", h2),
                     new("@User", account),
-                    new("@Now", now)
+                    new("@Now", now),
+                    new("@TenantId", tenantId)
                 });
 
             var newId = await _db.Ado.GetIntAsync("SELECT LAST_INSERT_ID()");
@@ -191,7 +198,7 @@ public class ShopCalendarWorkCtrService : IDynamicApiController, ITransient
                 ShiftsHours2 = @H2,
                 UpdateUser = @User,
                 UpdateTime = @Now
-            WHERE RecID = @Id
+            WHERE RecID = @Id AND tenant_id = @TenantId
             """,
             new List<SugarParameter>
             {
@@ -207,7 +214,8 @@ public class ShopCalendarWorkCtrService : IDynamicApiController, ITransient
                 new("@S2", s2),
                 new("@H2", h2),
                 new("@User", account),
-                new("@Now", now)
+                new("@Now", now),
+                new("@TenantId", tenantId)
             });
         if (n == 0)
             throw Oops.Oh("记录不存在或未变更");
@@ -218,9 +226,10 @@ public class ShopCalendarWorkCtrService : IDynamicApiController, ITransient
     [HttpPost("shop-calendar/delete/{id:long}")]
     public async Task<object> Delete(long id)
     {
+        var tenantId = _userManager.TenantId;
         var n = await _db.Ado.ExecuteCommandAsync(
-            "UPDATE ShopCalendarWorkCtr SET IsActive = 0, UpdateTime = @Now WHERE RecID = @Id",
-            new List<SugarParameter> { new("@Id", id), new("@Now", DateTime.Now) });
+            "UPDATE ShopCalendarWorkCtr SET IsActive = 0, UpdateTime = @Now WHERE RecID = @Id AND tenant_id = @TenantId",
+            new List<SugarParameter> { new("@Id", id), new("@Now", DateTime.Now), new("@TenantId", tenantId) });
         if (n == 0)
             throw Oops.Oh("记录不存在");
         return new { message = "已删除" };

+ 7 - 3
server/Plugins/Admin.NET.Plugin.AiDOP/Production/WorkOrderProgressDashboardService.cs

@@ -11,10 +11,12 @@ namespace Admin.NET.Plugin.AiDOP.Production;
 public class WorkOrderProgressDashboardService : IDynamicApiController, ITransient
 {
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public WorkOrderProgressDashboardService(ISqlSugarClient db)
+    public WorkOrderProgressDashboardService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     /// <summary>工单执行进度看板分页列表</summary>
@@ -23,11 +25,13 @@ public class WorkOrderProgressDashboardService : IDynamicApiController, ITransie
     public async Task<object> GetList([FromQuery] WorkOrderProgressDashboardListInput input)
     {
         const string C = "utf8mb4_general_ci";
-        var pars = new List<SugarParameter>();
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
 
         var innerWhere = new List<string>
         {
-            "IFNULL(wm.Status,'') <> ''"
+            "IFNULL(wm.Status,'') <> ''",
+            "wm.tenant_id = @TenantId"
         };
 
         if (!string.IsNullOrWhiteSpace(input.WorkOrd))

+ 4 - 2
server/Plugins/Admin.NET.Plugin.AiDOP/Production/WorkOrderSchedulingService.cs

@@ -86,11 +86,13 @@ public class WorkOrderSchedulingService : IDynamicApiController, ITransient
     {
         //const string C = "utf8mb4_general_ci";
         const string C = "utf8mb4_0900_ai_ci";
-        var pars = new List<SugarParameter>();
+        var tenantId = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
 
         var innerWhere = new List<string>
         {
-            "IFNULL(a.Status,'') <> ''"
+            "IFNULL(a.Status,'') <> ''",
+            "a.tenant_id = @TenantId"
         };
 
         if (!string.IsNullOrWhiteSpace(input.WorkOrd))

+ 8 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/DeliveryExceptionService.cs

@@ -11,10 +11,12 @@ public class DeliveryExceptionService : IDynamicApiController, ITransient
 {
     private const string C = "utf8mb4_general_ci";
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public DeliveryExceptionService(ISqlSugarClient db)
+    public DeliveryExceptionService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     /// <summary>交货单异常记录分页列表</summary>
@@ -29,6 +31,11 @@ public class DeliveryExceptionService : IDynamicApiController, ITransient
         var pars = new List<SugarParameter>();
         var where = new List<string> { "1=1" };
 
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("dm.tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.OptTime))
         {
             where.Add($"(CAST(dm.OptTime AS CHAR(50)) COLLATE {C}) LIKE @OptTimeLike");

+ 15 - 4
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/DeliveryScheduleService.cs

@@ -278,6 +278,7 @@ public class DeliveryScheduleService : IDynamicApiController, ITransient
         if (!ids.Any()) throw Oops.Oh("请勾选要发布的数据");
 
         var account = _userManager.Account ?? "system";
+        var tenantId = _userManager.TenantId;
         var affected = await _db.Updateable<PolistDeliverySchedule>()
             .SetColumns(x => new PolistDeliverySchedule
             {
@@ -286,7 +287,7 @@ public class DeliveryScheduleService : IDynamicApiController, ITransient
                 UpdateUser = account,
                 UpdateTime = DateTime.Now
             })
-            .Where(x => ids.Contains(x.Id) && x.IsActive == 1 && x.Status == "N")
+            .Where(x => ids.Contains(x.Id) && x.IsActive == 1 && x.Status == "N" && (tenantId <= 0 || x.TenantId == tenantId))
             .ExecuteCommandAsync();
         return new { affected, message = affected > 0 ? "发布成功" : "无可发布数据" };
     }
@@ -295,7 +296,8 @@ public class DeliveryScheduleService : IDynamicApiController, ITransient
     [HttpPost("delivery-schedule/unpublish/{id:long}")]
     public async Task<object> UnPublish(long id)
     {
-        var row = await _rep.GetFirstAsync(x => x.Id == id && x.IsActive == 1) ?? throw Oops.Oh("交货单不存在");
+        var tenantId = _userManager.TenantId;
+        var row = await _rep.GetFirstAsync(x => x.Id == id && x.IsActive == 1 && (tenantId <= 0 || x.TenantId == tenantId)) ?? throw Oops.Oh("交货单不存在");
         row.Status = "N";
         row.UpdateUser = _userManager.Account;
         row.UpdateTime = DateTime.Now;
@@ -307,7 +309,8 @@ public class DeliveryScheduleService : IDynamicApiController, ITransient
     [HttpPost("delivery-schedule/cancel/{id:long}")]
     public async Task<object> Cancel(long id)
     {
-        var row = await _rep.GetFirstAsync(x => x.Id == id && x.IsActive == 1) ?? throw Oops.Oh("交货单不存在");
+        var tenantId = _userManager.TenantId;
+        var row = await _rep.GetFirstAsync(x => x.Id == id && x.IsActive == 1 && (tenantId <= 0 || x.TenantId == tenantId)) ?? throw Oops.Oh("交货单不存在");
         row.Status = "C";
         row.UpdateUser = _userManager.Account;
         row.UpdateTime = DateTime.Now;
@@ -330,6 +333,11 @@ public class DeliveryScheduleService : IDynamicApiController, ITransient
             "IFNULL(d.Status,'') <> 'C'",
             "(IFNULL(ds.dsnum, '') = '' OR (ds.status = 'C' AND d.QtyOrded - d.RctQty > 0))"
         };
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("m.tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.PurOrd))
         {
             where.Add("m.PurOrd LIKE @PurOrd");
@@ -901,6 +909,9 @@ public class DeliveryScheduleService : IDynamicApiController, ITransient
 
         var pars = new List<SugarParameter>();
         var inClause = BuildInClause(demandIds.Select(x => x.ToString()).ToList(), "DemandId", pars);
+        var tenantWhere = _userManager.TenantId > 0 ? " AND tenant_id = @TenantId" : string.Empty;
+        if (_userManager.TenantId > 0)
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
         var rows = await _db.Ado.SqlQueryAsync<ExistingScheduleUsageRow>(
             $"""
             SELECT
@@ -913,7 +924,7 @@ public class DeliveryScheduleService : IDynamicApiController, ITransient
                     END
                 ) AS UsedQty
             FROM srm_polist_ds
-            WHERE isactive = 1 AND icdsid IN ({inClause})
+            WHERE isactive = 1 AND icdsid IN ({inClause}){tenantWhere}
             GROUP BY icdsid
             """,
             pars);

+ 31 - 19
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/DemandOrderService.cs

@@ -36,6 +36,11 @@ public class DemandOrderService : IDynamicApiController, ITransient
         };
         var pars = new List<SugarParameter>();
 
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("p.tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.PurOrd))
         {
             where.Add("p.PurOrd LIKE @PurOrd");
@@ -201,8 +206,9 @@ public class DemandOrderService : IDynamicApiController, ITransient
             {
                 masterId = input.Id.Value;
                 var exists = await _db.Ado.GetIntAsync(
-                    "SELECT COUNT(1) FROM PurOrdMaster WHERE RecID=@Id AND Potype='PO' AND IFNULL(ReqBy,'')='DO'",
-                    new SugarParameter("@Id", masterId));
+                    "SELECT COUNT(1) FROM PurOrdMaster WHERE RecID=@Id AND Potype='PO' AND IFNULL(ReqBy,'')='DO'" + (_userManager.TenantId > 0 ? " AND tenant_id=@TenantId" : ""),
+                    new SugarParameter("@Id", masterId),
+                    _userManager.TenantId > 0 ? new SugarParameter("@TenantId", _userManager.TenantId) : null!);
                 if (exists <= 0) throw Oops.Oh("记录不存在");
 
                 purOrd = await _db.Ado.GetStringAsync(
@@ -250,27 +256,23 @@ public class DemandOrderService : IDynamicApiController, ITransient
     {
         if (string.IsNullOrWhiteSpace(purOrd)) throw Oops.Oh("缺少要货令单号");
 
+        var delPars = new List<SugarParameter> { new("@PurOrd", purOrd.Trim()) };
+        if (_userManager.TenantId > 0) delPars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        var tenantSuffix = _userManager.TenantId > 0 ? " AND tenant_id=@TenantId" : string.Empty;
+
         var hasReceipt = await _db.Ado.GetIntAsync(
-            """
-            SELECT COUNT(1)
-            FROM PurOrdRctDetail
-            WHERE OrdNbr=@PurOrd AND IFNULL(QtyReceived,0)>0
-            """,
-            new SugarParameter("@PurOrd", purOrd.Trim()));
+            $"SELECT COUNT(1) FROM PurOrdRctDetail WHERE OrdNbr=@PurOrd AND IFNULL(QtyReceived,0)>0{tenantSuffix}",
+            delPars);
         if (hasReceipt > 0) throw Oops.Oh("存在收货数量,不允许删除");
 
         var hasDetailRct = await _db.Ado.GetIntAsync(
-            """
-            SELECT COUNT(1)
-            FROM PurOrdDetail
-            WHERE PurOrd=@PurOrd AND IFNULL(RctQty,0)>0
-            """,
-            new SugarParameter("@PurOrd", purOrd.Trim()));
+            $"SELECT COUNT(1) FROM PurOrdDetail WHERE PurOrd=@PurOrd AND IFNULL(RctQty,0)>0{tenantSuffix}",
+            delPars);
         if (hasDetailRct > 0) throw Oops.Oh("存在收货数量,不允许删除");
 
         var hasShip = await _db.Ado.GetIntAsync(
-            "SELECT COUNT(1) FROM scm_shdzb WHERE po_bill=@PurOrd",
-            new SugarParameter("@PurOrd", purOrd.Trim()));
+            $"SELECT COUNT(1) FROM scm_shdzb WHERE po_bill=@PurOrd{tenantSuffix}",
+            delPars);
         if (hasShip > 0) throw Oops.Oh("存在发货单,不允许删除");
 
         try
@@ -304,6 +306,11 @@ public class DemandOrderService : IDynamicApiController, ITransient
         var where = new List<string> { "1=1" };
         var pars = new List<SugarParameter>();
 
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.ItemNum))
         {
             where.Add("ItemNum LIKE @ItemNum");
@@ -523,8 +530,13 @@ public class DemandOrderService : IDynamicApiController, ITransient
 
     private async Task<DemandOrderListRow> GetMasterRowAsync(int id)
     {
+        var tenantId = _userManager.TenantId;
+        var tenantWhere = tenantId > 0 ? " AND p.tenant_id=@TenantId" : string.Empty;
+        var pars = new List<SugarParameter> { new("@Id", id) };
+        if (tenantId > 0) pars.Add(new SugarParameter("@TenantId", tenantId));
+
         var row = (await _db.Ado.SqlQueryAsync<DemandOrderListRow>(
-            """
+            $"""
             SELECT
                 p.RecID AS Id,
                 p.PurOrd AS PurOrd,
@@ -553,10 +565,10 @@ public class DemandOrderService : IDynamicApiController, ITransient
             LEFT JOIN SuppMaster s ON p.Supp=s.Supp
             LEFT JOIN DepartmentMaster d ON p.Department=d.Department
             LEFT JOIN EmployeeMaster e ON p.Buyer=e.Employee
-            WHERE p.RecID=@Id AND p.Potype='PO' AND IFNULL(p.ReqBy,'')='DO'
+            WHERE p.RecID=@Id AND p.Potype='PO' AND IFNULL(p.ReqBy,'')='DO'{tenantWhere}
             LIMIT 1
             """,
-            new SugarParameter("@Id", id))).FirstOrDefault();
+            pars)).FirstOrDefault();
         return row ?? throw Oops.Oh("记录不存在");
     }
 

+ 10 - 5
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/DemandScheduleService.cs

@@ -104,7 +104,8 @@ public class DemandScheduleService : IDynamicApiController, ITransient
     [HttpGet("demand-schedule/{id:long}")]
     public async Task<object> GetDetail(long id)
     {
-        var row = await _rep.GetFirstAsync(x => x.Id == id && (x.IsDeleted == null || x.IsDeleted == 0));
+        var tenantId = _userManager.TenantId;
+        var row = await _rep.GetFirstAsync(x => x.Id == id && (x.IsDeleted == null || x.IsDeleted == 0) && (tenantId <= 0 || x.TenantId == tenantId));
         if (row == null) throw Oops.Oh("记录不存在");
         return row;
     }
@@ -138,7 +139,8 @@ public class DemandScheduleService : IDynamicApiController, ITransient
         }
         else
         {
-            var entity = await _rep.GetFirstAsync(x => x.Id == input.Id.Value && (x.IsDeleted == null || x.IsDeleted == 0))
+            var tenantId = _userManager.TenantId;
+            var entity = await _rep.GetFirstAsync(x => x.Id == input.Id.Value && (x.IsDeleted == null || x.IsDeleted == 0) && (tenantId <= 0 || x.TenantId == tenantId))
                          ?? throw Oops.Oh("记录不存在");
 
             entity.ItemNum = input.ItemNum?.Trim();
@@ -166,7 +168,8 @@ public class DemandScheduleService : IDynamicApiController, ITransient
     [HttpPost("demand-schedule/delete/{id:long}")]
     public async Task<object> Delete(long id)
     {
-        var entity = await _rep.GetFirstAsync(x => x.Id == id && (x.IsDeleted == null || x.IsDeleted == 0))
+        var tenantId = _userManager.TenantId;
+        var entity = await _rep.GetFirstAsync(x => x.Id == id && (x.IsDeleted == null || x.IsDeleted == 0) && (tenantId <= 0 || x.TenantId == tenantId))
                      ?? throw Oops.Oh("记录不存在");
 
         entity.IsDeleted = 1;
@@ -184,6 +187,7 @@ public class DemandScheduleService : IDynamicApiController, ITransient
         var ids = ParseIds(input.Ids);
         if (!ids.Any()) throw Oops.Oh("请选择要发布的数据");
 
+        var tenantId = _userManager.TenantId;
         var affected = await _db.Updateable<DemandSchedule>()
             .SetColumns(x => new DemandSchedule
             {
@@ -192,7 +196,7 @@ public class DemandScheduleService : IDynamicApiController, ITransient
                 UpdateByName = _userManager.Account,
                 UpdateTime = DateTime.Now
             })
-            .Where(x => ids.Contains(x.Id) && (x.IsDeleted == null || x.IsDeleted == 0) && (x.Status == null || x.Status == ""))
+            .Where(x => ids.Contains(x.Id) && (x.IsDeleted == null || x.IsDeleted == 0) && (x.Status == null || x.Status == "") && (tenantId <= 0 || x.TenantId == tenantId))
             .ExecuteCommandAsync();
         return new { affected, message = affected > 0 ? "发布成功" : "无可发布数据" };
     }
@@ -225,6 +229,7 @@ public class DemandScheduleService : IDynamicApiController, ITransient
         var ids = ParseIds(input.Ids);
         if (!ids.Any()) throw Oops.Oh("请选择要取消发布的数据");
 
+        var tenantId = _userManager.TenantId;
         var affected = await _db.Updateable<DemandSchedule>()
             .SetColumns(x => new DemandSchedule
             {
@@ -233,7 +238,7 @@ public class DemandScheduleService : IDynamicApiController, ITransient
                 UpdateByName = _userManager.Account,
                 UpdateTime = DateTime.Now
             })
-            .Where(x => ids.Contains(x.Id) && (x.IsDeleted == null || x.IsDeleted == 0) && x.Status == "P")
+            .Where(x => ids.Contains(x.Id) && (x.IsDeleted == null || x.IsDeleted == 0) && x.Status == "P" && (tenantId <= 0 || x.TenantId == tenantId))
             .ExecuteCommandAsync();
         return new { affected, message = affected > 0 ? "取消发布成功" : "无可取消发布数据" };
     }

+ 6 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/Entity/PurOrdDetail.cs

@@ -512,4 +512,10 @@ public class PurOrdDetail
 
     [SugarColumn(ColumnName = "Descr", ColumnDataType = "text", IsNullable = true)]
     public string? Descr { get; set; }
+
+    /// <summary>
+    /// 租户Id
+    /// </summary>
+    [SugarColumn(ColumnName = "tenant_id", ColumnDescription = "租户Id")]
+    public long? TenantId { get; set; }
 }

+ 6 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/Entity/PurOrdMaster.cs

@@ -353,4 +353,10 @@ public class PurOrdMaster
 
     [SugarColumn(ColumnName = "WorkOrd", Length = 255, IsNullable = true)]
     public string? WorkOrd { get; set; }
+
+    /// <summary>
+    /// 租户Id
+    /// </summary>
+    [SugarColumn(ColumnName = "tenant_id", ColumnDescription = "租户Id")]
+    public long? TenantId { get; set; }
 }

+ 24 - 8
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/NumberRuleService.cs

@@ -6,10 +6,12 @@ namespace Admin.NET.Plugin.AiDOP.Supply;
 public class NumberRuleService : ITransient
 {
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public NumberRuleService(ISqlSugarClient db)
+    public NumberRuleService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     public async Task<IReadOnlyList<string>> NextBatchAsync(string ruleCode, string domain, int count, string operatorNo)
@@ -37,8 +39,16 @@ public class NumberRuleService : ITransient
         var normalizedDomain = domain?.Trim() ?? string.Empty;
         var now = DateTime.Now;
 
+        var tenantWhere = _userManager.TenantId > 0 ? "\n              AND tenant_id = @TenantId" : string.Empty;
+        var rulePars = new List<SugarParameter>
+        {
+            new("@RuleCode", normalizedRuleCode),
+            new("@Domain", normalizedDomain)
+        };
+        if (_userManager.TenantId > 0) rulePars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+
         var rule = (await _db.Ado.SqlQueryAsync<NbrControlRuleRow>(
-            """
+            $"""
             SELECT
                 RecID AS Id,
                 NbrType,
@@ -67,7 +77,7 @@ public class NumberRuleService : ITransient
                   OR IFNULL(TRIM(domain_code),'') = ''
                   OR IFNULL(TRIM(Domain),'') = ''
               )
-              AND IFNULL(IsActive, 1) = 1
+              AND IFNULL(IsActive, 1) = 1{tenantWhere}
             ORDER BY
                 CASE
                     WHEN IFNULL(TRIM(domain_code),'') = @Domain THEN 0
@@ -78,8 +88,7 @@ public class NumberRuleService : ITransient
             LIMIT 1
             FOR UPDATE
             """,
-            new SugarParameter("@RuleCode", normalizedRuleCode),
-            new SugarParameter("@Domain", normalizedDomain))).FirstOrDefault();
+            rulePars)).FirstOrDefault();
 
         if (rule == null)
             throw Oops.Oh($"未找到编号规则:{normalizedRuleCode}");
@@ -124,6 +133,14 @@ public class NumberRuleService : ITransient
     private async Task<NbrDayInfoRow?> GetDayInfoForUpdateAsync(NbrControlRuleRow rule, string ruleCode, string domain, DateTime? sequenceDate)
     {
         var dateFilter = sequenceDate.HasValue ? "AND DATE(Today) = DATE(@Today)" : string.Empty;
+        var tenantFilter = _userManager.TenantId > 0 ? "AND tenant_id = @TenantId2" : string.Empty;
+        var dayPars = new List<SugarParameter>
+        {
+            new("@RuleCode", rule.NbrType ?? ruleCode),
+            new("@Domain", rule.Domain ?? domain),
+            new("@Today", sequenceDate ?? DateTime.Today)
+        };
+        if (_userManager.TenantId > 0) dayPars.Add(new SugarParameter("@TenantId2", _userManager.TenantId));
         return (await _db.Ado.SqlQueryAsync<NbrDayInfoRow>(
             $"""
             SELECT
@@ -133,13 +150,12 @@ public class NumberRuleService : ITransient
             WHERE LOWER(TRIM(IFNULL(NbrType,''))) = LOWER(@RuleCode)
               AND IFNULL(TRIM(Domain),'') = @Domain
               {dateFilter}
+              {tenantFilter}
             ORDER BY RecID
             LIMIT 1
             FOR UPDATE
             """,
-            new SugarParameter("@RuleCode", rule.NbrType ?? ruleCode),
-            new SugarParameter("@Domain", rule.Domain ?? domain),
-            new SugarParameter("@Today", sequenceDate ?? DateTime.Today))).FirstOrDefault();
+            dayPars)).FirstOrDefault();
     }
 
     private async Task InsertDayInfoAsync(NbrControlRuleRow rule, DateTime? sequenceDate, int nextValue, string operatorNo, DateTime now)

+ 52 - 19
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/OutsourceOrderService.cs

@@ -35,6 +35,11 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
             "IFNULL(p.`Usage`,'')='委外加工'"
         };
         var pars = new List<SugarParameter>();
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("p.tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.PurOrd))
         {
             where.Add("p.PurOrd LIKE @PurOrd");
@@ -95,8 +100,12 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
     [HttpGet("outsource-order/{id:int}")]
     public async Task<object> GetOrderDetail(int id)
     {
+        var tenantWhere = _userManager.TenantId > 0 ? " AND p.tenant_id=@TenantId" : string.Empty;
+        var detailPars = _userManager.TenantId > 0
+            ? new[] { new SugarParameter("@Id", id), new SugarParameter("@TenantId", _userManager.TenantId) }
+            : new[] { new SugarParameter("@Id", id) };
         var row = (await _db.Ado.SqlQueryAsync<OutsourceOrderListRow>(
-            """
+            $"""
             SELECT
                 p.RecID AS Id,
                 p.PurOrd AS PurOrd,
@@ -118,10 +127,10 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
             LEFT JOIN SuppMaster s ON p.Supp=s.Supp
             LEFT JOIN DepartmentMaster d ON p.Department=d.Department
             LEFT JOIN EmployeeMaster e ON p.Buyer=e.Employee
-            WHERE p.RecID=@Id
+            WHERE p.RecID=@Id{tenantWhere}
             LIMIT 1
             """,
-            new SugarParameter("@Id", id))).FirstOrDefault();
+            detailPars)).FirstOrDefault();
         return row ?? throw Oops.Oh("记录不存在");
     }
 
@@ -196,7 +205,10 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
             }
         }
 
-        var exists = await _db.Ado.GetIntAsync("SELECT COUNT(1) FROM PurOrdMaster WHERE RecID=@Id", new SugarParameter("@Id", input.Id.Value));
+        var exists = await _db.Ado.GetIntAsync("SELECT COUNT(1) FROM PurOrdMaster WHERE RecID=@Id" + (_userManager.TenantId > 0 ? " AND tenant_id=@TenantId" : ""),
+            _userManager.TenantId > 0
+                ? new[] { new SugarParameter("@Id", input.Id.Value), new SugarParameter("@TenantId", _userManager.TenantId) }
+                : new[] { new SugarParameter("@Id", input.Id.Value) });
         if (exists <= 0) throw Oops.Oh("记录不存在");
         await _db.Ado.ExecuteCommandAsync(
             """
@@ -224,17 +236,17 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
     {
         if (string.IsNullOrWhiteSpace(purOrd)) throw Oops.Oh("缺少采购订单号");
         var hasReceipt = await _db.Ado.GetIntAsync(
-            """
-            SELECT COUNT(1)
-            FROM PurOrdRctDetail
-            WHERE OrdNbr=@PurOrd AND IFNULL(QtyReceived,0)>0
-            """,
-            new SugarParameter("@PurOrd", purOrd.Trim()));
+            "SELECT COUNT(1) FROM PurOrdRctDetail WHERE OrdNbr=@PurOrd AND IFNULL(QtyReceived,0)>0" + (_userManager.TenantId > 0 ? " AND tenant_id=@TenantId" : ""),
+            _userManager.TenantId > 0
+                ? new[] { new SugarParameter("@PurOrd", purOrd.Trim()), new SugarParameter("@TenantId", _userManager.TenantId) }
+                : new[] { new SugarParameter("@PurOrd", purOrd.Trim()) });
         if (hasReceipt > 0) throw Oops.Oh("存在收货数量,不允许删除");
 
         var hasShip = await _db.Ado.GetIntAsync(
-            "SELECT COUNT(1) FROM scm_shdzb WHERE po_bill=@PurOrd",
-            new SugarParameter("@PurOrd", purOrd.Trim()));
+            "SELECT COUNT(1) FROM scm_shdzb WHERE po_bill=@PurOrd" + (_userManager.TenantId > 0 ? " AND tenant_id=@TenantId" : ""),
+            _userManager.TenantId > 0
+                ? new[] { new SugarParameter("@PurOrd", purOrd.Trim()), new SugarParameter("@TenantId", _userManager.TenantId) }
+                : new[] { new SugarParameter("@PurOrd", purOrd.Trim()) });
         if (hasShip > 0) throw Oops.Oh("存在发货单,不允许删除");
 
         try
@@ -264,6 +276,11 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
 
         var where = new List<string> { "d.Potype='PW'" };
         var pars = new List<SugarParameter>();
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("d.tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.PurOrd))
         {
             where.Add("d.PurOrd LIKE @PurOrd");
@@ -314,18 +331,22 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
     [HttpGet("outsource-order/detail/{id:int}")]
     public async Task<object> GetDetail(int id)
     {
+        var tenantWhere = _userManager.TenantId > 0 ? " AND d.tenant_id=@TenantId" : string.Empty;
+        var detailPars = _userManager.TenantId > 0
+            ? new[] { new SugarParameter("@Id", id), new SugarParameter("@TenantId", _userManager.TenantId) }
+            : new[] { new SugarParameter("@Id", id) };
         var detail = (await _db.Ado.SqlQueryAsync<OutsourceOrderDetailRow>(
-            """
+            $"""
             SELECT
                 d.PurOrd AS PurOrd,d.ItemNum AS ItemNum,d.QtyOrded AS QtyOrded,d.QtyReceived AS QtyReceived,d.QtyReleased AS QtyReleased,
                 d.DueDate AS DueDate,d.Line AS Line,d.Location AS Location,d.UM AS UM,d.RecID AS Id,d.Rev AS Rev,d.Drawing AS Drawing,
                 d.WorkOrd AS WorkOrd,d.LotSerial AS LotSerial,d.Status AS Status,IFNULL(i.Descr,'') AS Descr,d.PurOrdRecID AS PurOrdRecID
             FROM PurOrdDetail d
             LEFT JOIN ItemMaster i ON d.ItemNum=i.ItemNum
-            WHERE d.RecID=@Id
+            WHERE d.RecID=@Id{tenantWhere}
             LIMIT 1
             """,
-            new SugarParameter("@Id", id))).FirstOrDefault();
+            detailPars)).FirstOrDefault();
         if (detail == null) throw Oops.Oh("记录不存在");
 
         var batches = await _db.Ado.SqlQueryAsync<OutsourceOrderBatchRow>(
@@ -507,7 +528,10 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
     [HttpPost("outsource-order/detail/delete/{id:int}")]
     public async Task<object> DeleteDetail(int id)
     {
-        var status = await _db.Ado.GetStringAsync("SELECT Status FROM PurOrdDetail WHERE RecID=@Id LIMIT 1", new SugarParameter("@Id", id));
+        var status = await _db.Ado.GetStringAsync("SELECT Status FROM PurOrdDetail WHERE RecID=@Id" + (_userManager.TenantId > 0 ? " AND tenant_id=@TenantId" : "") + " LIMIT 1",
+            _userManager.TenantId > 0
+                ? new[] { new SugarParameter("@Id", id), new SugarParameter("@TenantId", _userManager.TenantId) }
+                : new[] { new SugarParameter("@Id", id) });
         if (string.Equals(status, "C", StringComparison.OrdinalIgnoreCase))
             throw Oops.Oh("关闭状态不允许删除");
 
@@ -531,16 +555,20 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
     public async Task<object> GetDetailInit([FromQuery] string purOrd)
     {
         if (string.IsNullOrWhiteSpace(purOrd)) throw Oops.Oh("采购订单号不能为空");
+        var tenantWhere = _userManager.TenantId > 0 ? " AND p.tenant_id=@TenantId" : string.Empty;
+        var initPars = _userManager.TenantId > 0
+            ? new[] { new SugarParameter("@PurOrd", purOrd.Trim()), new SugarParameter("@TenantId", _userManager.TenantId) }
+            : new[] { new SugarParameter("@PurOrd", purOrd.Trim()) };
         var row = (await _db.Ado.SqlQueryAsync<DetailInitRow>(
-            """
+            $"""
             SELECT p.`Usage` AS `Usage`, IFNULL(MAX(d.Line),0)+1 AS Line, p.RecID AS PurOrdRecID, p.PurOrd AS PurOrd
             FROM PurOrdMaster p
             LEFT JOIN PurOrdDetail d ON p.PurOrd=d.PurOrd
-            WHERE p.PurOrd=@PurOrd
+            WHERE p.PurOrd=@PurOrd{tenantWhere}
             GROUP BY p.`Usage`, p.RecID, p.PurOrd
             LIMIT 1
             """,
-            new SugarParameter("@PurOrd", purOrd.Trim()))).FirstOrDefault();
+            initPars)).FirstOrDefault();
         return row ?? throw Oops.Oh("采购订单不存在");
     }
 
@@ -554,6 +582,11 @@ public class OutsourceOrderService : IDynamicApiController, ITransient
         var where = new List<string> { "1=1" };
         var pars = new List<SugarParameter>();
 
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.ItemNum))
         {
             where.Add("ItemNum LIKE @ItemNum");

+ 24 - 12
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/ProcessOutsourceOrderService.cs

@@ -30,6 +30,11 @@ public class ProcessOutsourceOrderService : IDynamicApiController, ITransient
 
         var where = new List<string> { "p.Potype='PW'", "p.IsActive<=1", "IFNULL(p.`Usage`,'')='外协'" };
         var pars = new List<SugarParameter>();
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("p.tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.PurOrd))
         {
             where.Add("p.PurOrd LIKE @PurOrd");
@@ -109,17 +114,21 @@ public class ProcessOutsourceOrderService : IDynamicApiController, ITransient
     [HttpGet("process-outsource-order/{id:int}")]
     public async Task<object> GetDetail(int id)
     {
+        var tenantWhere = _userManager.TenantId > 0 ? " AND p.tenant_id=@TenantId" : string.Empty;
+        var masterPars = _userManager.TenantId > 0
+            ? new[] { new SugarParameter("@Id", id), new SugarParameter("@TenantId", _userManager.TenantId) }
+            : new[] { new SugarParameter("@Id", id) };
         var master = (await _db.Ado.SqlQueryAsync<ProcessOutsourceOrderMasterRow>(
-            """
+            $"""
             SELECT
                 p.RecID AS Id,p.PurOrd AS PurOrd,p.OrdDate AS OrdDate,p.Supp AS Supp,p.ReqBy AS ReqBy,p.WorkOrd AS WorkOrd,
                 p.Buyer AS Buyer,p.Department AS Department,p.`Usage` AS `Usage`,p.Curr AS Curr,p.Remark AS Remark,
                 CASE WHEN IFNULL(LENGTH(p.Status),0)=0 OR p.Buyer IS NULL THEN 'R' ELSE p.Status END AS Status
             FROM PurOrdMaster p
-            WHERE p.RecID=@Id
+            WHERE p.RecID=@Id{tenantWhere}
             LIMIT 1
             """,
-            new SugarParameter("@Id", id))).FirstOrDefault();
+            masterPars)).FirstOrDefault();
         if (master == null) throw Oops.Oh("记录不存在");
 
         var details = await _db.Ado.SqlQueryAsync<ProcessOutsourceOrderDetailRow>(
@@ -502,7 +511,10 @@ public class ProcessOutsourceOrderService : IDynamicApiController, ITransient
         if (string.IsNullOrWhiteSpace(input.Supp)) throw Oops.Oh("供应商不能为空");
         if (string.IsNullOrWhiteSpace(input.Department)) throw Oops.Oh("部门不能为空");
 
-        var exists = await _db.Ado.GetIntAsync("SELECT COUNT(1) FROM PurOrdMaster WHERE RecID=@Id", new SugarParameter("@Id", input.Id));
+        var exists = await _db.Ado.GetIntAsync("SELECT COUNT(1) FROM PurOrdMaster WHERE RecID=@Id" + (_userManager.TenantId > 0 ? " AND tenant_id=@TenantId" : ""),
+            _userManager.TenantId > 0
+                ? new[] { new SugarParameter("@Id", input.Id), new SugarParameter("@TenantId", _userManager.TenantId) }
+                : new[] { new SugarParameter("@Id", input.Id) });
         if (exists <= 0) throw Oops.Oh("记录不存在");
 
         try
@@ -653,17 +665,17 @@ public class ProcessOutsourceOrderService : IDynamicApiController, ITransient
         var ordNo = purOrd.Trim();
 
         var hasReceipt = await _db.Ado.GetIntAsync(
-            """
-            SELECT COUNT(1)
-            FROM PurOrdRctDetail
-            WHERE OrdNbr=@PurOrd AND IFNULL(QtyReceived,0)>0
-            """,
-            new SugarParameter("@PurOrd", ordNo));
+            "SELECT COUNT(1) FROM PurOrdRctDetail WHERE OrdNbr=@PurOrd AND IFNULL(QtyReceived,0)>0" + (_userManager.TenantId > 0 ? " AND tenant_id=@TenantId" : ""),
+            _userManager.TenantId > 0
+                ? new[] { new SugarParameter("@PurOrd", ordNo), new SugarParameter("@TenantId", _userManager.TenantId) }
+                : new[] { new SugarParameter("@PurOrd", ordNo) });
         if (hasReceipt > 0) throw Oops.Oh("存在收货数量,不允许删除");
 
         var hasShip = await _db.Ado.GetIntAsync(
-            "SELECT COUNT(1) FROM scm_shdzb WHERE po_bill=@PurOrd",
-            new SugarParameter("@PurOrd", ordNo));
+            "SELECT COUNT(1) FROM scm_shdzb WHERE po_bill=@PurOrd" + (_userManager.TenantId > 0 ? " AND tenant_id=@TenantId" : ""),
+            _userManager.TenantId > 0
+                ? new[] { new SugarParameter("@PurOrd", ordNo), new SugarParameter("@TenantId", _userManager.TenantId) }
+                : new[] { new SugarParameter("@PurOrd", ordNo) });
         if (hasShip > 0) throw Oops.Oh("存在发货单,不允许删除");
 
         try

+ 13 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/PurchaseOrderService.cs

@@ -10,10 +10,12 @@ namespace Admin.NET.Plugin.AiDOP.Supply;
 public class PurchaseOrderService : IDynamicApiController, ITransient
 {
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public PurchaseOrderService(ISqlSugarClient db)
+    public PurchaseOrderService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     [DisplayName("物料采购订单列表")]
@@ -32,6 +34,11 @@ public class PurchaseOrderService : IDynamicApiController, ITransient
         var where = new List<string> { "1=1" };
         var pars = new List<SugarParameter>();
 
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("a.tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.Cgdd))
         {
             where.Add("a.cgdd LIKE @Cgdd");
@@ -134,6 +141,11 @@ public class PurchaseOrderService : IDynamicApiController, ITransient
         var where = new List<string> { "1=1" };
         var pars = new List<SugarParameter>();
 
+        if (_userManager.TenantId > 0)
+        {
+            where.Add("a.tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", _userManager.TenantId));
+        }
         if (!string.IsNullOrWhiteSpace(input.Cgdd))
         {
             where.Add("a.po_no LIKE @Cgdd");

+ 32 - 14
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/PurchaseRequestService.cs

@@ -109,8 +109,13 @@ public class PurchaseRequestService : IDynamicApiController, ITransient
     [HttpGet("purchase-request/{id:long}")]
     public async Task<object> GetDetail(long id)
     {
+        var tenantId = _userManager.TenantId;
+        var tenantWhere = tenantId > 0 ? " AND pm.tenant_id=@TenantId" : string.Empty;
+        var pars = new List<SugarParameter> { new("@Id", id) };
+        if (tenantId > 0) pars.Add(new SugarParameter("@TenantId", tenantId));
+
         var row = (await _db.Ado.SqlQueryAsync<PurchaseRequestDetailRow>(
-            """
+            $"""
             SELECT
                 pm.id AS Id,
                 pm.pr_billno AS PrBillNo,
@@ -131,10 +136,10 @@ public class PurchaseRequestService : IDynamicApiController, ITransient
                 pm.pr_purchaser AS PrPurchaser,
                 pm.currencytype AS CurrencyType
             FROM srm_pr_main pm
-            WHERE pm.Id=@Id AND IFNULL(pm.IsDeleted,0)=0
+            WHERE pm.Id=@Id AND IFNULL(pm.IsDeleted,0)=0{tenantWhere}
             LIMIT 1
             """,
-            new SugarParameter("@Id", id))).FirstOrDefault();
+            pars)).FirstOrDefault();
 
         return row ?? throw Oops.Oh("记录不存在");
     }
@@ -209,13 +214,17 @@ public class PurchaseRequestService : IDynamicApiController, ITransient
         }
         else
         {
+            var tenantId = _userManager.TenantId;
+            var tenantSuffix = tenantId > 0 ? " AND tenant_id=@TenantId" : string.Empty;
+            var existPars = new List<SugarParameter> { new("@Id", input.Id.Value) };
+            if (tenantId > 0) existPars.Add(new SugarParameter("@TenantId", tenantId));
             var exist = await _db.Ado.GetIntAsync(
-                "SELECT COUNT(1) FROM srm_pr_main WHERE Id=@Id AND IFNULL(IsDeleted,0)=0",
-                new SugarParameter("@Id", input.Id.Value));
+                $"SELECT COUNT(1) FROM srm_pr_main WHERE Id=@Id AND IFNULL(IsDeleted,0)=0{tenantSuffix}",
+                existPars);
             if (exist <= 0) throw Oops.Oh("记录不存在");
 
             await _db.Ado.ExecuteCommandAsync(
-                """
+                $"""
                 UPDATE srm_pr_main
                 SET
                     pr_purchaseid=@PrPurchaseId,
@@ -239,7 +248,7 @@ public class PurchaseRequestService : IDynamicApiController, ITransient
                     update_time=@UpdateTime,
                     IsRequireGoods=@IsRequireGoods,
                     supplier_type=@SupplierType
-                WHERE Id=@Id AND IFNULL(IsDeleted,0)=0
+                WHERE Id=@Id AND IFNULL(IsDeleted,0)=0{tenantSuffix}
                 """,
                 new SugarParameter("@Id", input.Id.Value),
                 new SugarParameter("@PrPurchaseId", input.PrPurchaseId!.Value),
@@ -262,7 +271,8 @@ public class PurchaseRequestService : IDynamicApiController, ITransient
                 new SugarParameter("@UpdateByName", _userManager.Account),
                 new SugarParameter("@UpdateTime", now),
                 new SugarParameter("@IsRequireGoods", input.IsRequireGoods ?? 0),
-                new SugarParameter("@SupplierType", input.SupplierType?.Trim())
+                new SugarParameter("@SupplierType", input.SupplierType?.Trim()),
+                new SugarParameter("@TenantId", tenantId)
             );
 
             return new { id = input.Id, message = "编辑成功" };
@@ -273,16 +283,24 @@ public class PurchaseRequestService : IDynamicApiController, ITransient
     [HttpPost("purchase-request/delete/{id:long}")]
     public async Task<object> Delete(long id)
     {
+        var tenantId = _userManager.TenantId;
+        var tenantSuffix = tenantId > 0 ? " AND tenant_id=@TenantId" : string.Empty;
+        var pars = new List<SugarParameter>
+        {
+            new("@Id", id),
+            new("@UpdateBy", _userManager.UserId),
+            new("@UpdateByName", _userManager.Account),
+            new("@UpdateTime", DateTime.Now)
+        };
+        if (tenantId > 0) pars.Add(new SugarParameter("@TenantId", tenantId));
+
         var affected = await _db.Ado.ExecuteCommandAsync(
-            """
+            $"""
             UPDATE srm_pr_main
             SET IsDeleted=1,state=0,update_by=@UpdateBy,update_by_name=@UpdateByName,update_time=@UpdateTime
-            WHERE Id=@Id AND IFNULL(IsDeleted,0)=0
+            WHERE Id=@Id AND IFNULL(IsDeleted,0)=0{tenantSuffix}
             """,
-            new SugarParameter("@Id", id),
-            new SugarParameter("@UpdateBy", _userManager.UserId),
-            new SugarParameter("@UpdateByName", _userManager.Account),
-            new SugarParameter("@UpdateTime", DateTime.Now));
+            pars);
 
         if (affected <= 0) throw Oops.Oh("记录不存在");
         return new { message = "删除成功" };

+ 24 - 4
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/S3MdpMonitorService.cs

@@ -10,18 +10,26 @@ namespace Admin.NET.Plugin.AiDOP.Supply;
 public class S3MdpMonitorService : IDynamicApiController, ITransient
 {
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public S3MdpMonitorService(ISqlSugarClient db)
+    public S3MdpMonitorService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     [DisplayName("S3 MDP最近运行状态")]
     [HttpGet("s3-mdp-monitor/latest")]
     public async Task<object> GetLatest()
     {
+        var tenantId = _userManager.TenantId;
+        var tenantWhere = tenantId > 0 ? " AND tenant_id=@TenantId" : string.Empty;
+        var pars = new List<SugarParameter>();
+        if (tenantId > 0) pars.Add(new SugarParameter("@TenantId", tenantId));
+
         return await _db.Ado.SqlQuerySingleAsync<S3MdpRunLogRow>(
-            $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE job_code='S3_MDP_SYNC_TRANSFORM' ORDER BY start_time DESC, id DESC LIMIT 1")
+            $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE job_code='S3_MDP_SYNC_TRANSFORM'{tenantWhere} ORDER BY start_time DESC, id DESC LIMIT 1",
+            pars)
             ?? new S3MdpRunLogRow();
     }
 
@@ -35,6 +43,13 @@ public class S3MdpMonitorService : IDynamicApiController, ITransient
         var where = new List<string> { "job_code='S3_MDP_SYNC_TRANSFORM'" };
         var pars = new List<SugarParameter>();
 
+        var tenantId = _userManager.TenantId;
+        if (tenantId > 0)
+        {
+            where.Add("tenant_id=@TenantId");
+            pars.Add(new SugarParameter("@TenantId", tenantId));
+        }
+
         if (!string.IsNullOrWhiteSpace(input.BatchId))
         {
             where.Add("batch_id LIKE @BatchId");
@@ -75,9 +90,14 @@ public class S3MdpMonitorService : IDynamicApiController, ITransient
     [HttpGet("s3-mdp-monitor/detail/{id}")]
     public async Task<object> GetDetail(long id)
     {
+        var tenantId = _userManager.TenantId;
+        var tenantWhere = tenantId > 0 ? " AND tenant_id=@TenantId" : string.Empty;
+        var pars = new List<SugarParameter> { new("@Id", id) };
+        if (tenantId > 0) pars.Add(new SugarParameter("@TenantId", tenantId));
+
         var row = await _db.Ado.SqlQuerySingleAsync<S3MdpRunLogRow>(
-            $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE id=@Id LIMIT 1",
-            new SugarParameter("@Id", id));
+            $"{SelectColumnsSql()} FROM mdp_transform_run_log WHERE id=@Id{tenantWhere} LIMIT 1",
+            pars);
         return row ?? throw Oops.Oh("运行日志不存在");
     }
 

+ 23 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Supply/WorkOrderMaterialReadinessService.cs

@@ -11,11 +11,13 @@ public class WorkOrderMaterialReadinessService : IDynamicApiController, ITransie
 {
     private readonly ISqlSugarClient _db;
     private readonly S3MdpSyncTransformService _mdpService;
+    private readonly UserManager _userManager;
 
-    public WorkOrderMaterialReadinessService(ISqlSugarClient db, S3MdpSyncTransformService mdpService)
+    public WorkOrderMaterialReadinessService(ISqlSugarClient db, S3MdpSyncTransformService mdpService, UserManager userManager)
     {
         _db = db;
         _mdpService = mdpService;
+        _userManager = userManager;
     }
 
     [DisplayName("工单物料齐套上线看板列表")]
@@ -29,6 +31,13 @@ public class WorkOrderMaterialReadinessService : IDynamicApiController, ITransie
         var where = new List<string> { "1=1" };
         var pars = new List<SugarParameter>();
 
+        var tenantId = _userManager.TenantId;
+        if (tenantId > 0)
+        {
+            where.Add("a.tenant_id=@TenantId");
+            pars.Add(new SugarParameter("@TenantId", tenantId));
+        }
+
         if (!string.IsNullOrWhiteSpace(input.SeOrder))
         {
             where.Add("a.SeOrder LIKE @SeOrder");
@@ -249,6 +258,12 @@ public class WorkOrderMaterialReadinessService : IDynamicApiController, ITransie
         if (!string.IsNullOrWhiteSpace(input.SeOrder))
             return false;
 
+        var tenantId = _userManager.TenantId;
+        if (tenantId > 0)
+        {
+            var pars = new List<SugarParameter> { new("@TenantId", tenantId) };
+            return await _db.Ado.GetIntAsync("SELECT COUNT(1) FROM dwd_material_readiness WHERE tenant_id=@TenantId LIMIT 1", pars) > 0;
+        }
         return await _db.Ado.GetIntAsync("SELECT COUNT(1) FROM dwd_material_readiness LIMIT 1") > 0;
     }
 
@@ -257,6 +272,13 @@ public class WorkOrderMaterialReadinessService : IDynamicApiController, ITransie
         var where = new List<string> { "1=1" };
         var pars = new List<SugarParameter>();
 
+        var tenantId = _userManager.TenantId;
+        if (tenantId > 0)
+        {
+            where.Add("a.tenant_id=@TenantId");
+            pars.Add(new SugarParameter("@TenantId", tenantId));
+        }
+
         if (!string.IsNullOrWhiteSpace(input.Workord))
         {
             where.Add("a.work_order LIKE @Workord");

+ 4 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Universal/Entity/CustMaster.cs

@@ -102,4 +102,8 @@ public class CustMaster
     /// <summary>银行帐户</summary>
     [SugarColumn(ColumnName = "BankAcct", Length = 30, IsNullable = true)]
     public string? BankAcct { get; set; }
+
+    /// <summary>租户ID(多租户隔离)</summary>
+    [SugarColumn(ColumnName = "tenant_id", IsNullable = true)]
+    public long? TenantId { get; set; }
 }

+ 5 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Universal/UniversalCustomerService.cs

@@ -11,10 +11,12 @@ namespace Admin.NET.Plugin.AiDOP.Universal;
 public class UniversalCustomerService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<CustMaster> _custRep;
+    private readonly UserManager _userManager;
 
-    public UniversalCustomerService(SqlSugarRepository<CustMaster> custRep)
+    public UniversalCustomerService(SqlSugarRepository<CustMaster> custRep, UserManager userManager)
     {
         _custRep = custRep;
+        _userManager = userManager;
     }
 
     /// <summary>获取客户选择分页列表 🏢</summary>
@@ -22,7 +24,9 @@ public class UniversalCustomerService : IDynamicApiController, ITransient
     [HttpGet("customer/page")]
     public async Task<object> GetCustomerPage([FromQuery] UniversalCustomerPageInput input)
     {
+        var tenantId = _userManager.TenantId;
         var query = _custRep.AsQueryable()
+            .Where(u => u.TenantId == tenantId)
             .WhereIF(!string.IsNullOrWhiteSpace(input.CustNo),   u => u.Cust!.Contains(input.CustNo!.Trim()))
             .WhereIF(!string.IsNullOrWhiteSpace(input.SortName), u => u.SortName!.Contains(input.SortName!.Trim()));
 

+ 5 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Universal/UniversalItemService.cs

@@ -11,10 +11,12 @@ namespace Admin.NET.Plugin.AiDOP.Universal;
 public class UniversalItemService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<ItemMaster> _itemRep;
+    private readonly UserManager _userManager;
 
-    public UniversalItemService(SqlSugarRepository<ItemMaster> itemRep)
+    public UniversalItemService(SqlSugarRepository<ItemMaster> itemRep, UserManager userManager)
     {
         _itemRep = itemRep;
+        _userManager = userManager;
     }
 
     /// <summary>获取物料选择分页列表 📦</summary>
@@ -22,7 +24,9 @@ public class UniversalItemService : IDynamicApiController, ITransient
     [HttpGet("item/page")]
     public async Task<object> GetItemPage([FromQuery] UniversalItemPageInput input)
     {
+        var tenantId = _userManager.TenantId;
         var query = _itemRep.AsQueryable()
+            .Where(u => u.TenantId == tenantId)
             .WhereIF(!string.IsNullOrWhiteSpace(input.ItemNum), u => u.ItemNum!.Contains(input.ItemNum!.Trim()))
             .WhereIF(!string.IsNullOrWhiteSpace(input.Descr), u => u.Descr!.Contains(input.Descr!.Trim()));
 

+ 7 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Universal/UniversalSourceListService.cs

@@ -11,10 +11,12 @@ public class UniversalSourceListService : IDynamicApiController, ITransient
 {
     private const string C = "utf8mb4_general_ci";
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public UniversalSourceListService(ISqlSugarClient db)
+    public UniversalSourceListService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     [DisplayName("获取货源清单选择列表")]
@@ -25,9 +27,11 @@ public class UniversalSourceListService : IDynamicApiController, ITransient
         var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
         var offset = (page - 1) * pageSize;
 
+        var tenantId = _userManager.TenantId;
         var pars = new List<SugarParameter>();
         var where = new List<string>
         {
+            "sp.tenant_id = @TenantId",
             "(it.erp_cls=3 OR it.erp_cls=2)",
             "IFNULL(sp.quota_rate,0)>0",
             "IFNULL(sp.IsDeleted,0)=0"
@@ -48,6 +52,8 @@ public class UniversalSourceListService : IDynamicApiController, ITransient
             pars.Add(new SugarParameter("@SupplierNumber", $"%{input.SupplierNumber.Trim()}%"));
         }
 
+        pars.Add(new SugarParameter("@TenantId", tenantId));
+
         var orderBy = BuildOrderBy(input.SortField, input.SortOrder);
         var fromSql = $"""
             FROM srm_purchase sp

+ 6 - 2
server/Plugins/Admin.NET.Plugin.AiDOP/Universal/UniversalWorkOrderService.cs

@@ -10,10 +10,12 @@ namespace Admin.NET.Plugin.AiDOP.Universal;
 public class UniversalWorkOrderService : IDynamicApiController, ITransient
 {
     private readonly ISqlSugarClient _db;
+    private readonly UserManager _userManager;
 
-    public UniversalWorkOrderService(ISqlSugarClient db)
+    public UniversalWorkOrderService(ISqlSugarClient db, UserManager userManager)
     {
         _db = db;
+        _userManager = userManager;
     }
 
     [DisplayName("获取工单选择列表")]
@@ -24,12 +26,14 @@ public class UniversalWorkOrderService : IDynamicApiController, ITransient
         var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
         var offset = (page - 1) * pageSize;
 
+        var tenantId = _userManager.TenantId;
         var where = new List<string>
         {
+            "a.tenant_id = @TenantId",
             "a.Status!='c'",
             "a.Workord in (select Workord from WorkOrdRouting where ProcessOut=1 and WorkOrd not in (SELECT WorkOrd from PurOrdMaster where Potype='PW' and WorkOrd is not null))"
         };
-        var pars = new List<SugarParameter>();
+        var pars = new List<SugarParameter> { new SugarParameter("@TenantId", tenantId) };
         if (!string.IsNullOrWhiteSpace(input.WorkOrd))
         {
             where.Add("a.WorkOrd LIKE @WorkOrd");

+ 3 - 2
server/Plugins/Admin.NET.Plugin.AiDOP/WorkOrder/WorkOrderDispatchService.cs

@@ -54,10 +54,11 @@ public class WorkOrderDispatchService : IDynamicApiController, ITransient
     [HttpGet("dispatch/list")]
     public async Task<object> GetDispatchList([FromQuery] WorkOrderDispatchListInput input)
     {
-        var pars = new List<SugarParameter>();
+        var tid = _userManager.TenantId;
+        var pars = new List<SugarParameter> { new SugarParameter("@TenantId", tid) };
         // 与库内其它原生 SQL 一致:统一 COLLATE,避免 utf8mb4_general_ci / utf8mb4_0900_ai_ci 混用报错
         const string C = "utf8mb4_general_ci";
-        var conditions = new List<string> { $"a.Status COLLATE {C} = 'p'" };
+        var conditions = new List<string> { $"a.tenant_id = @TenantId", $"a.Status COLLATE {C} = 'p'" };
 
         if (!string.IsNullOrWhiteSpace(input.WorkOrd))
         {