using MyCode.Project.Domain.Message.Request.KingDee; using MyCode.Project.Domain.Message.Request.KingDee.SaveModel; using MyCode.Project.Domain.Message.Response.KingDee.K3Result; using MyCode.Project.Domain.Message.Response.KingDee.K3Result.Model; using MyCode.Project.Domain.Model; using MyCode.Project.Domain.Repositories; using MyCode.Project.Infrastructure.Common; using MyCode.Project.Infrastructure.Exceptions; using MyCode.Project.Infrastructure.Extensions; using MyCode.Project.OutSideService; using MyCode.Project.Services.IServices; using System; using System.Collections.Generic; using System.Linq; namespace MyCode.Project.Services.Implementation { /// /// 采购入库单服务实现 /// 功能:处理采购入库单推送到金蝶云星空的业务逻辑 /// public class PurchaseStockInService : ServiceBase, IPurchaseStockInService { private const string BILL_TYPE_CODE = "RKD01_SYS"; private const string OWNER_TYPE = "BD_OwnerOrg"; private const string EXCHANGE_TYPE = "HLTX01_SYS"; private const string STOCK_STATUS = "KCZT01_SYS"; private const string DEFAULT_ORG = "100"; private const string DEFAULT_CURRENCY = "PRE001"; private const string DEFAULT_UNIT = "Pcs"; private const string ROW_TYPE_STANDARD = "Standard"; private const string ROW_TYPE_SERVICE = "Service"; private const string FORM_ID = "STK_InStock"; private IPushKingDeeGoodsDocInRepository _pushKingDeeGoodsDocInRepository; private IBusiOrderGoodsDocInRepository _busiOrderGoodsDocInRepository; private IYTKJTShopParameterRepository _yTKJTShopParameterRepository; private IKingDeeService _kingDeeService; public PurchaseStockInService( IPushKingDeeGoodsDocInRepository pushKingDeeGoodsDocInRepository, IBusiOrderGoodsDocInRepository busiOrderGoodsDocInRepository, IYTKJTShopParameterRepository yTKJTShopParameterRepository, IKingDeeService kingDeeService) { _pushKingDeeGoodsDocInRepository = pushKingDeeGoodsDocInRepository; _busiOrderGoodsDocInRepository = busiOrderGoodsDocInRepository; _yTKJTShopParameterRepository = yTKJTShopParameterRepository; _kingDeeService = kingDeeService; } /// /// 推送采购入库单到金蝶云星空 /// /// PushKingDeeGoodsDocIn表的主键ID(Guid格式的字符串) /// 返回金蝶API的响应结果(JSON格式) public string PushPurchaseStockInToKingDee(string id) { var goodsDocIn = _pushKingDeeGoodsDocInRepository .Queryable() .Where(t => id == t.ID.ToString()) .First(); if (goodsDocIn == null) { throw new BaseException($"未找到ID为 {id} 的采购入库单记录"); } if (goodsDocIn.Status ==2 ) { throw new BaseException($"采购入库单 {goodsDocIn.GoodsdocNo} 已经推送过,状态为:{goodsDocIn.Status},不允许重复推送"); } var param = _yTKJTShopParameterRepository .Queryable() .Where(t => t.FDOCUMENTSTATUS == "C") .First(); if (param == null) { throw new BaseException("没有找到已审核的门店参数配置,请联系管理员检查门店参数表"); } if (param.FPURCHASERECEIVING == "0") { throw new BaseException("门店参数配置中采购入库单同步功能未启用,请联系管理员检查门店参数配置"); } if (param.FPURCHASERECEIVING == "1") { var response = PushKingdeePurchaseStockIn(goodsDocIn, param); string result = JsonHelper.ToJson(response); if (response.IsSuccess) { var allRecords = _pushKingDeeGoodsDocInRepository .Queryable() .Where(t => t.GoodsdocNo == goodsDocIn.GoodsdocNo) .ToList(); foreach (var record in allRecords) { record.Status = 2; _pushKingDeeGoodsDocInRepository.Update(record); } } return result; } return ""; } private K3CloudResponseStatus PushKingdeePurchaseStockIn(PushKingDeeGoodsDocIn goodsDocIn, YTKJTShopParameter param) { // 从BusiOrderGoodsDocIn表获取明细数据 var detailList = _busiOrderGoodsDocInRepository .Queryable() .Where(t => t.SourceBillNo == goodsDocIn.GoodsdocNo) .ToList(); if (detailList == null || detailList.Count == 0) { throw new BaseException($"采购入库单 {goodsDocIn.GoodsdocNo} 没有找到明细数据,无法推送"); } var vendorCodes = detailList.Where(d => !string.IsNullOrEmpty(d.VendCode)) .Select(d => d.VendCode) .Distinct() .ToList(); if (vendorCodes.Count > 1) { throw new BaseException($"采购入库单 {goodsDocIn.GoodsdocNo} 明细行中存在不同的供应商编码:{string.Join(",", vendorCodes)},无法推送"); } // 获取第一条明细用于主表信息 var firstDetail = detailList.FirstOrDefault(); if (firstDetail == null) { throw new BaseException($"采购入库单 {goodsDocIn.GoodsdocNo} 明细数据为空,无法推送"); } // 获取采购组织ID string purchaseOrgId = param.FPURCHASEORGID?.ToString() ?? param.FSALEORGID?.ToString() ?? DEFAULT_ORG; // 获取仓库编码 string warehouseCode = firstDetail.WarehouseCode ?? param.FPURCHASINGWAREHOUSECODE ?? ""; // 数据校验 if (string.IsNullOrEmpty(firstDetail.VendCode)) { throw new BaseException($"采购入库单 {goodsDocIn.GoodsdocNo} 供应商编码为空,无法推送"); } if (string.IsNullOrEmpty(warehouseCode)) { throw new BaseException($"采购入库单 {goodsDocIn.GoodsdocNo} 仓库编码为空,无法推送"); } // 构建金蝶API的明细行数据 var entryList = detailList.Select((n, index) => BuildEntryItem(n, param, purchaseOrgId, warehouseCode)).ToList(); if (entryList.Count == 0) { throw new BaseException($"采购入库单 {goodsDocIn.GoodsdocNo} 明细数据转换失败,无法推送"); } // 构建金蝶API的主表数据 var model = BuildMainModel(goodsDocIn, firstDetail, param, purchaseOrgId, entryList); // 构建金蝶API请求对象 BillSave billSave = new BillSave() { Model = model, IsAutoSubmitAndAudit = false, }; // 调用金蝶服务保存单据 var responseStatus = _kingDeeService.Save(FORM_ID, billSave); return responseStatus; } /// /// 构建明细行数据 /// private FPurchaseStockInEntryItem BuildEntryItem(BusiOrderGoodsDocIn detail, YTKJTShopParameter param, string orgId, string warehouseCode) { // 根据入库类型动态设置FRowType(如果入库类型包含"服务"或"费用"等关键字,则设置为Service,否则为Standard) string rowType = ROW_TYPE_STANDARD; if (!string.IsNullOrEmpty(detail.InouttypeName)) { string inoutType = detail.InouttypeName.ToUpper(); if (inoutType.Contains("服务") || inoutType.Contains("费用") || inoutType.Contains("SERVICE") || inoutType.Contains("FEE")) { rowType = ROW_TYPE_SERVICE; } } // 计算折扣后金额(无税金额) decimal? allAmountExceptDisCount = detail.BaceCurrencyNoTaxAmount ?? 0; return new FPurchaseStockInEntryItem() { Fcode = detail.SkuBarcode ?? "", FRowType = rowType, //FMaterialId = new FMaterialId() //{ // FNumber = detail.SkuBarcode ?? "" //}, //FUnitID = new FUnitID() //{ // FNumber = detail.UnitName ?? DEFAULT_UNIT //}, //FMaterialDesc = detail.GoodsName ?? "", FWWPickMtlQty = 0, FRealQty = detail.Quantity ?? 0, //FPriceUnitID = new FPriceUnitID() //{ // FNumber = detail.UnitName ?? DEFAULT_UNIT //}, FPrice = detail.BaceCurrencyNoTaxPrice ?? 0, FDisPriceQty = 0, FStockID = new FStockID() { FNumber = param.FPURCHASINGWAREHOUSECODE }, FStockStatusId = new FStockStatusId() { FNumber = STOCK_STATUS }, FGiveAway = false, FOWNERTYPEID = OWNER_TYPE, FExtAuxUnitQty = 0, FCheckInComing = false, FIsReceiveUpdateStock = false, FInvoicedJoinQty = 0, FPriceBaseQty = detail.Quantity ?? 0, FRemainInStockUnitId = new FRemainInStockUnitId() { FOrgId = param.FPURCHASEORGID.SafeValue().ToString(), }, FBILLINGCLOSE = false, FRemainInStockQty = detail.Quantity ?? 0, FRemainInStockBaseQty = detail.Quantity ?? 0, FAPNotJoinQty = detail.Quantity ?? 0, FTaxPrice = detail.BaceCurrencyWithTaxPrice ?? 0, FOWNERID = new FOwnerId() { FOrgId = orgId }, }; } private PurchaseStockInModel BuildMainModel(PushKingDeeGoodsDocIn goodsDocIn, BusiOrderGoodsDocIn firstDetail, YTKJTShopParameter param, string orgId, List entryList) { string dateStr = goodsDocIn.InOutDate2?.ToString("yyyy-MM-dd HH:mm:ss") ?? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); return new PurchaseStockInModel() { FBillNo= goodsDocIn.GoodsdocNo, FID = 0, FBillTypeID = new FBillTypeID() { FNUMBER = BILL_TYPE_CODE }, FDate = dateStr, IsVerifyBaseDataField=true, FStockOrgId = new FStockOrgId() { FOrgId = orgId }, FDemandOrgId = new FDemandOrgId() { FOrgId = orgId }, FPurchaseOrgId = new FPurchaseOrgId() { FOrgId = orgId }, FSupplierId = new FSupplierId() { FNumber = firstDetail.VendCode }, FOwnerTypeIdHead = OWNER_TYPE, FOwnerIdHead = new FOwnerIdHead() { FOrgId = orgId }, FCDateOffsetValue = 0, FSplitBillType = "A", FInStockFin = new FInStockFin() { FSettleCurrId = new FSettleCurrId() { FNumber = DEFAULT_CURRENCY }, FIsIncludedTax = true, FPriceTimePoint = "1", FLocalCurrId = new FLocalCurrId() { FNumber = DEFAULT_CURRENCY }, FExchangeTypeId = new FExchangeTypeId() { FNumber = EXCHANGE_TYPE }, FExchangeRate = 1m, FISPRICEEXCLUDETAX = true, }, FInStockEntry = entryList }; } } }