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

334 lines
12 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 SalesOutboundService : ServiceBase, ISalesOutboundService
{
private const string BILL_TYPE_CODE = "XSCKD01_SYS";
private const string OWNER_TYPE = "BD_OwnerOrg";
private const string EXCHANGE_TYPE = "HLTX01_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 = "SAL_OUTSTOCK";
private const int TRADE_TYPE_SALES_OUTBOUND = 1;
private IPushKingDeeOrderRepository _pushKingDeeOrderRepository;
private IPushKingDeeOrderItemRepository _pushKingDeeOrderItemRepository;
private IYTKJTShopParameterRepository _yTKJTShopParameterRepository;
private IKingDeeService _kingDeeService;
public SalesOutboundService(
IPushKingDeeOrderRepository pushKingDeeOrderRepository,
IPushKingDeeOrderItemRepository pushKingDeeOrderItemRepository,
IYTKJTShopParameterRepository yTKJTShopParameterRepository,
IKingDeeService kingDeeService)
{
_pushKingDeeOrderRepository = pushKingDeeOrderRepository;
_pushKingDeeOrderItemRepository = pushKingDeeOrderItemRepository;
_yTKJTShopParameterRepository = yTKJTShopParameterRepository;
_kingDeeService = kingDeeService;
}
/// <summary>
/// 推送销售出库单到金蝶云星空
/// </summary>
/// <param name="id">PushKingDeeOrder表的主键IDGuid格式的字符串</param>
/// <returns>返回金蝶API的响应结果JSON格式</returns>
public string PushSalesOutboundToKingDee(string id)
{
var orderHead = _pushKingDeeOrderRepository
.Queryable()
.Where(t => id == t.Id.ToString())
.First();
if (orderHead == null)
{
throw new BaseException($"未找到ID为 {id} 的销售出库单记录");
}
if (orderHead.Status != 0)
{
throw new BaseException($"销售出库单 {orderHead.Sheet} 已经推送过,状态为:{orderHead.Status},不允许重复推送");
}
if (orderHead.TradeType != TRADE_TYPE_SALES_OUTBOUND)
{
throw new BaseException($"订单类型 {orderHead.TradeType} 不是销售出库单TradeType应为1无法推送");
}
var param = _yTKJTShopParameterRepository
.Queryable()
.Where(t => t.FSHOPCODE == orderHead.ShopCode)
.Where(t => t.FDOCUMENTSTATUS == "C")
.First();
if (param == null)
{
throw new BaseException($"门店编号:{orderHead.ShopCode},门店名称:{orderHead.ShopName},没有找到对应的门店参数");
}
if (param.FSYNCHRONIZEKINGDEE == "0")
{
throw new BaseException($"门店编号:{orderHead.ShopCode},门店名称:{orderHead.ShopName},金蝶同步功能未启用,请联系管理员检查门店参数配置");
}
if (param.FSYNCHRONIZEKINGDEE == "1")
{
var response = PushKingdeeSalesOutbound(orderHead, param);
string result = JsonHelper.ToJson(response);
if (response.IsSuccess)
{
orderHead.Status = 2;
_pushKingDeeOrderRepository.Update(orderHead);
}
return result;
}
return "";
}
/// <summary>
/// 推送到金蝶云星空
/// </summary>
/// <param name="orderHead">源单信息</param>
/// <param name="param">门店配置</param>
/// <returns></returns>
private K3CloudResponseStatus PushKingdeeSalesOutbound(PushKingDeeOrder orderHead, YTKJTShopParameter param)
{
// 从PushKingDeeOrderItem表获取明细数据
var itemList = _pushKingDeeOrderItemRepository
.Queryable()
.Where(t => orderHead.Id == t.PushKingDeeOrderId)
.ToList();
if (itemList == null || itemList.Count == 0)
{
throw new BaseException($"销售出库单 {orderHead.Sheet} 没有找到明细数据,无法推送");
}
// 获取销售组织ID
string orgId = param.FSALEORGID?.ToString() ?? DEFAULT_ORG;
// 获取仓库编码
string warehouseCode = orderHead.WarehouseCode ?? param.FWAREHOUSECODE ?? "";
// 数据校验
if (string.IsNullOrEmpty(warehouseCode))
{
throw new BaseException($"销售出库单 {orderHead.Sheet} 仓库编码为空,无法推送");
}
// 构建金蝶API的明细行数据
var entryList = itemList.Select(n => BuildEntryItem(n, param, orgId, warehouseCode)).ToList();
if (entryList.Count == 0)
{
throw new BaseException($"销售出库单 {orderHead.Sheet} 明细数据转换失败,无法推送");
}
// 构建金蝶API的主表数据
var model = BuildMainModel(orderHead, param, orgId, entryList);
// 构建金蝶API请求对象
BillSave billSave = new BillSave()
{
Model = model,
IsAutoSubmitAndAudit = true,
};
// 调用金蝶服务保存单据
var responseStatus = _kingDeeService.Save(FORM_ID, billSave);
return responseStatus;
}
/// <summary>
/// 构建明细行数据
/// </summary>
private FSalesOutboundEntryItem BuildEntryItem(PushKingDeeOrderItem item, YTKJTShopParameter param, string orgId, string warehouseCode)
{
string rowType = ROW_TYPE_STANDARD;
// 计算数量(确保为正数)
decimal realQty = Math.Abs(item.SellCount);
// 计算含税单价
decimal taxRate = param.FTAXRATE;
decimal taxPrice = item.SellCount != 0 ? Math.Round(Math.Abs(item.DivideSellTotal) / item.SellCount, 10) : 0;
// 计算无税单价
decimal price = taxRate > 0 && taxPrice > 0 ? Math.Round(taxPrice / (1 + taxRate / 100), 10) : taxPrice;
// 计算金额
decimal allAmountExceptDisCount = Math.Abs(item.DivideSellTotal);
return new FSalesOutboundEntryItem()
{
FRowType = rowType,
FMaterialID = new FMaterialID()
{
FNumber = item.Barcode ?? ""
},
FUnitID = new FUnitID()
{
FNumber = item.Unit ?? DEFAULT_UNIT
},
FInventoryQty = 0,
FRealQty = realQty,
FDisPriceQty = 0,
FPrice = price,
FTaxPrice = taxPrice,
FIsFree = false,
FOwnerTypeID = OWNER_TYPE,
FOwnerID = new FOwnerID()
{
FNumber = orgId
},
FEntryTaxRate = param.FTAXRATE,
FAuxUnitQty = 0,
FExtAuxUnitQty = 0,
FSrcType = "",
FSrcBillNo = "",
FDiscountRate = 0,
FPriceDiscount = 0,
FActQty = realQty,
FSalUnitID = new FSalUnitID()
{
FNumber = item.Unit ?? DEFAULT_UNIT
},
FSALUNITQTY = realQty,
FSALBASEQTY = realQty,
FPRICEBASEQTY = realQty,
FOUTCONTROL = false,
FRepairQty = 0,
FIsOverLegalOrg = false,
FARNOTJOINQTY = realQty,
FQmEntryID = 0,
FConvertEntryID = 0,
FSOEntryId = 0,
FBeforeDisPriceQty = 0,
FSignQty = 0,
FCheckDelivery = false,
FAllAmountExceptDisCount = allAmountExceptDisCount,
FSettleBySon = false,
FBOMEntryId = 0,
F_dmi_Amount = allAmountExceptDisCount,
FMaterialID_Sal = new FMaterialID_Sal()
{
FNUMBER = item.Barcode ?? ""
},
FInStockEntryId = 0,
FReceiveEntryId = 0,
FIsReplaceOut = false,
FVmiBusinessStatus = false
};
}
/// <summary>
/// 构建主表数据
/// </summary>
private SalesOutboundModel BuildMainModel(PushKingDeeOrder orderHead, YTKJTShopParameter param, string orgId, List<FSalesOutboundEntryItem> entryList)
{
string dateStr = orderHead.ConsignTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
string customerId = param.FSALESCUSTOMERS > 0 ? param.FSALESCUSTOMERS.ToString() : "";
string salesManId = param.FSALER.HasValue && param.FSALER.Value > 0 ? param.FSALER.Value.ToString() : "";
return new SalesOutboundModel()
{
FID = 0,
FBillTypeID = new FBillTypeID()
{
FNUMBER = BILL_TYPE_CODE
},
FBillNo = orderHead.Sheet > 0 ? orderHead.Sheet.ToString() : "",
FDate = dateStr,
FSaleOrgId = new FSaleOrgId()
{
FNumber = orgId
},
FCustomerID = new FCustomerID()
{
FNumber = customerId
},
FSaleDeptID = new FSaleDeptID()
{
FNumber = "02"
},
FReceiverID = new FReceiverID()
{
FNumber = customerId
},
FSalesManID = new FSalesManID()
{
FNumber = salesManId
},
FStockOrgId = new FStockOrgId()
{
FNumber = orgId
},
FSettleID = new FSettleID()
{
FNumber = customerId
},
FPayerID = new FPayerID()
{
FNumber = customerId
},
FOwnerTypeIdHead = OWNER_TYPE,
FOwnerIdHead = new FOwnerIdHead()
{
FNumber = orgId
},
FCDateOffsetValue = 0,
FIsTotalServiceOrCost = false,
F_dmi_Combo = "标准出库",
SubHeadEntity = new FSubHeadEntity()
{
FSettleCurrID = new FSettleCurrID()
{
FNumber = DEFAULT_CURRENCY
},
FSettleOrgID = new FSettleOrgID()
{
FNumber = orgId
},
FIsIncludedTax = false,
FLocalCurrID = new FLocalCurrID()
{
FNumber = DEFAULT_CURRENCY
},
FExchangeTypeID = new FExchangeTypeID()
{
FNumber = EXCHANGE_TYPE
},
FExchangeRate = 1m,
FIsPriceExcludeTax = true,
FAllDisCount = 0m
},
FEntity = entryList
};
}
}
}