2025-11-11 10:14:00 +08:00
|
|
|
|
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";
|
2025-11-15 17:56:13 +08:00
|
|
|
|
private const string DEFAULT_UNIT = "包";
|
2025-11-11 10:14:00 +08:00
|
|
|
|
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表的主键ID(Guid格式的字符串)</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} 的销售出库单记录");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-15 17:56:13 +08:00
|
|
|
|
if (orderHead.Status == 2)
|
2025-11-11 10:14:00 +08:00
|
|
|
|
{
|
|
|
|
|
|
throw new BaseException($"销售出库单 {orderHead.Sheet} 已经推送过,状态为:{orderHead.Status},不允许重复推送");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 18:14:49 +08:00
|
|
|
|
//if (orderHead.TradeType != TRADE_TYPE_SALES_OUTBOUND)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// throw new BaseException($"订单类型 {orderHead.TradeType} 不是销售出库单(TradeType应为1),无法推送");
|
|
|
|
|
|
//}
|
2025-11-11 10:14:00 +08:00
|
|
|
|
|
|
|
|
|
|
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;
|
2025-11-15 17:56:13 +08:00
|
|
|
|
|
2025-11-11 10:14:00 +08:00
|
|
|
|
|
2025-11-15 17:56:13 +08:00
|
|
|
|
// 获取仓库编码
|
|
|
|
|
|
//string warehouseCode = orderHead.WarehouseCode ?? param.FWAREHOUSECODE ?? "";
|
|
|
|
|
|
string warehouseCode = param.FWAREHOUSECODE ;
|
2025-11-11 10:14:00 +08:00
|
|
|
|
// 数据校验
|
|
|
|
|
|
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,
|
2025-11-15 17:56:13 +08:00
|
|
|
|
IsAutoSubmitAndAudit = false,
|
2025-11-11 10:14:00 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 调用金蝶服务保存单据
|
|
|
|
|
|
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()
|
|
|
|
|
|
{
|
2025-11-15 17:56:13 +08:00
|
|
|
|
Fcode= item.Barcode ?? "",
|
2025-11-11 10:14:00 +08:00
|
|
|
|
FRowType = rowType,
|
2025-11-15 17:56:13 +08:00
|
|
|
|
//FMaterialID = new FMaterialID()
|
|
|
|
|
|
//{
|
|
|
|
|
|
// FNumber = item.Barcode ?? ""
|
|
|
|
|
|
//},
|
|
|
|
|
|
//FUnitID = new FUnitID()
|
|
|
|
|
|
//{
|
|
|
|
|
|
// FNumber = item.Unit ?? DEFAULT_UNIT
|
|
|
|
|
|
//},
|
2025-11-11 10:14:00 +08:00
|
|
|
|
FInventoryQty = 0,
|
|
|
|
|
|
FRealQty = realQty,
|
|
|
|
|
|
FDisPriceQty = 0,
|
|
|
|
|
|
FPrice = price,
|
|
|
|
|
|
FTaxPrice = taxPrice,
|
|
|
|
|
|
FIsFree = false,
|
|
|
|
|
|
FOwnerTypeID = OWNER_TYPE,
|
|
|
|
|
|
FOwnerID = new FOwnerID()
|
|
|
|
|
|
{
|
2025-11-15 17:56:13 +08:00
|
|
|
|
FOrgId = orgId
|
|
|
|
|
|
},
|
|
|
|
|
|
FStockID=new FStockID()
|
|
|
|
|
|
{
|
|
|
|
|
|
FNumber = param.FWAREHOUSECODE
|
2025-11-11 10:14:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
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
|
|
|
|
|
|
},
|
2025-11-17 14:36:57 +08:00
|
|
|
|
FBillNo = GenerateBillNo(orderHead.Sheet, orderHead.ConsignTime.Value),
|
2025-11-11 10:14:00 +08:00
|
|
|
|
FDate = dateStr,
|
|
|
|
|
|
FSaleOrgId = new FSaleOrgId()
|
|
|
|
|
|
{
|
2025-11-15 17:56:13 +08:00
|
|
|
|
FOrgId = orgId
|
2025-11-11 10:14:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
FCustomerID = new FCustomerID()
|
|
|
|
|
|
{
|
2025-11-15 17:56:13 +08:00
|
|
|
|
FCustId = customerId
|
2025-11-11 10:14:00 +08:00
|
|
|
|
},
|
2025-11-15 17:56:13 +08:00
|
|
|
|
//FSaleDeptID = new FSaleDeptID()
|
|
|
|
|
|
//{
|
|
|
|
|
|
// FNumber = "02"
|
|
|
|
|
|
//},
|
2025-11-11 10:14:00 +08:00
|
|
|
|
FReceiverID = new FReceiverID()
|
|
|
|
|
|
{
|
|
|
|
|
|
FNumber = customerId
|
|
|
|
|
|
},
|
|
|
|
|
|
FSalesManID = new FSalesManID()
|
|
|
|
|
|
{
|
|
|
|
|
|
FNumber = salesManId
|
|
|
|
|
|
},
|
|
|
|
|
|
FStockOrgId = new FStockOrgId()
|
|
|
|
|
|
{
|
2025-11-15 17:56:13 +08:00
|
|
|
|
FOrgId = orgId
|
2025-11-11 10:14:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
FSettleID = new FSettleID()
|
|
|
|
|
|
{
|
|
|
|
|
|
FNumber = customerId
|
|
|
|
|
|
},
|
|
|
|
|
|
FPayerID = new FPayerID()
|
|
|
|
|
|
{
|
|
|
|
|
|
FNumber = customerId
|
|
|
|
|
|
},
|
|
|
|
|
|
FOwnerTypeIdHead = OWNER_TYPE,
|
2025-11-17 14:36:57 +08:00
|
|
|
|
|
2025-11-11 10:14:00 +08:00
|
|
|
|
FOwnerIdHead = new FOwnerIdHead()
|
|
|
|
|
|
{
|
2025-11-15 17:56:13 +08:00
|
|
|
|
FOrgId = orgId
|
2025-11-11 10:14:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
FCDateOffsetValue = 0,
|
|
|
|
|
|
FIsTotalServiceOrCost = false,
|
2025-11-15 17:56:13 +08:00
|
|
|
|
//F_dmi_Combo = "标准出库",
|
2025-11-11 10:14:00 +08:00
|
|
|
|
SubHeadEntity = new FSubHeadEntity()
|
|
|
|
|
|
{
|
|
|
|
|
|
FSettleCurrID = new FSettleCurrID()
|
|
|
|
|
|
{
|
|
|
|
|
|
FNumber = DEFAULT_CURRENCY
|
|
|
|
|
|
},
|
|
|
|
|
|
FSettleOrgID = new FSettleOrgID()
|
|
|
|
|
|
{
|
2025-11-15 17:56:13 +08:00
|
|
|
|
FOrgId = orgId
|
2025-11-11 10:14:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
FIsIncludedTax = false,
|
|
|
|
|
|
FLocalCurrID = new FLocalCurrID()
|
|
|
|
|
|
{
|
|
|
|
|
|
FNumber = DEFAULT_CURRENCY
|
|
|
|
|
|
},
|
|
|
|
|
|
FExchangeTypeID = new FExchangeTypeID()
|
|
|
|
|
|
{
|
|
|
|
|
|
FNumber = EXCHANGE_TYPE
|
|
|
|
|
|
},
|
|
|
|
|
|
FExchangeRate = 1m,
|
|
|
|
|
|
FIsPriceExcludeTax = true,
|
|
|
|
|
|
FAllDisCount = 0m
|
|
|
|
|
|
},
|
|
|
|
|
|
FEntity = entryList
|
|
|
|
|
|
};
|
2025-11-17 14:36:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* JKXC+年月日+自增ID(三位)--销售出库单
|
|
|
|
|
|
JKXT+年月日+自增ID(三位)--销售退货单
|
|
|
|
|
|
JKCR+年月日+自增ID(三位)--采购入库单
|
|
|
|
|
|
JKCT+年月日+自增ID(三位)--采购退货单
|
|
|
|
|
|
**/
|
|
|
|
|
|
private string GenerateBillNo(int Sheet, DateTime date)
|
|
|
|
|
|
{
|
|
|
|
|
|
string prefix = "JKXC" + date.ToString("yyyyMMdd");
|
|
|
|
|
|
string numberPart = (Sheet > 0 ? Sheet.ToString() : "").PadLeft(3, '0');
|
|
|
|
|
|
numberPart = numberPart.Length > 3 ? numberPart.Substring(numberPart.Length - 3) : numberPart;
|
|
|
|
|
|
// 组合并确保只取最后3位数字
|
|
|
|
|
|
string combined = prefix + numberPart;
|
|
|
|
|
|
return combined;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-11-11 10:14:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|