You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

855 lines
27 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using DSWeb.MvcShipping.DAL.MsSysParamSet;
using DSWeb.MvcShipping.Models.MsOpExpress;
using InvokeWebService;
namespace DSWeb.MvcShipping.DAL.MsOpExpressDAL
{
public class SFService
{
//顾客编码
private static string ClientCode = MsSysParamSetDAL.GetData("PARAMNAME='ClientCode'").PARAMVALUE;
//电商加密私钥,校验码,注意保管,不要泄漏
private static string CheckWord = MsSysParamSetDAL.GetData("PARAMNAME='CheckWord'").PARAMVALUE;
//月结卡号
private static string custid = MsSysParamSetDAL.GetData("PARAMNAME='custid'").PARAMVALUE;
//顺丰运单查询接口
private static string OrderUrl = "http://bsp-oisp.sf-express.com/bsp-oisp/sfexpressService";
#region 路由查询
/// <summary>
/// 路由查询
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static List<RouteResponse> GetHttpRouteSearch(RouteSearchService model)
{
//返回路由查询XML请求体
var xml = GetRoutexml(model);
//MD5编码
var pass = Convert.ToBase64String(MD5(xml + CheckWord));
var result = GetRouteack(OrderUrl, "xml=" + xml + "&verifyCode=" + pass);
return result;
}
/// <summary>
/// 路由查询
/// </summary>
/// <param name="add">URL地址</param>
/// <param name="post">编码后的请求体</param>
/// <returns></returns>
private static List<RouteResponse> GetRouteack(string add, string post)
{
var client = new WebClient();
var sXml = "";
var rutoelist = new List<RouteResponse>();
try
{
var postData = Encoding.UTF8.GetBytes(post);
client.Headers.Clear();
//采取POST方式必须加的header如果改为GET方式的话就去掉这句话即可
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
sXml = Encoding.UTF8.GetString(client.UploadData(add, "POST", postData));
//判断返回响应体是否是ERR
if (Convert.ToString(GetNodeValue(sXml, "Head")) == "ERR")
{
sXml = XElement.Parse(sXml).Value;
rutoelist.Add(new RouteResponse {failMessage = XElement.Parse(sXml).Value});
}
//将xml字符串转换为XML文档
var xmlDoc = XDocument.Parse(sXml);
//获取 文档中子代元素 RouteResponse 的所有集合
var nodelist = xmlDoc.Descendants("RouteResponse");
if (nodelist != null)
{
//获取源集合中每个元素和子元素的集合
var pieceareas = nodelist.Elements();
foreach (var item in pieceareas)
//循环添加到路由响应容器集合中
rutoelist.Add(new RouteResponse
{
//获取XML mailno 属性值
mailno = GetXmlNodeValue(sXml, "RouteResponse", "mailno"),
Route = new Route
{
opcode = item.Attribute("opcode").Value,
accept_address = item.Attribute("accept_address").Value,
accept_time = item.Attribute("accept_time").Value,
remark = item.Attribute("remark").Value
}
});
}
}
catch (Exception e)
{
client.Dispose();
rutoelist.Add(new RouteResponse {failMessage = XElement.Parse(sXml).Value});
return rutoelist;
}
client.Dispose();
return rutoelist;
}
/// <summary>
/// 构建路由查询XML请求体
/// </summary>
/// <param name="model">路由查询请求模型</param>
/// <returns></returns>
private static string GetRoutexml(RouteSearchService model)
{
string[] xmls =
{
"<Request service='RouteService' lang='zh-CN'>",
"<Head>" + ClientCode + "</Head>",
"<Body>",
"<RouteRequest",
"tracking_type='" + model.tracking_type + "'",
"method_type='" + model.method_type + "'",
//"check_phoneNo='" + model.check_phoneNo + "'",
"tracking_number='" + model.tracking_number + "'/>",
"</Body>",
"</Request>"
};
var xml = "";
foreach (var s in xmls)
if (xml == "")
xml = s;
else
xml += "\r\n" + s;
return xml;
}
#endregion
#region 下单接口
private static string CreateOrderXML(Order order,cargo cargo)
{
string[] xmls =
{
"<Request service='OrderService' lang='zh-CN'>",
"<Head>" + ClientCode + "</Head>",
"<Body>",
"<Order",
"orderid='" + order.orderid + "'",
"j_company='" + order.j_company + "'",
"j_contact='" + order.j_contact + "'",
"j_tel='" + order.j_tel + "'",
"j_province='" + order.j_province + "'",
"j_city='" + order.j_city + "'",
"j_county='" + order.j_county + "'",
"j_address='" + order.j_address+ "'",
"d_province='" + order.d_province + "'",
"d_city='" + order.d_city + "'",
"d_county='" + order.d_county + "'",
"d_company='" + order.d_company + "'",
"d_contact='" + order.d_contact + "'",
"d_tel='" + order.d_tel + "'",
"d_address='" + order.d_address + "'/>",
"<Cargo name='" + cargo.name + "'></Cargo>",
"</Body>",
"</Request>"
};
var xml = "";
foreach (var s in xmls)
if (xml == "")
xml = s;
else
xml += "\r\n" + s;
return xml;
}
/**
* 获取顺丰下订单接口xml
* @param params
* @return
*/
private static string getOrderServiceRequestXml(Order order)
{
StringBuilder sb = new StringBuilder();
sb.Append("<Request service='OrderService' lang='zh-CN'>");
sb.Append("<Head>" + ClientCode + "</Head>");
sb.Append("<Body>");
sb.Append("<Order").Append(" ");
sb.Append("orderid='" + order.orderid.ToString().Trim() + "" + "'").Append(" ");
//返回顺丰运单号
// sb.Append("is_gen_bill_no='1'").Append(" ");
//寄件方信息
sb.Append("j_company='" + order.j_company + "'").Append(" ");
sb.Append("j_contact='" + order.j_contact + "'").Append(" ");
sb.Append("j_tel='" + order.j_tel + "'").Append(" ");
sb.Append("j_address='" + order.j_province + order.j_city + order.j_county + order.j_address + "'").Append(" ");
//收件方信息
sb.Append("d_company='" + order.d_company + "'").Append(" ");
sb.Append("d_contact='" + order.d_contact.ToString().Trim() + "'").Append(" ");
sb.Append("d_tel='" + order.d_tel.ToString().Trim() + "'").Append(" ");
sb.Append("d_address='" + order.d_address.ToString().Trim() + "'").Append(" ");
sb.Append(" > ");
//货物信息
sb.Append("<Cargo").Append(" ");
sb.Append("name='手机'").Append(">");
//sb.Append("count=1").Append(">");
sb.Append("</Cargo>");
sb.Append("</Order>");
sb.Append("</Body>");
sb.Append("</Request>");
return sb.ToString();
}
public static MsOpSFPrint CreateOrder(Order order,cargo cargo)
{
order.custid = custid;
//返回路由查询XML请求体
var xml = CreateOrderXML(order,cargo);
//MD5编码
var pass = Convert.ToBase64String(MD5(xml + CheckWord));
var result = CreateOrderAction(OrderUrl, "xml=" + xml + "&verifyCode=" + pass);
return result;
}
/// <summary>
/// 下单
/// </summary>
/// <param name="add">URL地址</param>
/// <param name="post">编码后的请求体</param>
/// <returns></returns>
private static MsOpSFPrint CreateOrderAction(string add, string post)
{
var client = new WebClient();
var sXml = "";
var orderResult = new MsOpSFPrint();
try
{
//编码,尤其是汉字,事先要看下抓取网页的编码方式
var postData = Encoding.UTF8.GetBytes(post);
client.Headers.Clear();
//采取POST方式必须加的header如果改为GET方式的话就去掉这句话即可
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
sXml = Encoding.UTF8.GetString(client.UploadData(add, "POST", postData));
if (Convert.ToString(GetNodeValue(sXml, "Head")) == "ERR")
{
sXml = XElement.Parse(sXml).Value;
orderResult.mailno = "ERR";
}
//将xml字符串转换为XML文档
var xmlDoc = XDocument.Parse(sXml);
//获取 文档中子代元素 RouteResponse 的所有集合
var nodelist = xmlDoc.Descendants("OrderResponse");
if (nodelist != null)
{
//获取源集合中每个元素和子元素的集合
//var pieceareas = nodelist.Elements();
orderResult.mailno = GetXmlNodeValue(sXml, "OrderResponse", "mailno");
orderResult.origincode = GetXmlNodeValue(sXml, "OrderResponse", "origincode");
orderResult.destcode = GetXmlNodeValue(sXml, "OrderResponse", "destcode");
//orderResult.filter_result = Convert.ToInt16(GetXmlNodeValue(sXml, "OrderResponse", "filter_result"));
orderResult.orderid = GetXmlNodeValue(sXml, "OrderResponse", "orderid");
orderResult.rlsCode = orderResult.proCode = GetXmlNodeValue(sXml, "rls_info", "rls_code");
//orderResult.invoke_result = orderResult.proCode = GetXmlNodeValue(sXml, "rls_info", "invoke_result");
//orderResult.errorDesc = orderResult.proCode = GetXmlNodeValue(sXml, "rls_info", "errorDesc");
orderResult.proCode = GetXmlNodeValue(sXml, "rls_detail", "proCode");
orderResult.destRouteLabel = GetXmlNodeValue(sXml, "rls_detail", "destRouteLabel");
orderResult.destTeamCode = GetXmlNodeValue(sXml, "rls_detail", "destTeamCode");
orderResult.codingMapping = GetXmlNodeValue(sXml, "rls_detail", "codingMapping");
orderResult.codingMappingOut = GetXmlNodeValue(sXml, "rls_detail", "codingMappingOut");
orderResult.twoDimensionCode = GetXmlNodeValue(sXml, "rls_detail", "twoDimensionCode");
orderResult.abFlag = GetXmlNodeValue(sXml, "rls_detail", "abFlag");
}
}
catch (Exception e)
{
client.Dispose();
//rutoelist.Add(new RouteResponse {failMessage = XElement.Parse(sXml).Value});
//return rutoelist;
}
client.Dispose();
return orderResult;
}
#endregion
#region XML处理
/// <summary>
/// 读取XML资源中的指定节点内容
/// </summary>
/// <param name="source">XML资源</param>
/// <param name="nodeName">节点名称</param>
/// <returns>节点内容</returns>
public static object GetNodeValue(string source, string nodeName)
{
if (source == null || nodeName == null || source == "" || nodeName == "" ||
source.Length < nodeName.Length * 2) return null;
var start = source.IndexOf("<" + nodeName + ">") + nodeName.Length + 2;
var end = source.IndexOf("</" + nodeName + ">");
if (start == -1 || end == -1)
return null;
if (start >= end)
return null;
return source.Substring(start, end - start);
}
/// <summary>
/// 获取xml任意节点中某个属性值
/// </summary>
/// <param name="strXml">xml</param>
/// <param name="strNodeName">节点名称</param>
/// <param name="strValueName">属性名称</param>
/// <returns></returns>
public static string GetXmlNodeValue(string strXml, string strNodeName, string strValueName)
{
try
{
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(strXml);
var xNode = xmlDoc.SelectSingleNode("//" + strNodeName + "");
var strValue = xNode.Attributes[strValueName].Value;
return strValue;
}
catch (Exception ex)
{
//return ex.Message;
return "";
}
}
/// <summary>
/// 获取MD5
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private static byte[] MD5(string str)
{
var result = Encoding.UTF8.GetBytes(str);
MD5 md5 = new MD5CryptoServiceProvider();
var output = md5.ComputeHash(result);
return output;
}
#endregion
#region 路由推送
public static string RoutePushService(RoutePushService model)
{
var xml = GetPushxml(model);
var pass = Convert.ToBase64String(MD5(xml + CheckWord));
var strData = "xml=" + xml + "&verifyCode=" + pass;
var strHeaders = "Content-Type: application/x-www-form-urlencoded\r\n";
var bytePost = Encoding.UTF8.GetBytes(strData);
var byteHeaders = Encoding.UTF8.GetBytes(strHeaders);
var str = GetPushBack(OrderUrl, "xml=" + xml + "&verifyCode=" + pass);
return str;
}
/// <summary>
/// 构建路由推送XML
/// </summary>
/// <param name="model">推送容器</param>
/// <returns></returns>
private static string GetPushxml(RoutePushService model)
{
string[] xmls =
{
"<Request service=RouteService lang=zh-CN>",
"<Body>",
"<WaybillRoute",
"id=" + model.id + "",
"mailno=" + model.mailno + "",
"acceptTime=" + model.acceptTime.ToString("yyyy-MM-dd HH:mm:ss") + "",
"acceptAddress=" + model.acceptAddress + "",
"remark=" + model.remark + "",
"opCode=50/>",
"orderid=" + model.orderid + "/>",
"</Body>",
"</Request>"
};
var xml = "";
foreach (var s in xmls)
if (xml == "")
xml = s;
else
xml += "\r\n" + s;
return xml;
}
/// <summary>
/// 推送
/// </summary>
/// <param name="add">URL</param>
/// <param name="post">数据</param>
/// <returns></returns>
private static string GetPushBack(string add, string post)
{
var pusthclient = new WebClient();
var sXml = "";
try
{
var postData = Encoding.UTF8.GetBytes(post);
pusthclient.Headers.Clear();
//采取POST方式必须加的header如果改为GET方式的话就去掉这句话即可
pusthclient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
sXml = Encoding.UTF8.GetString(pusthclient.UploadData(add, "POST", postData));
//获取Head是否是ERR,若不是直接返回OK
if (Convert.ToString(GetNodeValue(sXml, "Head")) == "ERR")
sXml = XElement.Parse(sXml).Value;
else
sXml = "OK";
}
catch (Exception e)
{
sXml = e.Message;
}
pusthclient.Dispose();
return sXml;
}
#endregion
}
/// <summary>
/// 路由请求实体
/// </summary>
public class RouteSearchService
{
/// <summary>
/// 查询号类别 1运单号查询 2 订单号查询
/// </summary>
public string tracking_type { get; set; }
/// <summary>
/// 查询号 tracking_type=1 则此值是运单号 tracking_type为1=2 此值是订单号
/// </summary>
public string tracking_number { get; set; }
/// <summary>
/// 1 标准路由查询 2定制路由查询
/// </summary>
public string method_type { get; set; }
/// <summary>
/// 收件人或寄件人手机号后四位
/// </summary>
public string check_phoneNo { get; set; }
}
/// <summary>
/// 路由返回报文实体
/// </summary>
public class RouteResponse
{
public string mailno { get; set; }
public Route Route { get; set; }
public string failMessage { get; set; }
}
/// <summary>
/// 路由信息实体
/// </summary>
public class Route
{
public string accept_time { get; set; }
public string accept_address { get; set; }
public string remark { get; set; }
public string opcode { get; set; }
}
/// <summary>
/// 下单实体
/// </summary>
public class Order
{
//客户订单号,必填
public string orderid { get; set; }
//顺丰运单号,条件
public string mailno { get; set; }
//寄件方公司名称,条件
public string j_company { get; set; }
//寄件方联系人,条件
public string j_contact { get; set; }
//寄件方联系电话,条件
public string j_tel { get; set; }
//寄件方手机,否
public string j_mobile { get; set; }
//寄件方所在省份,否
public string j_province { get; set; }
//寄件方所在城市名称,否
public string j_city { get; set; }
//寄件方所在区县,否
public string j_county { get; set; }
//寄件方详细地址,条件
public string j_address { get; set; }
//到件方公司名称,必填
public string d_company { get; set; }
//到件方联系人,必填
public string d_contact { get; set; }
//到件方联系电话,必填
public string d_tel { get; set; }
//到件方手机,否
public string d_mobile { get; set; }
//到件方所在省份,否
public string d_province { get; set; }
//到件方所在城市名称,否
public string d_city { get; set; }
//到件方所在县区,否
public string d_county { get; set; }
//到件方详细地址,是
public string d_address { get; set; }
//月结号,否
public string custid { get; set; }
//付款方式,否
public int pay_method { get; set; }
//快件产品编码,否
public string express_type { get; set; }
//快件包裹数,否
public int parcel_quantity { get; set; }
//客户订单货物总长,否
public decimal cargo_length { get; set; }
//客户订单货物总宽,否
public decimal cargo_width { get; set; }
//客户订单货物高度,否
public decimal cargo_height { get; set; }
//总体积,否
public decimal volume { get; set; }
//订单货物总重量,否
public decimal cargo_total_weight { get; set; }
//要求上门开始时间,否
public DateTime sendstarttime { get; set; }
//是否通过手持端通知顺丰快递员,否
public int is_docall { get; set; }
//是否要求签回单号,否
public string need_return_tracking_no { get; set; }
//顺丰签回运单号,否
public string return_tracking { get; set; }
//温度范围类型,条件
public int temp_range { get; set; }
//业务模板编码,否
public string template { get; set; }
//备注,否
public string remark { get; set; }
//客户自取,否
public int oneself_pickup_flg { get; set; }
//特殊派送类型,否
public string special_delivery_type_code { get; set; }
//特殊派送类型表述,否
public string special_delivery_value { get; set; }
//实名认证流水号,否
public string realname_num { get; set; }
//签回单路由返回,否
public int routelabelForReturn { get; set; }
//路由标签查询服务,否
public int routelabelService { get; set; }
//是否使用国家统一面单号,否
public int is_unified_waybill_no { get; set; }
}
public class cargo
{
//货物名称,必填
public string name { get; set; }
//货物数量,条件
public int count { get; set; }
}
public class OrderResponse
{
//客户订单号,必填
public string orderid { get; set; }
//顺丰运单号,否
public string mailno { get; set; }
//顺丰签回单服务运单号,否
public string return_tracking_no { get; set; }
//原寄地区域代码,否
public string origincode { get; set; }
//目的地区域代码,否
public string destcode { get; set; }
//筛单结果:1:人工确认2可收派3不可以收派
public int filter_result { get; set; }
//若filter_result为3则为必填1收方超范围2寄方超范围3其他原因
public string remark { get; set; }
//代理单号
public string agentMailno { get; set; }
//地址映射码
public string mapping_mark { get; set; }
//url
public string url { get; set; }
//用于第三方支付的url
public string PaymentLink { get; set; }
public rls_info rls_info { get; set; }
}
/// <summary>
/// 下单元素响应
/// </summary>
public class rls_info
{
public string invoke_result { get; set; }
public string rls_code { get; set; }
public string errorDesc { get; set; }
public rls_detail rls_detail { get; set; }
}
public class rls_detail
{
public string waybillNo { get; set; }
//原寄地中转场
public string sourceTransferCode { get; set; }
//原寄地城市代码
public string sourceCityCode { get; set; }
//原寄地网点代码
public string sourceDeptCode { get; set; }
//原寄地单元代码
public string sourceTeamCode { get; set; }
//目的地城市代码
public string deptCityCode { get; set; }
//目的地网点代码
public string deptDeptCode { get; set; }
//目的地代码映射
public string destDeptCodeMapping { get; set; }
//目的地单元代码
public string destTeamCode { get; set; }
//目的地单元区域码映射
public string destTeamCodeMapping { get; set; }
//目的地中转场
public string destTransferCode { get; set; }
//打单时的标签信息
public string destRouteLabel { get; set; }
//产品名称
public string proName { get; set; }
//快件内容
public string cargoTypeCode { get; set; }
//时效代码
public string limitTypeCode { get; set; }
//产品类型
public string expressTypeCode { get; set; }
//入港映射码
public string codingMapping { get; set; }
//出港映射码
public string codingMappingOut { get; set; }
//xb标志
public string xbFlag { get; set; }
//打印标志
public string printFlag { get; set; }
//二维码
public string twoDimensionCode { get; set; }
//时效类型
public string proCode { get; set; }
//打印图标
public string printIcon { get; set; }
//ab标
public string abFlag { get; set; }
//时效类型
public string errMsg { get; set; }
//目的地口岸代码
public string destPortCode { get; set; }
//目的地国别
public string destCountry { get; set; }
//目的地邮编
public string destPostCode { get; set; }
//总价值
public string goodsValueTotal { get; set; }
//币种
public string currencySymbol { get; set; }
//件数
public string goodsNumber { get; set; }
//校验码
public string checkCode { get; set; }
}
/// <summary>
/// 路由推送模型
/// </summary>
public class RoutePushService
{
/// <summary>
/// 路由节点信息编号每一个id 代表一条不同的路由节点信息
/// </summary>
public int id { get; set; }
/// <summary>
/// 顺丰运单号
/// </summary>
public string mailno { get; set; }
/// <summary>
/// 客户订单号
/// </summary>
public string orderid { get; set; }
/// <summary>
/// 路由节点产生的时间格式YYYY-MM-DDHH24:MM:SS
/// </summary>
public DateTime acceptTime { get; set; }
/// <summary>
/// 路由节点发生的城市
/// </summary>
public string acceptAddress { get; set; } = "深圳";
/// <summary>
/// 路由节点具体描述
/// </summary>
public string remark { get; set; } = "上门收件";
/// <summary>
/// 路由节点操作码
/// </summary>
public string opCode { get; set; } = "50";
}
}