From bf5efa6faad3b9cb522a4ebd787544c977d4416c Mon Sep 17 00:00:00 2001 From: richboo111 Date: Fri, 17 Mar 2023 14:16:48 +0800 Subject: [PATCH] 1 --- platformapi/xpyunapi/xpu_model.go | 282 +++++++++++++++++++++++++ platformapi/xpyunapi/xpuapi_test.go | 218 +++++++++++++++++++ platformapi/xpyunapi/xputil.go | 170 +++++++++++++++ platformapi/xpyunapi/xpyunapi.go | 312 ++++++++++++++++++++++++++++ 4 files changed, 982 insertions(+) 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 +}