Files
SGGL_SHJ/SGGL/BLL/CLGL/TwArrivalStatisticsService.cs
T
lpf 201443e437 feat(hjgl): 支持按焊口匹配和回写管线材料
管线材料导入需要关联到具体焊口,并允许按材料编码匹配库存后回写
材料主编码。新增 HJGL_PipeLineMat 的焊口和材料编码字段,材料匹配、
任务生成和出库关系同步按焊口维度处理,避免仅按组件匹配导致材料
范围不准确。
2026-06-11 10:39:58 +08:00

383 lines
21 KiB
C#

using Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace BLL
{
public class TwArrivalStatisticsService
{
public static List<Tw_ArrivalStatisticsOutPut> GetStatistics(string projectid, string materialCode, string WarehouseCode)
{
using (Model.SGGLDB db = new Model.SGGLDB(Funs.ConnString))
{
string WarehouseId = Base_WarehouseService.GetWarehouseList(projectid).Where(x => x.WarehouseName == WarehouseCode).Select(x => x.WarehouseId).FirstOrDefault();
///所需材料数量列表
var NeedOutMateriaList = from x in db.HJGL_PipeLineMat
join y in db.HJGL_MaterialCodeLib on x.MaterialCode equals y.MaterialCode
join z in db.HJGL_Pipeline on x.PipelineId equals z.PipelineId
where z.ProjectId == projectid && (string.IsNullOrEmpty(materialCode) || x.MaterialCode.Contains(materialCode)) && z.WarehouseId == WarehouseId
group x by x.MaterialCode
into g
select new
{
g.Key,
NeedNum = g.Sum(x => x.Number) ?? 0,
};
///实际材料入库数量列表
var RealInMateriaList = (from x in db.Tw_InputDetail
join master in db.Tw_InputMaster on x.InputMasterId equals master.Id
join y in db.HJGL_MaterialCodeLib on x.MaterialCode equals y.MaterialCode
where master.ProjectId == projectid && master.WarehouseCode == WarehouseCode
group x by x.MaterialCode
into g
where (string.IsNullOrEmpty(materialCode) || g.Key.Contains(materialCode))
select new
{
g.Key,
RealNum = g.Sum(x => x.ActNum) ?? 0,
}).ToList();
//库存数量
var tw_MaterialStock = (from x in db.Tw_MaterialStock
where x.WarehouseCode == WarehouseCode && x.ProjectId == projectid
select x).ToList();
var needMateriaList = NeedOutMateriaList.ToList();
var materialCodeList = needMateriaList.Select(x => x.Key)
.Union(RealInMateriaList.Select(x => x.Key))
.Distinct()
.ToList();
var materialInfoList = (from x in db.HJGL_MaterialCodeLib
where materialCodeList.Contains(x.MaterialCode)
select x).ToList();
var StatisticsList = (from code in materialCodeList
join x in needMateriaList on code equals x.Key into needGroup
from x in needGroup.DefaultIfEmpty()
join y in RealInMateriaList on code equals y.Key into realGroup
from y in realGroup.DefaultIfEmpty()
join z in materialInfoList on code equals z.MaterialCode into infoGroup
from z in infoGroup.DefaultIfEmpty()
join m in tw_MaterialStock on code equals m.PipeLineMatCode into stockGroup
from m in stockGroup.DefaultIfEmpty()
orderby code
select new Tw_ArrivalStatisticsOutPut
{
MaterialCode = code,
StockNum = m == null ? 0 : (decimal)m.StockNum,
NeedNum = x == null ? 0 : x.NeedNum,
RealNum = y == null ? 0 : y.RealNum,
Code = z == null ? null : z.Code,
HeatNo = z == null ? null : z.HeatNo,
BatchNo = z == null ? null : z.BatchNo,
MaterialName = z == null ? null : z.MaterialName,
MaterialSpec = z == null ? null : z.MaterialSpec,
MaterialUnit = z == null ? null : z.MaterialUnit,
MaterialDef = z == null ? null : z.MaterialDef,
MatchRate = (x == null || x.NeedNum == 0 ? 0 : Math.Round((y == null ? 0 : y.RealNum) / x.NeedNum, 4, MidpointRounding.ToEven)),
}).ToList();
foreach (var item in StatisticsList)
{
item.MatchRateString = Math.Round(item.MatchRate * 100, 2).ToString() + "%";
}
return StatisticsList;
}
}
/// <summary>
/// 根据所需材料列表和库存列表获取匹配结果
/// </summary>
/// <param name="requiredMaterials"></param>
/// <param name="warehouseCode"></param>
/// <param name="projectId"></param>
/// <returns></returns>
public static List<Tw_PipeMatMatchOutput> GetMatMatchOutput(List<Tw_PipeMatMatchOutput> requiredMaterials, string warehouseCode, string projectId, bool matchByMaterialCodeLibCode = false)
{
Tw_MaterialStockOutput twMaterialStockOutput = new Tw_MaterialStockOutput
{
WarehouseCode = warehouseCode,
ProjectId = projectId
};
var stockList = TwMaterialstockService.GetTw_MaterialStockByModle(twMaterialStockOutput).ToList();//获取库存列表
// 预扣除出库申请单中状态为待审核/已审核的材料数量
using (Model.SGGLDB db = new Model.SGGLDB(Funs.ConnString))
{
var outboundMaterials = from detail in db.Tw_InOutPlanDetail
join master in db.Tw_InOutPlanMaster on detail.InOutPlanMasterId equals master.Id
where master.InOutType == (int)TwConst.InOutType.
&& (master.State == (int)TwConst.State. || master.State == (int)TwConst.State.)
&& master.WarehouseCode == warehouseCode
&& master.ProjectId == projectId
group detail by detail.MaterialCode into g
select new
{
MaterialCode = g.Key,
TotalPlanNum = g.Sum(d => d.PlanNum) ?? 0
};
var outboundList = outboundMaterials.ToList();
foreach (var outbound in outboundList)
{
var stock = stockList.FirstOrDefault(x => x.PipeLineMatCode == outbound.MaterialCode);
if (stock != null)
{
stock.StockNum -= outbound.TotalPlanNum;
}
}
}
foreach (var material in requiredMaterials)
{
material.Id = Guid.NewGuid().ToString();
var stock = matchByMaterialCodeLibCode
? stockList
.Where(x => x.Code == material.MaterialCode && (x.StockNum ?? 0) > 0)
.OrderByDescending(x => (x.StockNum ?? 0) >= (material.NeedNum ?? 0))
.ThenBy(x => x.PipeLineMatCode)
.FirstOrDefault()
: stockList.FirstOrDefault(x => x.PipeLineMatCode == material.MaterialCode);
var thisMaterialStockNum = stock?.StockNum ?? 0;
if (thisMaterialStockNum >= material.NeedNum)
{
material.MatchNum = material.NeedNum;
material.MatchRate = 1;
material.MatchRateString = "100%";
}
else
{
material.MatchNum = thisMaterialStockNum < 0 ? 0 : thisMaterialStockNum;
material.MatchRate = (material.NeedNum == 0 ? 0 : ((material.MatchNum ?? 0) / material.NeedNum));
material.MatchRateString = Math.Round((decimal)(material.MatchRate ?? 0) * 100, 2).ToString() + "%";
}
material.MatchMaterialCode = stock?.PipeLineMatCode;
//修改stockList对应的库存数量
if (stock != null)
{
stock.StockNum -= material.MatchNum;
}
}
var results = requiredMaterials;
return results;
}
/// <summary>
/// 获取管线匹配率
/// </summary>
/// <param name="pipelineId"></param>
/// <returns></returns>
public static decimal? GetPipeMatch(string pipelineId)
{
using (Model.SGGLDB db = new Model.SGGLDB(Funs.ConnString))
{
var twPipeMatMatchOutputs = new List<Tw_PipeMatMatchOutput>();
List<string> pipelineIds = new List<string>();
pipelineIds.Add(pipelineId);
var pipelineModel = PipelineService.GetPipelineByPipelineId(pipelineId);
string warehouseCode = BLL.Base_WarehouseService.GetWarehouseByWarehouseId(PipelineService.GetPipelineByPipelineId(pipelineModel.PipelineId).WarehouseId).WarehouseName;
var PipeMatMatch = GetPipeMatMatch(pipelineModel.ProjectId, pipelineIds, warehouseCode);
var pipeMatchRate = GetPipeMatch(PipeMatMatch).FirstOrDefault(x => x.PipelineId == pipelineId);
return pipeMatchRate?.MatchRate;
}
}
/// <summary>
/// 根据出库单主键获取材料匹配信息
/// </summary>
/// <param name="outPlanMasterId"></param>
/// <returns></returns>
public static List<Tw_PipeMatMatchOutput> GetMatMatchByOutPlanMasterId(string outPlanMasterId)
{
using (Model.SGGLDB db = new Model.SGGLDB(Funs.ConnString))
{
var results = new List<Tw_PipeMatMatchOutput>();
string[] taskPipeLineList = null;
var inoutPlanMasterl = db.Tw_InOutPlanMaster.FirstOrDefault(x => x.Id == outPlanMasterId);
if (inoutPlanMasterl != null)
{
if (inoutPlanMasterl.WeldTaskId.Split('|').Length == 4)
{
taskPipeLineList = Funs.DB.View_HJGL_WeldingTask.Where(e =>
e.UnitWorkId == inoutPlanMasterl.WeldTaskId.Split('|')[0].ToString()
&& e.UnitId == inoutPlanMasterl.WeldTaskId.Split('|')[1].ToString()
&& e.TaskDate.Value.Date == DateTime
.ParseExact(inoutPlanMasterl.WeldTaskId.Split('|')[2].ToString(), "yyyyMMdd", null).Date
&& e.SerialNumber == inoutPlanMasterl.WeldTaskId.Split('|')[3].ToString()
).Distinct().OrderBy(x => x.PipeLineSortIndex).Select(x => x.PipelineId).ToArray();
}
}
// 获取所需材料列表
var requiredMaterials = (from x in db.Tw_InOutPlanDetail_Relation
join master in db.Tw_InOutPlanMaster on x.InOutPlanMasterId equals master.Id
join y in db.HJGL_MaterialCodeLib on x.MaterialCode equals y.MaterialCode
join z in db.HJGL_Pipeline on x.PipelineId equals z.PipelineId
where x.InOutPlanMasterId == outPlanMasterId
select new Tw_PipeMatMatchOutput
{
Id = Guid.NewGuid().ToString(),
PipelineId = x.PipelineId,
PipelineCode = z.PipelineCode,
PrefabricatedComponents = x.PrefabricatedComponents,
MaterialCode = x.MaterialCode,
Code = y.Code,
HeatNo = y.HeatNo,
BatchNo = y.BatchNo,
MaterialName = y.MaterialName,
MaterialSpec = y.MaterialSpec,
MaterialUnit = y.MaterialUnit,
MaterialDef = y.MaterialDef,
NeedNum = x.Number
}
).ToList();
if (taskPipeLineList != null && taskPipeLineList.Any())
{
requiredMaterials = requiredMaterials.OrderBy(x => Array.IndexOf(taskPipeLineList, x.PipelineId.ToString())).ToList();
}
var masterModle = db.Tw_InOutPlanMaster.FirstOrDefault(x => x.Id == outPlanMasterId);
results = GetMatMatchOutput(requiredMaterials, masterModle.WarehouseCode, masterModle.ProjectId);
return results;
}
}
/// <summary>
/// 根据管线id获取材料匹配信息
/// </summary>
/// <param name="projectId"></param>
/// <param name="pipelineIds"></param>
/// <param name="warehouseCode"></param>
/// <returns></returns>
public static List<Tw_PipeMatMatchOutput> GetPipeMatMatch(string projectId, List<string> pipelineIds, string warehouseCode, Dictionary<string, List<string>> priorityWeldJoints = null)
{
using (Model.SGGLDB db = new Model.SGGLDB(Funs.ConnString))
{
var results = new List<Tw_PipeMatMatchOutput>();
// 获取所需材料列表
var pipeLineMats = (from x in db.HJGL_PipeLineMat
join z in db.HJGL_Pipeline on x.PipelineId equals z.PipelineId
join m in db.WBS_UnitWork on z.UnitWorkId equals m.UnitWorkId
join w in db.HJGL_WeldJoint on x.WeldJointId equals w.WeldJointId into weldJoin
from w in weldJoin.DefaultIfEmpty()
where z.ProjectId == projectId && pipelineIds.Contains(z.PipelineId) && x.PrefabricatedComponents != "" //x.PrefabricatedComponents!="" 用于筛选非散件材料
select new
{
PipeLineMat = x,
PipelineCode = z.PipelineCode,
UnitWorkId = z.UnitWorkId,
UnitWorkName = m.UnitWorkName,
WeldJointCode = w == null ? null : w.WeldJointCode
}).ToList();
var materialCodes = pipeLineMats
.Where(x => !string.IsNullOrEmpty(x.PipeLineMat.MaterialCode))
.Select(x => x.PipeLineMat.MaterialCode)
.Distinct()
.ToList();
var materialCode2s = pipeLineMats
.Where(x => !string.IsNullOrEmpty(x.PipeLineMat.MaterialCode2))
.Select(x => x.PipeLineMat.MaterialCode2)
.Distinct()
.ToList();
var libByMaterialCode = db.HJGL_MaterialCodeLib
.Where(x => materialCodes.Contains(x.MaterialCode))
.ToList()
.GroupBy(x => x.MaterialCode)
.ToDictionary(x => x.Key, x => x.First());
var libByCode = db.HJGL_MaterialCodeLib
.Where(x => materialCode2s.Contains(x.Code))
.ToList()
.GroupBy(x => x.Code)
.ToDictionary(x => x.Key, x => x.First());
var requiredMaterials = pipeLineMats.Select(x =>
{
HJGL_MaterialCodeLib lib = null;
if (!string.IsNullOrEmpty(x.PipeLineMat.MaterialCode) && libByMaterialCode.ContainsKey(x.PipeLineMat.MaterialCode))
{
lib = libByMaterialCode[x.PipeLineMat.MaterialCode];
}
else if (!string.IsNullOrEmpty(x.PipeLineMat.MaterialCode2) && libByCode.ContainsKey(x.PipeLineMat.MaterialCode2))
{
lib = libByCode[x.PipeLineMat.MaterialCode2];
}
string code = !string.IsNullOrEmpty(x.PipeLineMat.MaterialCode2) ? x.PipeLineMat.MaterialCode2 : lib?.Code;
return new Tw_PipeMatMatchOutput
{
Id = Guid.NewGuid().ToString(),
PipeLineMatId = x.PipeLineMat.PipeLineMatId,
PipelineId = x.PipeLineMat.PipelineId,
PipelineCode = x.PipelineCode,
UnitWorkId = x.UnitWorkId,
UnitWorkName = x.UnitWorkName,
PrefabricatedComponents = x.PipeLineMat.PrefabricatedComponents,
WeldJointId = x.PipeLineMat.WeldJointId,
WeldJointCode = x.WeldJointCode,
MaterialCode = code,
MatchMaterialCode = x.PipeLineMat.MaterialCode,
Code = code,
HeatNo = lib?.HeatNo,
BatchNo = lib?.BatchNo,
MaterialName = lib?.MaterialName,
MaterialSpec = lib?.MaterialSpec,
MaterialUnit = lib?.MaterialUnit,
MaterialDef = lib?.MaterialDef,
NeedNum = x.PipeLineMat.Number,
};
}).ToList();
var newRequiredMaterials = new List<Tw_PipeMatMatchOutput>();
foreach (string id in pipelineIds)
{
var pipelineMaterials = requiredMaterials.Where(x => x.PipelineId == id).ToList();
if (priorityWeldJoints != null && priorityWeldJoints.ContainsKey(id) && priorityWeldJoints[id] != null && priorityWeldJoints[id].Any())
{
var weldJointIds = priorityWeldJoints[id];
newRequiredMaterials.AddRange(pipelineMaterials
.Where(x => weldJointIds.Contains(x.WeldJointId))
.OrderBy(x => weldJointIds.IndexOf(x.WeldJointId)));
newRequiredMaterials.AddRange(pipelineMaterials
.Where(x => !weldJointIds.Contains(x.WeldJointId)));
}
else
{
newRequiredMaterials.AddRange(pipelineMaterials);
}
}
results = GetMatMatchOutput(newRequiredMaterials, warehouseCode, projectId, true);
return results;
}
}
/// <summary>
/// 根据管线材料匹配结果,获取管线匹配率
/// </summary>
/// <param name="twPipeMatMatch"></param>
/// <returns></returns>
public static List<Tw_PipeMatchOutput> GetPipeMatch(List<Tw_PipeMatMatchOutput> twPipeMatMatch)
{
var result = twPipeMatMatch
.GroupBy(item => new { item.PipelineId, item.PipelineCode, item.UnitWorkName }) // 按 PipelineId 和 PipelineCode 分组
.Select(group => new Tw_PipeMatchOutput
{
PipelineId = group.Key.PipelineId, // 当前组的 PipelineId
PipelineCode = group.Key.PipelineCode, // 当前组的 PipelineCode
UnitWorkName = group.Key.UnitWorkName, // 当前组的 UnitWorkName
SumNeedNum = group.Sum(item => item.NeedNum),
SumMatchNum = group.Sum(item => item.MatchNum),
MatchRate = group.Sum(item => item.MatchNum) > 0 && group.Sum(item => item.NeedNum) > 0 ? (decimal)group.Sum(item => item.MatchNum) / (decimal)group.Sum(item => item.NeedNum) : 0,
MatchRateString = Math.Round((decimal)group.Sum(item => item.MatchNum) / (decimal)group.Sum(item => item.NeedNum) * 100, 2).ToString() + "%"
})
.ToList(); // 转换为 List
return result;
}
}
}