一、 準備文件
文檔資料
根據 客户提供文檔《CHINAPAY商户控制枱使用手冊 》登陸(需要客户提供 商户號,操作員號及密碼)
下載
解壓文件後得到如下文件
還需要2個key(MerPrK.key和PgPubk.key)文件,分別是商户私匙和公匙,需要客户簽訂合同後銀聯才提供。
二、安裝部署
1. 將ChinaPay.dll、CPNPC.dll及netpay.dll複製bin下
2. 註冊Chinapay.dll和CPNPC.dll(指令regsvr32 )
例如 regsvr32 F:\工作\MySolution\Web\bin\Chinapay.dll
regsvr32 F:\工作\MySolution\Web\bin\CPNPC.dll
3. Com類型信息轉換為.NET元數據, 需要vs命令提示 工具下運行
tlbimp F:\工作\MySolution\Web\bin\Chinapay.dll /out: F:\工作\MySolution\Web\bin\ ChinaPay_loaf.dll
站點增加引用ChinaPay_loaf.dll 使用的時候引用using ChinaPay_loaf 即可
4. 寫一個類Chinapay.cs放在App_Code下 用於 用户簽名 和驗證,不理解簽名和驗證的看《附3商户技術開發手冊.doc》數字簽名,
Chinapay.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using ChinaPay_loaf ;
using System.Web.UI;
/// <summary>
///Chinapay 的摘要説明
/// </summary>
public class Chinapay
{
string strUrl =HttpContext.Current.Request.PhysicalApplicationPath; //獲取網站根目錄物理路徑
public Chinapay()
{
}
/// <summary>
/// 訂單簽名函數sign
/// </summary>
/// <param name="MerId">商户號,長度為15個字節的數字串,由ChinaPay或清算銀行分配</param>
/// <param name="OrdId">訂單號,長度為16個字節的數字串,由用户系統/網站生成,失敗的訂單號允許重複支付</param>
/// <param name="TransAmt">交易金額,長度為12個字節的數字串,例如:數字串"000000001234"表示12.34元</param>
/// <param name="CuryId">貨幣代碼, 長度為3個字節的數字串,目前只支持人民幣,取值為"156"</param>
/// <param name="TransDate">交易日期,長度為8個字節的數字串,表示格式為:YYYYMMDD</param>
/// <param name="TransType">交易類型,長度為4個字節的數字串,取值範圍為:"0001"和"0002", 其中"0001"表示消費交易,"0002"表示退貨交易</param>
/// <returns>string CheckValue[256] 即NetPayClient根據上述輸入參數生成的商户數字簽名,長度為256字節的字符串</returns>
public string getSign(string MerId, string OrdId, string TransAmt, string CuryId, string TransDate, string TransType)
{
NetPayClientClass npc = new NetPayClientClass(); //實例NetPay簽名
string temp = strUrl + "key\\MerPrK.key";
npc.setMerKeyFile(strUrl + "\\App_Data\\MerPrK.key");
string strChkValue = ""; //chinapay返回的商户數字簽名
strChkValue = npc.sign(MerId, OrdId, TransAmt, CuryId, TransDate, TransType);
return strChkValue.Trim();
}
/// <summary>
/// 對一段字符進行簽名 signData
/// </summary>
/// <param name="MerId">商户號,長度為15個字節的數字串,由ChinaPay分配</param>
/// <param name="SignMsg">用於要簽名的字符串</param>
/// <returns>String CheckValue[256]即NetPayClient根據上述輸入參數生成的商户數字簽名,長度為256字節的字符串</returns>
public string signData(string MerId, string SignMsg)
{
NetPayClientClass npc = new NetPayClientClass(); //實例NetPay簽名
npc.setMerKeyFile(strUrl + "App_Data\\MerPrK.key");
string strChkValueData = "";
strChkValueData = npc.signData(MerId, SignMsg);
return strChkValueData.Trim();
}
/// <summary>
/// 驗證交易應答函數check
/// </summary>
/// <param name="MerId">商户號,長度為15個字節的數字串,由ChinaPay分配</param>
/// <param name="OrdId">訂單號,長度為16個字節的數字串,由商户系統生成,失敗的訂單號允許重複支付</param>
/// <param name="TransAmt">交易金額,長度為12個字節的數字串,例如:數字串"000000001234"表示12.34元</param>
/// <param name="CuryId">貨幣代碼, 長度為3個字節的數字串,目前只支持人民幣,取值為"156"</param>
/// <param name="TransDate">交易日期,長度為8個字節的數字串,表示格式為: YYYYMMDD</param>
/// <param name="TransType">交易類型,長度為4個字節的數字串,取值範圍為:"0001"和"0002", 其中"0001"表示消費交易,"0002"表示退貨交易</param>
/// <param name="OrderStatus">交易狀態,長度為4個字節的數字串。詳見交易狀態碼説明</param>
/// <param name="CheckValue">校驗值,即ChinaPay對交易應答的數字簽名,長度為256字節的字符串</param>
/// <returns>true 表示成功,即該交易應答為ChinaPay所發送,商户根據“交易狀態”進行後續處理;否則表示失敗,即無效應答,商户可忽略該應答</returns>
public bool getCheck(string MerId, string OrdId, string TransAmt, string CuryId, string TransDate, string TransType, string OrderStatus, string CheckValue)
{
NetPayClientClass npc = new NetPayClientClass(); //實例NetPay簽名
npc.setPubKeyFile(strUrl + "App_Data\\PgPubk.key");
string strFlag = "";
bool bolFlag = false;
strFlag = npc.check(MerId, OrdId, TransAmt, CuryId, TransDate, TransType, OrderStatus, CheckValue); // ChkValue 為ChinaPay返回給商户的域段內容
if (strFlag == "0") //“0”表示驗籤成功
bolFlag = true;
return bolFlag;
}
/// <summary>
/// 對一段字符串進行簽名驗證 checkData
/// </summary>
/// <param name="PlainData">用於數字簽名的字符串</param>
/// <param name="CheckValue">校驗值,要驗證的字符串的數字簽名,長度為256字節的字符串</param>
/// <returns>true 表示驗證通過成功;否則表示失敗</returns>
public bool checkData(string PlainData, string CheckValue)
{
NetPayClientClass npc = new NetPayClientClass(); //實例NetPay簽名
npc.setPubKeyFile(strUrl + "App_Data\\PgPubk.key");
string strFlagData = "";
bool bolFlagData = false;
strFlagData = npc.checkData(PlainData, CheckValue);
if (strFlagData == "true")
bolFlagData = true;
return bolFlagData;
}
//
//支付函數
/// <summary>
/// 支付函數
/// </summary>
/// <param name="OrderID">程序 訂單編號</param>
/// <param name="TransAmt">交易錢數</param>
/// <param name="proName">產品名稱 可選</param>
public void GoToPay(string OrderID, string TransAmt, string proName,string gateid)
{
Chinapay cpy = new Chinapay();
//獲取傳遞給銀聯chinapay的各個參數-----------------------------------------------
// string cpyUrl = "http://payment-test.chinapay.com/pay/TransGet"; //測試地址,測試的時候用這個地址,應用到網站時用下面那個地址
string cpyUrl = "http://payment.chinapay.com/pay/TransGet";
string cpyMerId = "808080580112345"; //ChinaPay統一分配給商户的商户號,15位長度,必填
string cpyOrdId = getOrderID(OrderID); //商户提交給ChinaPay的交易訂單號,訂單號的第五至第九位必須是商户號的最後五位,即“12345”;16位長度,必填
string cpyTransAmt = getTransAmt(TransAmt); //訂單交易金額,12位長度,左補0,必填,單位為分,000000000001 表示 12.34 元
string cpyCuryId = "156"; //訂單交易幣種,3位長度,固定為人民幣156,必填
string cpyTransDate = DateTime.Now.ToString("yyyyMMdd"); //訂單交易日期,8位長度,必填,格式yyyyMMdd
string cpyTransType = "0001"; //交易類型,4位長度,必填,0001表示消費交易,0002表示退貨交易
string cpyVersion = "20040916"; //支付接入版本號,808080開頭的商户用此版本,必填,另一版本為"20070129"
string cpyBgRetUrl = "http://test003.abc.cc/Chinapay_Bgreturn.aspx"; //後台交易接收URL,為後台接受應答地址,用於商户記錄交易信息和處理,對於使用者是不可見的,長度不要超過80個字節,必填
string cpyPageRetUrl = "http://test003.abc.cc/Chinapay_Pgreturn.aspx"; //頁面交易接收URL,為頁面接受應答地址,用於引導使用者返回支付後的商户網站頁面,長度不要超過80個字節,必填
string cpyGateId = gateid; //支付網關號,可選,參看銀聯網關類型,如填寫GateId(支付網關號),則消費者將直接進入支付頁面,否則進入網關選擇頁面,可登陸商户管理平台 查看各個銀行的網管號
string cpyPriv1 = proName; //商户私有域,長度不要超過60個字節,商户通過此字段向Chinapay發送的信息,Chinapay依原樣填充返回給商户
string strChkValue = ""; //256字節長的ASCII碼,此次交易所提交的關鍵數據的數字簽名,必填
strChkValue = cpy.getSign(cpyMerId, cpyOrdId, cpyTransAmt, cpyCuryId, cpyTransDate, cpyTransType);
if (strChkValue != "")
{
HttpContext.Current.Response.Write("<form name='chinapayForm' method='post' action='" + cpyUrl + "'>"); //支付地址
HttpContext.Current.Response.Write("<input type='hidden' name='MerId' value='" + cpyMerId + "' />"); //商户號
HttpContext.Current.Response.Write("<input type='hidden' name='OrdId' value='" + cpyOrdId + "' />"); //訂單號
HttpContext.Current.Response.Write("<input type='hidden' name='TransAmt' value='" + cpyTransAmt + "' />"); //支付金額
HttpContext.Current.Response.Write("<input type='hidden' name='CuryId' value='" + cpyCuryId + "' />"); //交易幣種
HttpContext.Current.Response.Write("<input type='hidden' name='TransDate' value='" + cpyTransDate + "' />"); //交易日期
HttpContext.Current.Response.Write("<input type='hidden' name='TransType' value='" + cpyTransType + "' />"); //交易類型
HttpContext.Current.Response.Write("<input type='hidden' name='Version' value='" + cpyVersion + "' />"); //支付接入版本號
HttpContext.Current.Response.Write("<input type='hidden' name='BgRetUrl' value='" + cpyBgRetUrl + "' />"); //後台接受應答地址
HttpContext.Current.Response.Write("<input type='hidden' name='PageRetUrl' value='" + cpyPageRetUrl + "' />"); //為頁面接受應答地址
HttpContext.Current.Response.Write("<input type='hidden' name='GateId' value='" + cpyGateId + "' />"); //支付網關號
HttpContext.Current.Response.Write("<input type='hidden' name='Priv1' value='" + cpyPriv1 + "' />"); //商户私有域,這裏將訂單自增編號放進去了
HttpContext.Current.Response.Write("<input type='hidden' name='ChkValue' value='" + strChkValue + "' />"); //此次交易所提交的關鍵數據的數字簽名
HttpContext.Current.Response.Write("<script>");
HttpContext.Current.Response.Write("document.chinapayForm.submit();");
HttpContext.Current.Response.Write("</script></form>");
}
}
//訂單號
private string getOrderID(string orderID)
{
//程序中的訂單號 案例12022800001
string orderid = string.Format("{0}{1}{2}", orderID.Substring(0, 4), "12345", orderID.Substring(4)); //訂單前四位+商家最後五位+訂單後七位
return orderid;
}
//返回交易金額
private string getTransAmt(string count)
{
string moneyCount = count.ToString().Replace(".", "");
return moneyCount.PadLeft(12, '0');
}
}
5. 下面的需要解決的就是寫四個頁面(支付頁,銀行選擇頁面,後台接受處理頁和用户支付成功後跳轉頁),銀行選擇頁面,主要是自己定義圖標,這裏目的就是為了選擇不同的網關來對應不同的銀行.羅列出常用的銀行。
後台接受頁面
protected void Page_Load(object sender, EventArgs e)
{
Chinapay cpy = new Chinapay();
string TransDate = "",MerId = "",OrdId = "",TransType = "",TransAmt = "",CuryId = "",ChkValue = "",OrderStatus = "",GateId = "",Priv1 = "";
bool bolCheck=false;
TransDate = Request["transdate"].Trim(); //交易日期
MerId = Request["merid"].Trim(); //商家號
OrdId = Request["orderno"].Trim(); //訂單號
TransType = Request["transtype"].Trim();//交易類型
TransAmt = Request["amount"].Trim(); //交易貨幣值
CuryId = Request["currencycode"].Trim(); //交易幣種
ChkValue = Request["checkvalue"].Trim();
OrderStatus = Request["status"].Trim(); //訂單狀態
GateId = Request["GateId"].Trim(); //支付網關號
Priv1 = Request["Priv1"].Trim(); //商户私有域
///檢驗是否是銀聯chinapay返回的交易數據
bolCheck = cpy.getCheck(MerId,OrdId,TransAmt,CuryId,TransDate,TransType,OrderStatus,ChkValue);
if (bolCheck){
if (OrderStatus == "1001")//交易成功
{
string myOrderID = OrdId.Replace("12345", string.Empty);//移除商户號後正好是我係統的訂單號
//更新訂單表
OrderDetailBLL bll = new OrderDetailBLL();
bll.UpdateStateAll(myOrderID);//訂單號
}
}
}
三、需要注意的地方
1. 後台接受頁面驗證簽名後還要判斷下訂單狀態 只有1001狀態才是成功交易,退款其他 要看文檔
2. 商户提交給ChinaPay的交易訂單號,訂單號的第五至第九位必須是商户號的最後五位(04版的,現在07版不用這樣做了),即“12345”;16位長度
例如商家號是: 8080805801123456 則提交的訂單號必須如下形式
例如 123450000000 ;
這裏你要看着 怎麼處理比較好,根據這個訂單號 能對應上,你網站裏面的訂單號
我的訂單號生成規則是
訂單號=年數後2位+月數2位+天2位+五位自增數(不夠補0);
例如 :12030100001; //12年3月1號 第00001個單子,能看出當天的銷售量 也就是説 每天售量最大值是99999,一般小商場足夠用了。