根据运单号获取未出账单详情
此接口需要联系燕文销售申请权限;
*所有请求都需要提供公共参数
参数名 | 类型 | 是否必填 | 描述 |
data | String | 是 | 业务接口参数 |
API调用除了必须包含公共参数外,如果API本身有业务级的参数也必须传入,每个API的业务级参数请参考文档以下章节。
采用AES加密方式,实例方法参见下方附件
测试环境加密KEY:开通权限至燕文客户中心【财务管理-账单接口-未出账单接口-配置接口】沙箱服务配置
正式环境加密KEY:开通权限至燕文客户中心【财务管理-账单接口-未出账单接口-配置接口】正式服务配置
请求方式具体参考接口,用POST方式发起请求。发送参数时请以json方式发送数据。
Content-Type:application/json
字段名 | 类型 | 是否必填 | 描述 |
waybillNumber | String | 是 | 运单号 |
exchangeNumber | String | 否 | 转单号 |
orderNumber | String | 否 | 订单号 |
pickupWarehouse | String | 是 | 发货仓 |
customerCode | String | 是 | 发货账号 |
merchantCode | String | 是 | 商户号 |
calcWeight | Int | 是 | 计费重量 |
weight | Int | 是 | 实重 |
weightUnit | String | 是 | 重量单位 |
expressLength | int | 是 | 长,默认单位cm |
expressWidth | int | 是 | 宽,默认单位cm |
expressHeight | int | 是 | 高,默认单位cm |
timeOfExpress | date | 是 | 账单日期 |
timeOfCalc | datetime | 是 | 计费时间 |
deliveryChargeOfOriginal | decimal | 是 | 折前资费 |
deliveryCharge | decimal | 是 | 折后资费 |
linehaulCharge | decimal | 是 | 干线费 |
surcharge | decimal | 是 | 附加费 |
vatCharge | decimal | 是 | 税费 |
totalAmount | decimal | 是 | 合计金额 |
currency | String | 是 | 币种,默认CNY |
remark | String | 是 | 备注 |
version | int | 是 | 版本号,默认1,账单每调整一次,版本号+1 |
regionName | String | 是 | 目的地 |
productName | String | 是 | 产品名称 |
merchantName | String | 是 | 商户名称 |
expenseType | String | 是 | 交易类型 |
{"data":"BBj85GSylO5g0HFuHFJoLoWvH4h6/kIF0/AmBxh//GqvHLr+Mg1P4HKyp9//7GAwqnLSHDDgkO/neascvLoT34R16kZ84spPfCBo3a+ALewBMwro5mdoSIzf/sO5QM8CYVOZUP9fe1yrdk/hPHABaZmv3sSxwjhLeeU8CWuVXTrf5dhr1qiq6h5wz+6WHGXs+Z9x/1JH3057YSUEKsZw+/zFr2H99OBPtP1WyVahNJTsvsNU9ihl9QQiNe9Ue+g3ZGxa6XKKa0g01xSeKfSIDfPPdkMaQx9+KYJnubVLqTkUPypiL7HDbDVtp/a5nUrP2bhNB6on4AKM7PhU5qqv05Tp4OyjAWD7CDMTJjL+RMhwICpEBmHbCnlztp/Lk3CfH+gDdTx3qHeZNr5QudcRNwIBuAkRRzEyp/ktPjgHIuPU7rFc+5QCqyNvzM0PLkdryYjT0RHRl+Zf80kn2eJAsvFbcCS8UijP79pNhhaLrk3rrWq3wtowQFT62BK8cq3Jf2Tp5a8Du5hEqlUPo/n9j2WUMCF920VK8rsnzk/ZQf05xNOom++rc3xwEdnbqRvrU2PRLklUUO95WpHn/+1hHfQX9xlxNdJj/BmhnygonOA6uTe2L+U+XjtV9x9JsTDNG79x5b0ooWCHaIOtlZBhMe2BCPNjyfQADsBycxDq6bFr2XDS7cJPXd0UUeT3+yYNe1qN0Zan91s0RHM37Z9gMS8JHrfJlBG/q7xE+oLXY30wViiR8UUtOtyCFnClzlSFoxfaiUa2i+mK/QSrIKakmzyQ4GPD1L/ZOic8M1FIY/YeWIr36Nfqvx2kBO6bt7NYy+0sRGN9fd+dqF4OvRuSOc5h+7SptHP8vrIO5nU8i7dQr74M6IUO85XT4dl3ftFu"}
data格式详情:
{"waybillNumber":"UG307850645YP","exchangeNumber":"4205315092612902849687000000637032","orderNumber":"AMTULAD21122860849","pickupWarehouse":"义乌燕文","customerCode":"1234567890","merchantCode":"1234567890","calcWeight":616,"weight":616,"weightUnit":"g","expressLength":0,"expressWidth":0,"expressHeight":0,"expenseType":"TC01","timeOfExpress":"2021-12-29","timeOfCalc":"2021-12-29 09:57:26","deliveryChargeOfOriginal":92.30,"deliveryCharge":88.64,"linehaulCharge":0.29,"surcharge":0.00,"vatCharge":0.00,"totalAmount":88.93,"currency":"USD","remark":"重量调整","version":1,"regionName":"美国","productName":"燕文专线追踪-普货","merchantName":"YW-TEST"}
字段名 | 类型 | 必填 | 描述 |
success | Boolean | 是 | 是否成功 |
code | String | 是 | 消息编码。成功为0,失败且需触发重推为1,失败并不用触发重推为2. |
message | String | 是 | 消息描述 |
data | object | 否 | 接口返回的数据对象 |
{ "success": true, "code": "0", "message": "操作成功", "data": object }
若接口因网络或返回值success为false等导致数据未能推送成功,则该条数据五分钟后重试,若重试五次后依旧未成功则不再重试,需要人工干预方能重新推送。
import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.security.SecureRandom; public class AesUtils { private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding"; /** * AES加密 * * @param content 待加密的内容 * @param encryptKey 加密密钥 * @return 加密后的byte[] * @throws Exception */ public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); secureRandom.setSeed(encryptKey.getBytes("utf-8")); kgen.init(128, secureRandom); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance("AES");// 创建密码器 byte[] byteContent = content.getBytes("utf-8"); cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化 byte[] result = cipher.doFinal(byteContent); return result; // 加密 } /** * AES加密为base 64 code * * @param content 待加密的内容 * @param encryptKey 加密密钥 * @return 加密后的base 64 code * @throws Exception */ public static String aesEncrypt(String content, String encryptKey) throws Exception { return encode(aesEncryptToBytes(content, encryptKey)); } /** * AES解密 * * @param encryptBytes 待解密的byte[] * @param decryptKey 解密密钥 * @return 解密后的String * @throws Exception */ public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG") ; secureRandom.setSeed(decryptKey.getBytes("utf-8")); kgen.init(128, secureRandom); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance("AES");// 创建密码器 cipher.init(Cipher.DECRYPT_MODE, key);// 初始化 byte[] result = cipher.doFinal(encryptBytes); return new String(result,"utf-8"); // 解密 } /** * 将base 64 code AES解密 * * @param encryptStr 待解密的base 64 code * @param decryptKey 解密密钥 * @return 解密后的string * @throws Exception */ public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception { return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(decode(encryptStr), decryptKey); } /** * 解码 * * @param base64 * @return */ public static byte[] decode(final String base64) { if (StringUtils.isEmpty(base64)) { return null; } return Base64.decodeBase64(base64); } /** * 加码 * * @param binaryData * @return */ public static String encode(byte[] binaryData) { return Base64.encodeBase64String(binaryData); } public static void main(String[] args) throws Exception { String content = "我是明文"; String password = "12345678"; // 加密 System.out.println("加密前:" + content); String decode = aesEncrypt(content,password); System.out.println("密文字符串:" + decode); // 解密 System.out.println("解密后:" + aesDecrypt(decode, password)); //不转码会乱码 } }
<?php echo "解密处理:"; $sKey = substr(openssl_digest(openssl_digest('1234567890', 'sha1', true), 'sha1', true), 0, 16); $iv = ''; $decrypted = openssl_decrypt(base64_decode('BBj85GSylO5g0HFuHFJoLoWvH4h6/kIF0/AmBxh//GqvHLr+Mg1P4HKyp9//7GAwqnLSHDDgkO/neascvLoT34R16kZ84spPfCBo3a+ALewBMwro5mdoSIzf/sO5QM8CYVOZUP9fe1yrdk/hPHABaZmv3sSxwjhLeeU8CWuVXTrf5dhr1qiq6h5wz+6WHGXs+Z9x/1JH3057YSUEKsZw+4z4pl7mWRY7FrEmotRpXIkRurY3rgweW4W1cnGlROCY8670nWNhVhIyW4fhJurJJq66mhXKBLyawDJNR1b4nTJJlf+DLyApjwmYiQbcnFZNf7rRDV37yks6wmWHGS0prlrI1T3akrA5Q4mYDSmknfn170+j52Jp9JmSq4YNgZyAcKqYRZJLkgwFaDgd8ai26nVydVM8ovD0LBA4QWen0Lz2aiahP46ODFxDeeY8Y9FtXpW2AGuZyCkCh2xZr0VDmvQQdoLdfaWQfjsR5S8CyuNz0sAya6pH1ndPQYD/SDn66iPMkbG3/7wy37GZxL3ds4Pw9HQ6aGYrONjOGPOz/cgyT5wrPX4alsAz+WIc3lql+pvnM4Kbli0rHNy2SzoxMnJCu1LDjCN//l3PpCXz0LrEq2XKyZB3SxgeBgRJNsHC1tyxhATwUUvgV4bvcIV6kLPxIxatGkH3AmDoc4ZT8mtbSOQi33JQJsBCw7O3uYzKwkORhyQvp0L+Po7iuqF1urGxEJEzQal7jAT7Ps97uvK0tVZUqjlLvKV2YvE6m/v3OWwGBLS2VFrPsmFmo0jyDeJKSmFj36msuaWWJWtXerD53l8+HBDBAFVWPPYVbw7RSZ20fwElHeLu4VF5PU2GnY0SqfY2YqadD9H9bSSd5YmdHuUHL2bQjD3hz7WUX73+1J3KNDl0KhQiEe64XGBnwQ=='), 'AES-128-ECB', $sKey, OPENSSL_RAW_DATA, $iv); echo $decrypted;
#! /usr/bin/python3 # -*- coding:utf-8 -*- import base64 from Crypto.Cipher import AES import hashlib class AesEncryptDecrypt: def __init__(self, key: str): """ Init AES object used by encrypt or decrypt. AES-ECB-PKCS5Padding,the same as AES in java. :param key: Original key. """ self.aes = AES.new(self.get_sha1prng_key(key), AES.MODE_ECB) @staticmethod def get_sha1prng_key(key: str) -> bytes: """ key encrypted with SHA1PRNG,same as Java AES/ECB/PKCS5Padding mode. :param key :Original key. :return: key encrypted with SHA1PRNG,which used in AES Object.128 bits(16 long bytes). """ signature: bytes = hashlib.sha1(key.encode()).digest() signature: bytes = hashlib.sha1(signature).digest() return signature[:16] @staticmethod def pkcs5_padding(data: bytes) -> bytes: """ Padding PKCS5 When pieces of data are required for alignment, fill in bytes. needSize = 16-len(data) % 16 if needSize == 0: needSize = 16 return data + needSize.to_bytes(1, 'little')*needSize :param data:string data need padding. :return: """ ''' num: int = ord(data[-1]) padding_data: str = data + num * chr(num) return padding_data ''' needSize = 16 - len(data) % 16 if needSize == 0: needSize = 16 return data + needSize.to_bytes(1, 'little') * needSize @staticmethod def pkcs5_unpadding(data: str) -> str: """ Unpadding PKCS5 num: int = ord(data[-1]) unpadding_data = data[: -1 * num] return unpadding_data paddingSize = data[-1] return data.rstrip(paddingSize.to_s(1, 'little')) :param data: :return: """ num: int = ord(data[-1]) unpadding_data = data[: -1 * num] return unpadding_data def aes_encrypt(self, data: str) -> str: """ Encrypt string by AES. String to bytes-->padding PKCS5--> Encrypt by AES-->Encrypt by Base64-->Base64 to string. :param data:string needed encrypt. :return:String encrypted. """ # String to bytes. data_bytes = data.encode(encoding='utf-8') # print(f'data_bytes:{data_bytes}') # Padding PKCS5 data_padding = self.pkcs5_padding(data_bytes) # print(f'data_padding:{data_padding}') # Encrypt by AES. encrypt_aes = self.aes.encrypt(data_padding) # print(f'encrypt_aes:{encrypt_aes}') # Encrypt by Base64 encrypt_base64 = base64.b64encode(encrypt_aes) # print(f'encrypt_base64:{encrypt_base64}') # Base64 to string encrypt_data = encrypt_base64.decode(encoding='utf-8') # print(f'encrypt_data:{encrypt_data}') return encrypt_data def aes_decrypt(self, data: str) -> str: """ Encrypt string by AES. String to bytes-->Decrypt by base64-->Decrypt by AES-->bytes to string-->unpadding string :param data:String needed decrypted. :return:String decrypted. """ # String to bytes. decrypt_bytes = data.encode(encoding='utf-8') # print(f'decrypt_bytes:{decrypt_bytes}') # Decrypt by base64. decrypt_base64 = base64.decodebytes(decrypt_bytes) # print(f'decrypt_base64:{decrypt_base64}') # Decrypt by AES decrypt_aes = self.aes.decrypt(decrypt_base64) # print(f'decrypt_aes:{decrypt_aes}') # bytes to string decrypt_string = decrypt_aes.decode(encoding='utf-8') # print(f'decrypt_string:{decrypt_string}') # unpadding string decrypt_data = self.pkcs5_unpadding(decrypt_string) # print(f'decrypt_data:{decrypt_data}') return decrypt_data if __name__ == '__main__': key = '1234567890' aes = AesEncryptDecrypt(key) encrypt_data = 'I am a string that needed to be encrypted!' # data needed decrypted. decrypt_data = 'oDlBOiK6y4prLlWa0qAQnM0C67pgmUyRAPcHlfoYkHqLeXDxuS14yuCvM8G6dvmX' print(aes) print(aes.aes_encrypt(encrypt_data)) print(aes.aes_decrypt(decrypt_data))