diff --git a/platformapi/xpyunapi/xpu_model.go b/platformapi/xpyunapi/xpu_model.go
index 1a6a3402..f6aa6473 100644
--- a/platformapi/xpyunapi/xpu_model.go
+++ b/platformapi/xpyunapi/xpu_model.go
@@ -1 +1,283 @@
package xpyunapi
+
+const (
+ //http返回成功状态码
+ HttpStatusSuccessCode = 200
+ //响应状态码
+ REQUEST_HEADER_ERROR = -1 // 请求头错误
+ REQUEST_PARAM_INVALID = -2 //参数不合法
+ REQUEST_SIGN_FAILED = -3 //参数签名失败
+ REQUEST_USER_NOT_REGISTER = -4 //用户未注册
+
+ SN_USER_NOT_MATCH = 1001 //打印机编号和用户不匹配
+ PRINTER_NOT_REGISTER = 1002 //打印机未注册
+ PRINTER_OFFLINE = 1003 //打印机不在线
+ ADD_ORDER_FAILED = 1004 //添加订单失败
+ ORDER_NOT_FOUND = 1005 //未找到订单信息
+ ORDER_DATE_INVALID = 1006 //订单日期格式或大小不正确
+ PRINT_CONTENT_MORE_THAN_12K_BYTES = 1007 //打印内容不能超过12K
+ PRINTER_RECORD_LOCK_FAIL = 1008 //用户修改打印机记录失败
+ SN_OR_NAME_EMPTY = 1009 // 用户添加打印机时,打印机编号或名称不能为空
+ PRINTER_NUMBER_INVALID = 1010 //打印机设备编号无效
+ PRINTER_EXIST = 1011 //打印机已存在,若当前开放平台无法查询到打印机信息,请联系售后技术支持人员核实
+ PRINTER_EXCEPTION = 1012 //添加打印设备失败,请稍后再试或联系售后技术支持人员
+ ORDER_IDEMPOTENT = 1013 //打印订单时触发幂等性
+ ORDER_IDEMPOTENT_LIMITLEN = 1014 //幂等因子过长
+ LOGO_FORMAT_ERROR = 1016 //LOGO文件格式错误
+ LOGO_SIZE_LARGE = 1017 //LOGO文件超出规定范围
+ LOGO_UPLOAD_TIMES = 1018 //LOGO上传次数超限制
+ LOGO_DELETE_NO_EXIST = 1020 // LOGO删除失败
+ LABEL_MODE_ERROR = 1021 //LOGO上传模式错误
+)
+
+var XpuErrMsg2 = map[string]string{
+ "REQUEST_HEADER_ERROR": "请求头错误",
+ "REQUEST_PARAM_INVALID": "参数不合法",
+ "REQUEST_SIGN_FAILED": "参数签名失败",
+ "REQUEST_USER_NOT_REGISTER": "用户未注册",
+ "SN_USER_NOT_MATCH": "打印机编号和用户不匹配",
+ "PRINTER_NOT_REGISTER": "打印机未注册",
+ "PRINTER_OFFLINE": "打印机不在线",
+ "ADD_ORDER_FAILED": "添加订单失败",
+ "ORDER_NOT_FOUND": "未找到订单信息",
+ "ORDER_DATE_INVALID": "订单日期格式或大小不正确",
+ "PRINT_CONTENT_MORE_THAN_12K_BYTES": "打印内容不能超过12K",
+ "PRINTER_RECORD_LOCK_FAIL": "用户修改打印机记录失败",
+ "SN_OR_NAME_EMPTY": "用户添加打印机时,打印机编号或名称不能为空",
+ "PRINTER_NUMBER_INVALID": "打印机设备编号无效",
+ "PRINTER_EXIST": "打印机已存在",
+ "PRINTER_EXCEPTION": "添加打印设备失败",
+ "ORDER_IDEMPOTENT": "打印订单时触发幂等性",
+ "ORDER_IDEMPOTENT_LIMITLEN": "幂等因子过长",
+ "LOGO_FORMAT_ERROR": "LOGO文件格式错误",
+ "LOGO_SIZE_LARGE": "LOGO文件超出规定范围",
+ "LOGO_UPLOAD_TIMES": "LOGO上传次数超限制",
+ "LOGO_DELETE_NO_EXIST": "LOGO删除失败",
+ "LABEL_MODE_ERROR": "LOGO上传模式错误",
+}
+var XpuErrMsg = map[string]string{
+ "1001": "打印机编号和用户不匹配",
+ "1002": "打印机未注册,尚未添加至云平台",
+ "1003": "打印机不在线",
+ "1004": "添加订单失败",
+ "1005": "未找到订单信息",
+ "1006": "订单日期格式或大小不正确",
+ "1007": "打印内容不能超过12K",
+ "1008": "用户修改打印机记录失败",
+ "1009": "用户添加打印机时,打印机编号或名称不能为空",
+ "1010": "打印机设备编号无效",
+ "1011": "打印机已存在",
+ "1012": "添加打印设备失败",
+ "1013": "打印订单时触发幂等性",
+ "1014": "幂等因子过长",
+ "1016": "LOGO文件格式错误",
+ "1017": "LOGO文件超出规定范围",
+ "1018": "LOGO上传次数超限制",
+ "1020": "LOGO删除失败",
+ "1021": "LOGO上传模式错误",
+}
+
+const (
+ //声音类型 v10版本
+ VoiceTypeV10PersonBig = 0 //真人语音 大
+ VoiceTypeV10PersonMedium = 1 //真人语音 中
+ VoiceTypeV10PersonSmall = 2 //真人语音 小
+ VoiceTypeV10DiDi = 3 //滴滴声
+ VoiceTypeV10Mute = 4 //静音
+
+ //声音类型 其他固件版本
+ VoiceTypeOtherPerson = 0 //真人语音
+ VoiceTypeOtherDiDi = 3 //滴滴声
+ VoiceTypeOtherMute = 4 //静音
+
+ //声音大小,打印机固件版本为非V10.xx的机器支持此参数
+ VolumeLevelBig = 0 //大
+ VolumeLevelMedium = 1 //中
+ VolumeLevelSmall = 2 //小
+ VolumeLevelClose = 3 //关闭
+
+ //切刀控制开关,默认为0,仅用于支持切刀的芯烨云打印机
+ CutterOpen = 0 //开启云端默认设置控制切刀
+ CutterClose = 1 //关闭云端切刀
+
+ //声音播放模式:0-取消订单模式,1-静音模式,2-来单播放模式(默认),3-播报退单语音,4-播报美团来单语音,5-播报饿了么来单语音
+ VoiceCancelOrder = 0 //取消订单模式
+ VoiceMute = 1 //静音模式
+ VoicePlayOrder = 2 //来单播放模式
+ VoiceUserChargeback = 3 //用户申请退单模式
+ VoiceMT = 4 //播报美团来单语音
+ VoiceELM = 5 //播报饿了么来单语音
+
+ //打印模式 默认0
+ ModeCheckYes = 1 //不检查打印机是否在线,直接生成打印订单,并返回打印订单号。如果打印机不在线,订单将缓存在打印队列中,打印机正常在线时会自动打印
+ ModeCheckNo = 0 //或不指定则会检查打印机是否在线,如果不在线 则不生成打印订单,直接返回设备不在线状态码;如果在线则生成打印订单,并返回打印订单号
+ //默认订单过期时间
+ ExpiresInDefault = 86399 //秒
+ //支付方式41-55
+ PayTypeZFB = 41 //支付宝
+ PayTypeWX = 42 //微信
+ PayTypeYunZF = 43 //云支付
+ PayTypeYLCard = 44 //银联刷卡
+ PayTypeYLPay = 45 //银联支付
+ PayTypeMemberCardPay = 46 //会员卡消费
+ PayTypeMemberCardCharge = 47 //会员卡充值
+ PayTypeYiZF = 48 //翼支付
+ PayTypePaymentSuccess = 49 //成功收款
+ PayTypeJLZF = 50 //嘉联支付
+ PayTypeYQB = 51 //壹钱包
+ PayTypeJDZF = 52 //京东支付
+ PayTypeKQZF = 53 //快钱支付
+ PayTypeWZF = 54 //威支付
+ PayTypeXQZF = 55 //享钱支付
+
+ //支付与否
+ PayModeDrawback = 59 //退款
+ PayModeReceipt = 60 //到账
+ PayModeConsume = 61 //消费
+
+ //打印机状态
+ PrinterStateOffline = 0 //离线
+ PrinterStateOnlineNormal = 1 //在线正常
+ PrinterStateOnlineUnusual = 2 //在线异常
+ PrinterStateError = -1 //获取状态出错
+
+)
+
+var (
+ //打印机状态说明
+ PrinterStatus = map[float64]string{
+ PrinterStateOffline: "离线",
+ PrinterStateOnlineNormal: "在线正常",
+ PrinterStateOnlineUnusual: "在线异常",
+ PrinterStateError: "获取状态出错",
+ }
+)
+
+//请求参数
+type RestRequest struct {
+ User string `json:"user"` //开发者ID(芯烨云后台登录账号)
+ UserKey string `json:"-"` //芯烨云后台开发者密钥
+ Timestamp int64 `json:"timestamp"` //当前UNIX时间戳,10位,精确到秒
+ Sign string `json:"sign"` //对参数 user + UKEY + timestamp 拼接后(+号表示连接符)进行SHA1加密得到签名,值为40位小写字符串
+ Debug int `json:"debug"` //debug=1返回非json格式的数据。仅测试时候使用
+}
+
+//响应参数
+type XPYunResp struct {
+ HttpStatusCode int `json:"httpStatusCode"`
+ Content *XPYunRespContent `json:"content"`
+}
+type XPYunRespContent struct {
+ Code int `json:"code"`
+ Msg string `json:"msg"`
+ Data interface{} `json:"data,omitempty"`
+ ServerExecutedTime int `json:"serverExecutedTime"`
+}
+
+type AddPrinterRequestItem struct {
+ Sn string `json:"sn"` //打印机编号
+ Name string `json:"name,omitempty"` //打印机名称
+}
+
+// 添加打印机到开发者账户(可批量)
+type AddPrinterRequest struct {
+ RestRequest `json:",inline"`
+ Items []*AddPrinterRequestItem `json:"items"`
+}
+
+//设置打印机语音类型
+type SetVoiceTypeRequest struct {
+ RestRequest `json:",inline"`
+ Sn string `json:"sn"` //打印机编号
+ VoiceType int `json:"voiceType"` //声音类型:打印机固件版本为V10.xx的机器取值: 0真人语音(大) 1真人语音(中) 2真人语音(小) 3 嘀嘀声 4 静音;其它固件版本的机器取值:0真人语音 3 嘀嘀声 4 静音
+ VolumeLevel int `json:"volumeLevel"` //声音大小:0大 1中 2小 3关闭,说明:打印机固件版本为非V10.xx的机器支持此参数
+}
+
+//打印小票订单
+type PrintRequest struct {
+ RestRequest `json:",inline"`
+ Sn string `json:"sn"` //打印机编号
+ Content string `json:"content"` //打印内容,不能超过12k字节
+ //非必填
+ Copies int `json:"copies,omitempty"` //打印份数,默认为1,取值[1-65535]
+ Cutter int `json:"cutter,omitempty"` //是否支持切刀自定义控制 0采用默认切刀 1采用自定义控制切刀
+ Voice int `json:"voice,omitempty"` //声音播放模式,0-取消订单模式,1-静音模式,2-来单播放模式(默认),3-播报退单语音,4-播报美团来单语音,5-播报饿了么来单语音
+ Mode int `json:"mode,omitempty"` //打印模式,默认为0
+ ExpiresIn int `json:"expiresIn,omitempty"` //订单有效期 单位:秒 取值范围为:0<订单失效时间<24*60*60,使用该参数时,需要将参数mode 设置为1
+ BackurlFlag int `json:"backurlFlag,omitempty"` //回调地址对应标识,必须先在管理后台设置,否则无效
+ PayType int `json:"payType,omitempty"` //41~55: 支付宝 41、微信 42、云支付 43、银联刷卡 44、银联支付 45、会员卡消费 46、会员卡充值 47、翼支付 48、成功收款 49、嘉联支付 50、壹钱包 51、京东支付 52、快钱支付 53、威支付 54、享钱支付 55
+ PayMode int `json:"payMode,omitempty"` //59~61: 退款 59 到账 60 消费 61
+ Money float64 `json:"money,omitempty"` //支付金额 允许保留2位小数
+}
+
+//打印标签订单
+type PrintLabelRequest struct {
+ RestRequest `json:",inline"`
+ Sn string `json:"sn"` //打印机编号
+ Content string `json:"content"` //打印内容,不能超过12k字节
+ //非必填
+ Copies int `json:"copies,omitempty"` //打印份数,默认为1,取值[1-65535]
+ Voice int `json:"voice,omitempty"` //声音播放模式,0-取消订单模式,1-静音模式,2-来单播放模式(默认),3-播报退单语音,4-播报美团来单语音,5-播报饿了么来单语音
+ Mode int `json:"mode,omitempty"` //打印模式,默认为0
+ ExpiresIn int `json:"expiresIn,omitempty"` //订单有效期 单位:秒 取值范围为:0<订单失效时间<24*60*60,使用该参数时,需要将参数mode 设置为1
+ BackurlFlag int `json:"backurlFlag,omitempty"` //回调地址对应标识,必须先在管理后台设置,否则无效
+ PayType int `json:"payType,omitempty"` //41~55: 支付宝 41、微信 42、云支付 43、银联刷卡 44、银联支付 45、会员卡消费 46、会员卡充值 47、翼支付 48、成功收款 49、嘉联支付 50、壹钱包 51、京东支付 52、快钱支付 53、威支付 54、享钱支付 55
+ PayMode int `json:"payMode,omitempty"` //59~61: 退款 59 到账 60 消费 61
+ Money float64 `json:"money,omitempty"` //支付金额 允许保留2位小数
+}
+
+//删除打印机
+type DelPrinterRequest struct {
+ RestRequest `json:",inline"`
+ SnList []string `json:"snlist"` //打印机编号集合
+}
+
+//修改打印机信息
+type UpdPrinterRequest struct {
+ RestRequest `json:",inline"`
+ Sn string `json:"sn"` //打印机编号
+ Name string `json:"name,omitempty"` //打印机名称
+ //非必填
+ CardNo string `json:"cardno"` //打印机流量卡号码
+}
+
+//清空待打印队列
+type EmpPrinterQueueRequest struct {
+ RestRequest `json:",inline"`
+ Sn string `json:"sn"` //打印机编号
+}
+
+// 查询订单状态
+type QueryOrderStateRequest struct {
+ RestRequest `json:",inline"`
+ OrderId string `json:"orderId"` //订单编号,由“打印订单”接口返回
+}
+
+//查询指定打印机某天的订单统计数
+type QueryOrderStatisRequest struct {
+ RestRequest `json:",inline"`
+ Sn string `json:"sn"` //打印机编号
+ Date string `json:"date"` //查询日期,格式YY-MM-DD,如:2016-09-20
+}
+
+//获取指定打印机状态
+type QueryPrinterStatusRequest struct {
+ RestRequest `json:",inline"`
+ Sn string `json:"sn"` //打印机编号
+}
+
+//批量查询打印机状态
+type QueryPrintersStatusRequest struct {
+ RestRequest `json:",inline"`
+ SnList []string `json:"snlist"` //打印机编号集合,一次最多20台
+}
+
+//金额播报 仅用于支持金额播报的芯烨云打印机
+type PlayVoiceRequest struct {
+ RestRequest `json:",inline"`
+ Sn string `json:"sn"` //打印机编号
+ //非必填
+ PayType int `json:"payType"` //支付方式41~55
+ PayMode int `json:"payMode"` //支付与否59~61:退款 59 到账 60 消费 61
+ Money float64 `json:"money"` //支付金额,允许保留2位小数
+}
diff --git a/platformapi/xpyunapi/xpuapi_test.go b/platformapi/xpyunapi/xpuapi_test.go
index 1a6a3402..6751d67b 100644
--- a/platformapi/xpyunapi/xpuapi_test.go
+++ b/platformapi/xpyunapi/xpuapi_test.go
@@ -1 +1,219 @@
package xpyunapi
+
+//
+import (
+ "encoding/json"
+ "fmt"
+ "testing"
+)
+
+//
+const (
+ UserName = "feng.shi@rosy.net.cn" //开发者ID
+ UserKey = "20a24d4332954993b05876e7b3db2a96" //开发者密钥
+ TestPrinterSN = "029JC1ZZD853B4B" //测试打印机SN
+)
+
+//
+var api = New(UserName, UserKey)
+
+//
+//测试格式化商品列表
+func TestFormatPrintOrderItem(t *testing.T) {
+
+ str := FormatPrintOrderItem("测试商品名字", 100, 8.78)
+ fmt.Println(str)
+ request := &PrintRequest{
+ RestRequest: api.GenerateRestRequest(),
+ Sn: TestPrinterSN,
+ Content: str,
+ Copies: 1,
+ Voice: VoicePlayOrder,
+ Mode: ModeCheckYes,
+ }
+ orderID, err := api.Print(request)
+ fmt.Printf("orderID=====%s", orderID)
+ fmt.Printf("err=====%v", err)
+}
+func TestPrint(t *testing.T) {
+ printContent := ""
+ printContent = printContent + "![]()
" + "京西菜市" + "
"
+ printContent += StrRepeat("-", 32)
+ printContent += "
下单时间:2023-03-16 15:30:28"
+ printContent += "
预计送达:2023-03-16 16:30:28"
+ printContent += "
" + "客户姓名:杨玺" + "
" + "客户电话:17235643746"
+ printContent += "
订单编号:7764828754021845" + "
"
+ printContent += "![]()
" + "京西菜市#23" + "
"
+ printContent += "5842160392535156"
+ printContent += "" + "https://www.xpyun.net" + ""
+ printContent += StrRepeat("-", 32)
+ printContent += "客户地址:四川省成都市武侯区双流县金华镇门口大院5栋1单元1104号
"
+ printContent += StrRepeat("-", 32)
+ printContent += "
客户备注:缺货时电话与我沟通 收货人隐私号17882904902——5355,手机号 181****6752" + "
"
+ printContent += StrRepeat("-", 32)
+ printContent = printContent + "
商品列表" + StrRepeat(" ", 6) + "
"
+ printContent += "商品名" + StrRepeat(" ", 2) + "数量" + StrRepeat(" ", 3) + "单价" + StrRepeat(" ", 5) + "小计" + "
"
+ printContent += StrRepeat("-", 32)
+ printContent += FormatPrintOrderItem("[优]猪肉馅约250g/份", 1, 999)
+ printContent += FormatPrintOrderItem("鲜鸡蛋约250g/份", 1, 7.8)
+ printContent += FormatPrintOrderItem("豌豆米-手工剥豆约100g/份", 1, 4)
+ printContent += FormatPrintOrderItem("娃娃菜200g/个", 5, 2)
+ printContent += "" + "共4种9件商品" + "
"
+ printContent += "" + "实付金额: " + "327.83" + "元" + "
"
+
+ printContent = printContent + "
"
+ printContent += StrRepeat("-", 14) + "#23完" + StrRepeat("-", 14)
+ printContent += "
"
+
+ request := PrintRequest{
+ RestRequest: api.GenerateRestRequest(),
+ Sn: TestPrinterSN,
+ Content: printContent,
+ Copies: 1,
+ Voice: 2,
+ Mode: 1,
+ }
+ result, err := api.Print(&request)
+ //序列化
+ reslutJson, _ := json.Marshal(result)
+ var msg = fmt.Sprintf("response result: %+v", string(reslutJson))
+ fmt.Println(msg)
+ fmt.Println(err)
+}
+
+////批量添加打印机
+//func TestAddPrinters(t *testing.T) {
+// request := &AddPrinterRequest{
+// Items: []*AddPrinterRequestItem{{
+// Sn: TestPrinterSN,
+// Name: "京西测试打印机0315",
+// }},
+// RestRequest: api.GenerateRestRequest(),
+// }
+// err := api.AddPrinters(request)
+// fmt.Println(err)
+//}
+//
+////设置打印机语音类型
+//func TestSetVoiceType(t *testing.T) {
+// request := &SetVoiceTypeRequest{
+// RestRequest: api.GenerateRestRequest(),
+// Sn: TestPrinterSN,
+// VoiceType: VoiceTypeV10PersonSmall,
+// VolumeLevel: VolumeLevelSmall,
+// }
+// err := api.SetVoiceType(request)
+// fmt.Println(err)
+//}
+//
+////打印小票订单
+//func TestPrint(t *testing.T) {
+// request := &PrintRequest{
+// RestRequest: api.GenerateRestRequest(),
+// Sn: TestPrinterSN,
+// Content: "-----测试打印小票订单---------" +
+// "kljhsjkfhwiohguoiq" +
+// "ojkahfohsajkohaowjgokaw",
+// Copies: 1,
+// Voice: VoicePlayOrder,
+// Mode: ModeCheckYes,
+// }
+// orderID, err := api.Print(request)
+// fmt.Println(orderID)
+// fmt.Println(err)
+//}
+//
+////删除打印机
+//func TestDelPrinter(t *testing.T) {
+// request := &DelPrinterRequest{
+// RestRequest: api.GenerateRestRequest(),
+// SnList: []string{
+// TestPrinterSN,
+// },
+// }
+// err := api.DelPrinters(request)
+// fmt.Println(err)
+//}
+//
+////修改打印机信息
+//func TestUpdPrinter(t *testing.T) {
+// request := &UpdPrinterRequest{
+// RestRequest: api.GenerateRestRequest(),
+// Sn: "234124",
+// Name: "京西测试打印机3151",
+// }
+// err := api.UpdatePrinter(request)
+// fmt.Println(err)
+//}
+//
+////清空待打印队列
+//func TestEmptyPrinterQueue(t *testing.T) {
+// request := &EmpPrinterQueueRequest{
+// RestRequest: api.GenerateRestRequest(),
+// Sn: TestPrinterSN,
+// }
+// err := api.EmptyPrinterQueue(request)
+// fmt.Println(err)
+//}
+//
+////查询订单状态
+//func TestQueryOrderState(t *testing.T) {
+// request := &QueryOrderStateRequest{
+// RestRequest: api.GenerateRestRequest(),
+// OrderId: "dfhsehsteh",
+// }
+// state, err := api.QueryOrderState(request)
+// fmt.Println(state)
+// fmt.Println(err)
+//}
+//
+////查询指定某天的订单统计数
+//func TestQueryOrderStatis(t *testing.T) {
+// request := &QueryOrderStatisRequest{
+// RestRequest: api.GenerateRestRequest(),
+// Sn: "72624647",
+// Date: "2023-03-15",
+// }
+// printed, waiting, err := api.QueryOrderStatis(request)
+// fmt.Println(printed)
+// fmt.Println(waiting)
+// fmt.Println(err)
+//}
+//
+////查询指定打印机状态
+//func TestQueryPrinterStatus(t *testing.T) {
+// request := &QueryPrinterStatusRequest{
+// RestRequest: api.GenerateRestRequest(),
+// Sn: "7273737",
+// }
+// status, err := api.QueryPrinterStatus(request)
+// fmt.Println(status)
+// fmt.Println(err)
+//}
+//
+////批量查询打印机状态
+//func TestBatchQueryPrinterStatus(t *testing.T) {
+// request := &QueryPrintersStatusRequest{
+// RestRequest: api.GenerateRestRequest(),
+// SnList: []string{
+// TestPrinterSN,
+// "262623738",
+// },
+// }
+// status, err := api.QueryPrintersStatus(request)
+// fmt.Println(status)
+// fmt.Println(err)
+//}
+//
+////金额播报
+//func TestPlayVoice(t *testing.T) {
+// request := &PlayVoiceRequest{
+// RestRequest: api.GenerateRestRequest(),
+// Sn: TestPrinterSN,
+// PayType: PayTypeZFB,
+// PayMode: PayModeReceipt,
+// Money: 25.8,
+// }
+// err := api.PlayVoice(request)
+// fmt.Println(err)
+//}
diff --git a/platformapi/xpyunapi/xputil.go b/platformapi/xpyunapi/xputil.go
index 1a6a3402..cfa69d82 100644
--- a/platformapi/xpyunapi/xputil.go
+++ b/platformapi/xpyunapi/xputil.go
@@ -1 +1,171 @@
package xpyunapi
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "encoding/json"
+ "fmt"
+ "git.rosy.net.cn/baseapi/utils"
+ "golang.org/x/text/encoding/simplifiedchinese"
+ "golang.org/x/text/transform"
+ "io/ioutil"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+)
+
+/**
+ * 发送http的json请求
+ *
+ * @param url 请求url
+ * @param jsonStr 发送的json字符串
+ *
+ */
+func HttpPostJson(url string, data interface{}) *XPYunResp {
+ b, err := json.Marshal(&data)
+ if err != nil {
+ var msg = fmt.Sprintf("json serialize err:%+v", err)
+ fmt.Println(msg)
+ result := XPYunResp{
+ HttpStatusCode: 500,
+ }
+ return &result
+ }
+
+ //var reqMsg = fmt.Sprintf("response result:%+v", string(b))
+ //fmt.Println(reqMsg)
+
+ resp, err := http.Post(url, "application/json", bytes.NewBuffer(b))
+ if err != nil {
+ fmt.Println(err)
+ }
+ defer resp.Body.Close()
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ var msg = fmt.Sprintf("post json error:%+v", err)
+ fmt.Println(msg)
+ }
+
+ result := XPYunResp{
+ HttpStatusCode: resp.StatusCode,
+ }
+
+ var content XPYunRespContent
+ err = json.Unmarshal(body, &content)
+ if err == nil {
+ result.Content = &content
+ } else {
+ var msg = fmt.Sprintf("unmarshal body failed, error:%+v", err)
+ fmt.Println(msg)
+ }
+
+ return &result
+}
+
+/**
+ * 哈稀签名
+ * @param signSource - 源字符串
+ * @return
+ */
+func Sign(signSource string) string {
+ h := sha1.New()
+ h.Write([]byte(signSource))
+ result := fmt.Sprintf("%x", h.Sum(nil))
+ return result
+}
+
+//获得毫秒数
+func GetMillisecond() int64 {
+ return time.Now().UnixNano() / 1e6
+}
+
+/**
+ * 获得字符串重复
+ * @param str - 要进行重复的字符串
+ * @param repeatTimes - 重复次数
+ */
+func StrRepeat(str string, repeatTimes int) string {
+ return strings.Repeat(str, repeatTimes)
+}
+
+func CalcGbkLenForPrint(data string) int {
+ gbk, err := Utf8ToGbk(data)
+ if err != nil {
+ return 0
+ }
+
+ return len(gbk)
+}
+
+func CalcAsciiLenForPrint(data string) int {
+ return len(data)
+}
+
+func Utf8ToGbk(s string) (string, error) {
+ reader := transform.NewReader(bytes.NewReader([]byte(s)), simplifiedchinese.GBK.NewEncoder())
+ d, e := ioutil.ReadAll(reader)
+ if e != nil {
+ return "", e
+ }
+ return string(d), nil
+}
+
+//解析返回数据结构体
+func GetXpuResponse(data interface{}) *XPYunRespContent {
+ retVal := &XPYunRespContent{}
+ resultJson, _ := json.Marshal(data)
+ decoder := json.NewDecoder(bytes.NewBufferString(string(resultJson)))
+ if err := decoder.Decode(&retVal); err != nil {
+ return nil
+ }
+ return retVal
+}
+
+const ROW_MAX_CHAR_LEN = 32
+const MAX_NAME_CHAR_LEN = 20
+const NEX_ROW_CHAR_LEN = 8
+const LAST_ROW_MAX_NAME_CHAR_LEN = 16
+const MAX_QUANTITY_CHAR_LEN = 6
+const MAX_PRICE_CHAR_LEN = 6
+
+const LAST_ROW_MAX_NAME_CHAR_LEN80 = 24 //26
+const ROW_MAX_CHAR_LEN80 = 48
+const MAX_NAME_CHAR_LEN80 = 27
+const MAX_QUANTITY_CHAR_LEN80 = 7
+
+//var orderNameEmpty = StrRepeat(" ", MAX_NAME_CHAR_LEN)
+var orderNameEmpty = StrRepeat(" ", NEX_ROW_CHAR_LEN)
+
+//test函数
+func FormatPrintOrderItem(foodName string, quantity int, price float64) string {
+
+ //foodNameLen := CalcGbkLenForPrint(foodName)
+
+ quantityStr := strconv.Itoa(quantity)
+ quantityLen := CalcAsciiLenForPrint(quantityStr)
+
+ priceStr := fmt.Sprintf("%.2f", price)
+ priceLen := CalcAsciiLenForPrint(priceStr)
+
+ subtotalStr := fmt.Sprintf("%.2f", utils.Int2Float64(quantity)*price)
+ //subtotalLen := CalcAsciiLenForPrint(subtotalStr)
+
+ result := foodName + "
"
+ //mod := foodNameLen % ROW_MAX_CHAR_LEN
+ //if mod <= LAST_ROW_MAX_NAME_CHAR_LEN {
+ // // 保证各个列的宽度固定,不足部分,利用空格填充
+ // result = result + StrRepeat(" ", MAX_NAME_CHAR_LEN-mod)
+ //
+ //} else {
+ // // 另起新行
+ // result = result + "
"
+ // result = result + orderNameEmpty
+ //}
+
+ result += orderNameEmpty + "x" + quantityStr + StrRepeat(" ", MAX_QUANTITY_CHAR_LEN-quantityLen)
+ result += "¥" + priceStr + StrRepeat(" ", MAX_QUANTITY_CHAR_LEN+1-priceLen)
+ result += "¥" + subtotalStr
+ result += "
"
+ return result
+}
diff --git a/platformapi/xpyunapi/xpyunapi.go b/platformapi/xpyunapi/xpyunapi.go
index 1a6a3402..66ca0ebe 100644
--- a/platformapi/xpyunapi/xpyunapi.go
+++ b/platformapi/xpyunapi/xpyunapi.go
@@ -1 +1,313 @@
package xpyunapi
+
+import (
+ "errors"
+ "fmt"
+ "git.rosy.net.cn/baseapi/platformapi"
+ "net/http"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+const (
+ baseURL = "https://open.xpyun.net/api/openapi/xprinter/"
+ signKey = "sign"
+ timestampKey = "timestamp"
+ debugTest = 1 //debug=1返回非json格式的数据,仅测试时候使用
+)
+
+const (
+ ResponseCodeSuccess = 0 //成功
+ ResponseMsgSuccess = "ok"
+)
+
+var (
+ exceedLimitCodes = map[string]int{}
+ canRetryCodes = map[string]int{}
+)
+
+type API struct {
+ locker sync.RWMutex
+ accessToken string
+
+ userName string
+ userKey string
+ client *http.Client
+ config *platformapi.APIConfig
+}
+
+//初始化
+func New(userName, userKey string, config ...*platformapi.APIConfig) *API {
+ curConfig := platformapi.DefAPIConfig
+ if len(config) > 0 {
+ curConfig = *config[0]
+ }
+ return &API{
+ userName: userName,
+ userKey: userKey,
+ client: &http.Client{Timeout: curConfig.ClientTimeout},
+ config: &curConfig,
+ }
+}
+
+//生成签名
+func (a *API) GenerateSign() string {
+ return Sign(a.userName + a.userKey + strconv.FormatInt(GetMillisecond(), 10))
+}
+
+//生成 RestRequest
+func (a *API) GenerateRestRequest() RestRequest {
+ return RestRequest{
+ User: a.userName,
+ UserKey: a.userKey,
+ Timestamp: GetMillisecond(),
+ Sign: a.GenerateSign(),
+ }
+}
+
+func xpyunPostJson(url string, request interface{}) *XPYunResp {
+ result := HttpPostJson(url, request)
+ return result
+}
+
+// 1.添加打印机到开发者账户(可批量)
+func (a *API) AddPrinters(sn, printerName string) error {
+ url := baseURL + "addPrinters"
+ request := &AddPrinterRequest{
+ RestRequest: a.GenerateRestRequest(),
+ Items: []*AddPrinterRequestItem{{
+ Sn: sn,
+ Name: printerName,
+ }},
+ }
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ retVal, _ := resp.Content.Data.(map[string]interface{})
+ failMsg := ""
+ if len(retVal["failMsg"].([]interface{})) > 0 {
+ for _, v := range retVal["failMsg"].([]interface{}) {
+ t := strings.Split(v.(string), ":")
+ failMsg += t[0] + XpuErrMsg[t[1]]
+ }
+ return fmt.Errorf("添加打印机错误:%v", failMsg)
+ }
+ return nil
+}
+
+//2.设置打印机语音类型
+func (a *API) SetVoiceType(sn string, soundSize int) error {
+ url := baseURL + "setVoiceType"
+ request := &SetVoiceTypeRequest{
+ RestRequest: a.GenerateRestRequest(),
+ Sn: sn,
+ VoiceType: VoiceTypeOtherPerson,
+ VolumeLevel: soundSize,
+ }
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ retVal, _ := resp.Content.Data.(map[string]interface{})
+ failMsg := ""
+ if retVal != nil && len(retVal["failMsg"].([]interface{})) > 0 {
+ for _, v := range retVal["failMsg"].([]interface{}) {
+ t := strings.Split(v.(string), ":")
+ failMsg += t[0] + XpuErrMsg[t[1]]
+ }
+ return fmt.Errorf("设置打印机运营类型错误:%v", failMsg)
+ }
+ return nil
+}
+
+//3.打印小票订单
+func (a *API) Print(request *PrintRequest) (string, error) {
+ url := baseURL + "print"
+ request.RestRequest = a.GenerateRestRequest()
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return "0", errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return "0", fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ retVal, _ := resp.Content.Data.(string)
+ if len(retVal) > 0 {
+ return retVal, nil
+ } else {
+ return "0", nil
+ }
+}
+
+// 5.批量删除打印机
+func (a *API) DelPrinters(snList []string) error {
+ url := baseURL + "delPrinters"
+ request := &DelPrinterRequest{
+ RestRequest: a.GenerateRestRequest(),
+ SnList: snList,
+ }
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ retVal, _ := resp.Content.Data.(map[string]interface{})
+ failMsg := ""
+ if retVal != nil && len(retVal["failMsg"].([]interface{})) > 0 {
+ for _, v := range retVal["failMsg"].([]interface{}) {
+ t := strings.Split(v.(string), ":")
+ failMsg += t[0] + XpuErrMsg[t[1]]
+ }
+ return fmt.Errorf("删除打印机错误:%v", failMsg)
+ }
+ return nil
+}
+
+//6.修改打印机信息
+func (a *API) UpdatePrinter(request *UpdPrinterRequest) error {
+ url := baseURL + "updPrinter"
+ request.RestRequest = a.GenerateRestRequest()
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ retVal, _ := resp.Content.Data.(map[string]interface{})
+ failMsg := ""
+ if retVal != nil && len(retVal["failMsg"].([]interface{})) > 0 {
+ for _, v := range retVal["failMsg"].([]interface{}) {
+ t := strings.Split(v.(string), ":")
+ failMsg += t[0] + XpuErrMsg[t[1]]
+ }
+ return fmt.Errorf("修改打印机信息错误:%v", failMsg)
+ }
+ return nil
+}
+
+//7.清空待打印队列
+func (a *API) EmptyPrinterQueue(sn string) error {
+ url := baseURL + "delPrinterQueue"
+ request := &EmpPrinterQueueRequest{
+ RestRequest: a.GenerateRestRequest(),
+ Sn: sn,
+ }
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return fmt.Errorf("%v", XpuErrMsg[resp.Content.Msg])
+ }
+ retVal, _ := resp.Content.Data.(map[string]interface{})
+ failMsg := ""
+ if retVal != nil && len(retVal["failMsg"].([]interface{})) > 0 {
+ for _, v := range retVal["failMsg"].([]interface{}) {
+ t := strings.Split(v.(string), ":")
+ failMsg += t[0] + XpuErrMsg[t[1]]
+ }
+ return fmt.Errorf("清空待打印机队列错误:%v", failMsg)
+ }
+ return nil
+}
+
+//8.查询订单状态
+func (a *API) QueryOrderState(request *QueryOrderStateRequest) (bool, error) {
+ url := baseURL + "queryOrderState"
+ request.RestRequest = a.GenerateRestRequest()
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return false, errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return false, fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ return resp.Content.Data.(bool), nil
+}
+
+//9.查询打印机某天的订单统计数
+func (a *API) QueryOrderStatis(request *QueryOrderStatisRequest) (printed, waiting float64, err error) {
+ url := baseURL + "queryOrderStatis"
+ request.RestRequest = a.GenerateRestRequest()
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return 0, 0, errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return 0, 0, fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ retVal, _ := resp.Content.Data.(map[string]interface{})
+ if retVal != nil {
+ printed = retVal["printed"].(float64)
+ waiting = retVal["waiting"].(float64)
+ return printed, waiting, nil
+ }
+ return 0, 0, nil
+}
+
+//10.获取指定打印机状态
+//* 0、离线 1、在线正常 2、在线不正常
+// * 备注:异常一般是无纸,离线的判断是打印机与服务器失去联系超过30秒
+func (a *API) QueryPrinterStatus(sn string) (interface{}, error) {
+ url := baseURL + "queryPrinterStatus"
+ request := &QueryPrinterStatusRequest{
+ RestRequest: a.GenerateRestRequest(),
+ Sn: sn,
+ }
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return PrinterStateError, errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return PrinterStateError, fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ if resp.Content.Data != nil && resp.Content.Data.(float64) >= 0 {
+ return resp.Content.Data, nil
+ }
+ return PrinterStateError, nil
+}
+
+//11.批量获取指定打印机状态
+func (a *API) QueryPrintersStatus(request *QueryPrintersStatusRequest) ([]float64, error) {
+ url := baseURL + "queryPrintersStatus"
+ request.RestRequest = a.GenerateRestRequest()
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return nil, errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return nil, fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ retVal := []float64{}
+ if resp.Content.Data != nil && resp.Content.Data.(float64) >= 0 {
+ for _, v := range resp.Content.Data.([]interface{}) {
+ retVal = append(retVal, v.(float64))
+ }
+ }
+ return nil, nil
+}
+
+//12.金额播报
+func (a *API) PlayVoice(request *PlayVoiceRequest) error {
+ url := baseURL + "playVoice"
+ request.RestRequest = a.GenerateRestRequest()
+ resp := xpyunPostJson(url, request)
+ if resp.HttpStatusCode != HttpStatusSuccessCode {
+ return errors.New("HTTP请求错误,请检查重试")
+ }
+ if resp.Content.Code != ResponseCodeSuccess {
+ return fmt.Errorf("%v", XpuErrMsg2[resp.Content.Msg])
+ }
+ return nil
+}