2025-11-11 10:14:00 +08:00

335 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.OutSideService;
using MyCode.Project.Services.IServices;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MyCode.Project.Services.Implementation
{
/// <summary>
/// 采购入库单服务实现
/// 功能:处理采购入库单推送到金蝶云星空的业务逻辑
/// </summary>
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 = "PUR_PurchaseStockIn";
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;
}
/// <summary>
/// 推送采购入库单到金蝶云星空
/// </summary>
/// <param name="id">PushKingDeeGoodsDocIn表的主键IDGuid格式的字符串</param>
/// <returns>返回金蝶API的响应结果JSON格式</returns>
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 != 0 && goodsDocIn.Status != 1)
{
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.GoodsdocNo == 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 = true,
};
// 调用金蝶服务保存单据
var responseStatus = _kingDeeService.Save(FORM_ID, billSave);
return responseStatus;
}
/// <summary>
/// 构建明细行数据
/// </summary>
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()
{
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,
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()
{
FNumber = detail.UnitName ?? DEFAULT_UNIT
},
FBILLINGCLOSE = false,
FRemainInStockQty = detail.Quantity ?? 0,
FRemainInStockBaseQty = detail.Quantity ?? 0,
FAPNotJoinQty = detail.Quantity ?? 0,
FTaxPrice = detail.BaceCurrencyWithTaxPrice ?? 0,
FEntryTaxRate = detail.TaxRate ?? (decimal?)param.FTAXRATE,
FDiscountRate = 0,
FCostPrice = detail.BaceCurrencyCostPrice ?? 0,
FAuxUnitQty = 0,
FOWNERID = new FOwnerId()
{
FNumber = orgId
},
FSRCBILLTYPEID = detail.SourceBillNo,
FSRCBillNo = detail.SourceBillNo ?? detail.BillNo ?? "",
FAllAmountExceptDisCount = allAmountExceptDisCount,
FPriceDiscount = 0,
FConsumeSumQty = 0,
FBaseConsumeSumQty = 0,
FRejectsDiscountAmount = 0,
FSalOutStockEntryId = 0,
FBeforeDisPriceQty = 0,
FPayableEntryID = 0,
FSUBREQBILLSEQ = 0,
FSUBREQENTRYID = 0,
FBatchNo = detail.BatchNo ?? "",
FSerialNo = detail.SerialNo ?? ""
};
}
private PurchaseStockInModel BuildMainModel(PushKingDeeGoodsDocIn goodsDocIn, BusiOrderGoodsDocIn firstDetail, YTKJTShopParameter param, string orgId, List<FPurchaseStockInEntryItem> entryList)
{
string dateStr = goodsDocIn.InOutDate2?.ToString("yyyy-MM-dd HH:mm:ss") ?? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
return new PurchaseStockInModel()
{
FID = 0,
FBillTypeID = new FBillTypeID()
{
FNUMBER = BILL_TYPE_CODE
},
FDate = dateStr,
FStockOrgId = new FStockOrgId()
{
FNumber = orgId
},
FDemandOrgId = new FDemandOrgId()
{
FNumber = orgId
},
FCorrespondOrgId = new FCorrespondOrgId()
{
FNumber = orgId
},
FPurchaseOrgId = new FPurchaseOrgId()
{
FNumber = orgId
},
FOwnerTypeIdHead = OWNER_TYPE,
FOwnerIdHead = new FOwnerIdHead()
{
FNumber = orgId
},
FCDateOffsetValue = 0,
FSplitBillType = "A",
FSalOutStockOrgId = new FSalOutStockOrgId()
{
FNumber = orgId
},
FInStockFin = new FInStockFin()
{
FSettleOrgId = new FSettleOrgId()
{
FNumber = orgId
},
FSettleCurrId = new FSettleCurrId()
{
FNumber = goodsDocIn.CurrencyCode ?? DEFAULT_CURRENCY
},
FIsIncludedTax = true,
FPriceTimePoint = "1",
FLocalCurrId = new FLocalCurrId()
{
FNumber = goodsDocIn.CurrencyCode ?? DEFAULT_CURRENCY
},
FExchangeTypeId = new FExchangeTypeId()
{
FNumber = EXCHANGE_TYPE
},
FExchangeRate = goodsDocIn.CurrencyRate ?? 1m,
FISPRICEEXCLUDETAX = true,
FAllDisCount = 0m,
FHSExchangeRate = 1m
},
FInStockEntry = entryList
};
}
}
}