From b551b4016c0efea1da50e95a8ec2893528426a2f Mon Sep 17 00:00:00 2001 From: tangweijie <877588133@qq.com> Date: Wed, 28 May 2025 16:19:21 +0800 Subject: [PATCH] init --- .gitignore | 150 +++++ README.md | 35 ++ cmd/main.go | 48 ++ cmd/main/main.go | 48 ++ config/config.yaml | 44 ++ doc/api.md | 294 +++++++++ doc/建新接口代码.txt | 883 +++++++++++++++++++++++++++ doc/新建文本文档.txt | 48 ++ go.mod | 71 +++ go.sum | 225 +++++++ internal/config/config.go | 90 +++ internal/model/base.go | 15 + internal/model/criminal.go | 70 +++ internal/pkg/database/gorm_logger.go | 78 +++ internal/pkg/database/mysql.go | 80 +++ internal/pkg/errcode/errcode.go | 26 + internal/pkg/logger/logger.go | 131 ++++ internal/pkg/metrics/metrics.go | 44 ++ internal/server/socket.go | 397 ++++++++++++ internal/service/criminal.go | 151 +++++ internal/service/interface.go | 28 + 21 files changed, 2956 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 cmd/main.go create mode 100644 cmd/main/main.go create mode 100644 config/config.yaml create mode 100644 doc/api.md create mode 100644 doc/建新接口代码.txt create mode 100644 doc/新建文本文档.txt create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/config/config.go create mode 100644 internal/model/base.go create mode 100644 internal/model/criminal.go create mode 100644 internal/pkg/database/gorm_logger.go create mode 100644 internal/pkg/database/mysql.go create mode 100644 internal/pkg/errcode/errcode.go create mode 100644 internal/pkg/logger/logger.go create mode 100644 internal/pkg/metrics/metrics.go create mode 100644 internal/server/socket.go create mode 100644 internal/service/criminal.go create mode 100644 internal/service/interface.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9980aef --- /dev/null +++ b/.gitignore @@ -0,0 +1,150 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# Build output +/bin/ +/build/ +/dist/ + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Log files +*.log +logs/ + +# Environment variables +.env +.env.local +.env.development +.env.test +.env.production + +# Configuration files with sensitive data +config/local.yaml +config/production.yaml +config/development.yaml +config/*.local.yaml + +# Database files +*.db +*.sqlite +*.sqlite3 + +# Temporary files +tmp/ +temp/ +*.tmp + +# Coverage reports +coverage.txt +coverage.html +coverage.out + +# Air live reload tool +tmp/ + +# Delve debugger +__debug_bin + +# GoLand +.idea/ + +# VS Code +.vscode/ + +# Emacs +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Vim +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# JetBrains IDEs +.idea/ +*.iml +*.ipr +*.iws + +# Local development files +*.local + +# Docker +.dockerignore + +# Kubernetes +*.kubeconfig + +# Certificates and keys +*.pem +*.key +*.crt +*.p12 +*.pfx + +# Backup files +*.bak +*.backup + +# Node modules (if using any frontend tools) +node_modules/ + +# Yarn +yarn-error.log + +# NPM +npm-debug.log* + +# MacOS +.AppleDouble +.LSOverride + +# Windows +Desktop.ini +$RECYCLE.BIN/ + +# Linux +*~ + +# Application specific +# Add your application specific ignores here diff --git a/README.md b/README.md new file mode 100644 index 0000000..07a8a07 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# HospitalPay-Go + +医院支付系统后端服务 + +## 项目结构 + +``` +├── api # API 接口定义 +├── cmd # 主程序入口 +├── config # 配置文件 +├── internal # 内部包 +│ ├── handler # HTTP 处理器 +│ ├── middleware # 中间件 +│ ├── model # 数据模型 +│ ├── repository # 数据仓储层 +│ └── service # 业务逻辑层 +├── pkg # 可以被外部项目引用的包 +└── scripts # 脚本文件 +``` + +## 快速开始 + +1. 安装依赖 +```bash +go mod download +``` + +2. 运行项目 +```bash +go run cmd/main.go +``` + +## 配置说明 + +配置文件位于 `config` 目录下,使用 YAML 格式。 \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..e8af9ae --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "log" + "net/http" + + "github.com/emsoft/HospitalPay-Go/internal/config" + "github.com/emsoft/HospitalPay-Go/internal/pkg/database" + "github.com/emsoft/HospitalPay-Go/internal/pkg/logger" + "github.com/emsoft/HospitalPay-Go/internal/server" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func main() { + // 初始化配置 + if err := config.Init(); err != nil { + log.Fatalf("Failed to initialize config: %v", err) + } + + // 初始化日志 + if err := logger.Init(); err != nil { + log.Fatalf("Failed to initialize logger: %v", err) + } + + // 初始化数据库 + if err := database.Init(); err != nil { + logger.Fatalf("Failed to initialize database: %v", err) + } + defer database.Close() + + // 启动监控服务器 + if config.GlobalConfig.Monitoring.Enabled { + go func() { + http.Handle("/metrics", promhttp.Handler()) + addr := ":" + config.GlobalConfig.Monitoring.PrometheusPort + logger.Infof("Starting monitoring server on %s", addr) + if err := http.ListenAndServe(addr, nil); err != nil { + logger.Fatalf("Failed to start monitoring server: %v", err) + } + }() + } + + // 创建并启动 Socket 服务器 + socketServer := server.NewSocketServer() + if err := socketServer.Start(); err != nil { + logger.Fatalf("Failed to start socket server: %v", err) + } +} diff --git a/cmd/main/main.go b/cmd/main/main.go new file mode 100644 index 0000000..5239064 --- /dev/null +++ b/cmd/main/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "log" + + "github.com/gin-gonic/gin" + "github.com/spf13/viper" +) + +func init() { + // 加载配置文件 + viper.SetConfigName("config") + viper.SetConfigType("yaml") + viper.AddConfigPath("./config") + + if err := viper.ReadInConfig(); err != nil { + log.Fatalf("Error reading config file: %s", err) + } +} + +func main() { + // 创建 Gin 引擎 + r := gin.Default() + + // 注册路由 + setupRoutes(r) + + // 启动服务器 + port := viper.GetString("server.port") + if port == "" { + port = "8080" + } + + if err := r.Run(":" + port); err != nil { + log.Fatalf("Server failed to start: %v", err) + } +} + +func setupRoutes(r *gin.Engine) { + // 健康检查 + r.GET("/health", func(c *gin.Context) { + c.JSON(200, gin.H{ + "status": "ok", + }) + }) + + // TODO: 在这里添加其他路由 +} diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000..0611374 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,44 @@ +server: + port: "8080" + hospital_code: "9999" + mode: "debug" # debug, release, test + read_timeout: 30s + write_timeout: 30s + max_conn_num: 100 + +database: + driver: "mysql" + host: "localhost" + port: 3306 + username: "root" + password: "root" + dbname: "hospital_pay" + charset: "utf8mb4" + parseTime: true + loc: "Local" + max_idle_conns: 10 + max_open_conns: 100 + conn_max_lifetime: 3600s + +redis: + host: localhost + port: 6379 + password: "" + db: 0 + +jwt: + secret: your-secret-key + expire: 24h # token 过期时间 + +log: + level: "debug" # debug, info, warn, error, fatal + format: "json" # json, text + output_path: "logs/app.log" + max_size: 500 # MB + max_age: 28 # 天 + max_backups: 10 + compress: true + +monitoring: + enabled: true + prometheus_port: "9090" \ No newline at end of file diff --git a/doc/api.md b/doc/api.md new file mode 100644 index 0000000..0425586 --- /dev/null +++ b/doc/api.md @@ -0,0 +1,294 @@ +# 医院支付系统接口文档 + +## 目录 +- [1. 概述](#1-概述) +- [2. 通信协议](#2-通信协议) +- [3. 接口列表](#3-接口列表) +- [4. 错误码说明](#4-错误码说明) +- [5. 数据结构](#5-数据结构) +- [6. 对接示例](#6-对接示例) + +## 1. 概述 + +### 1.1 文档说明 +本文档详细描述了医院支付系统的接口规范,包括接口定义、参数说明、错误码等信息。 + +### 1.2 修订记录 +| 版本号 | 修订日期 | 修订说明 | +|--------|----------|----------| +| v1.0.0 | 2024-03-25 | 初始版本 | + +## 2. 通信协议 + +### 2.1 基本信息 +- 通信方式:Socket TCP +- 字符编码:UTF-8 +- 数据格式:JSON +- 端口配置:通过配置文件指定 + +### 2.2 消息格式 + +#### 请求消息格式 +\`\`\` +长度(4位) + 功能码(4位) + 医院编码(4位) + 时间戳(19位) + JSON数据 +\`\`\` + +示例: +\`\`\` +005700059999FJJXYY712024-08-01 09:00:44{"FCode":"3516022343"} +\`\`\` + +#### 响应消息格式 +\`\`\` +长度(4位) + JSON数据 +\`\`\` + +示例: +\`\`\` +0216{"ResultCode":"0000","ResultData":{"FCode":"3516022343","FName":null,"AmountA":414.54}} +\`\`\` + +## 3. 接口列表 + +### 3.1 入院登记 +- **功能码**: 0001 +- **功能说明**: 病人入院时进行登记 +- **请求参数**: +\`\`\`json +{ + "FCode": "string" // 病人编号 +} +\`\`\` +- **响应参数**: +\`\`\`json +{ + "ResultCode": "string", // 结果代码 + "ResultData": { + "FCode": "string", // 病人编号 + "FName": "string", // 病人姓名 + "AmountA": decimal, // A类金额 + "AmountB": decimal, // B类金额 + "AmountC": decimal, // C类金额 + "BankAccNo": "string", // 银行账号 + "BankAmount": decimal, // 银行余额 + "Fflag": int, // 状态标志 + "Flimitflag": int, // 限制标志 + "Flimitamt": decimal // 限制金额 + } +} +\`\`\` + +### 3.2 消费额度查询 +- **功能码**: 0002 +- **功能说明**: 查询病人当月消费额度 +- **请求参数**: +\`\`\`json +{ + "FCode": "string" // 病人编号 +} +\`\`\` +- **响应参数**: +\`\`\`json +{ + "AmountA": decimal, // A类消费金额 + "AmountB": decimal, // B类消费金额 + "FreeAmountA": decimal, // A类可用金额 + "FreeAmountB": decimal, // B类可用金额 + "Checkflag": int, // 检查标志 + "FCode": "string", // 病人编号 + "FCriminal": "string", // 病人姓名 + "Flag": int // 状态标志 +} +\`\`\` + +### 3.3 出院处理 +- **功能码**: 0003 +- **功能说明**: 病人出院时的处理 +- **请求参数**: +\`\`\`json +{ + "FCode": "string" // 病人编号 +} +\`\`\` +- **响应参数**: +\`\`\`json +{ + "Result": boolean, // 处理结果 + "ReMsg": "string" // 结果消息 +} +\`\`\` + +### 3.4 消费记录 +- **功能码**: 0004 +- **功能说明**: 记录病人消费信息 +- **请求参数**: +\`\`\`json +{ + "FCode": "string", // 病人编号 + "InvoiceNo": "string", // 发票号 + "AmountA": decimal, // A类金额 + "AmountB": decimal, // B类金额 + "Amount": decimal, // 总金额 + "FreeAmountA": decimal, // A类可用金额 + "FreeAmountB": decimal, // B类可用金额 + "CrtDate": "string", // 创建日期 + "FCriminal": "string", // 病人姓名 + "CardCode": "string", // 卡号 + "OrderId": int // 订单ID +} +\`\`\` +- **响应参数**: +\`\`\`json +{ + "ResultCode": "string", // 结果代码 + "ResultMsg": "string" // 结果消息 +} +\`\`\` + +### 3.5 实时余额查询 +- **功能码**: 0005 +- **功能说明**: 查询病人实时余额 +- **请求参数**: +\`\`\`json +{ + "FCode": "string" // 病人编号 +} +\`\`\` +- **响应参数**: 同入院登记响应 + +### 3.6 发票同步 +- **功能码**: 0006 +- **功能说明**: 同步发票信息 +- **请求参数**: +\`\`\`json +{ + "InvoiceList": [ + "string" // 发票号列表 + ] +} +\`\`\` +- **响应参数**: +\`\`\`json +{ + "ResultCode": "string", + "ResultData": [ + { + "BankFlag": int, // 银行标志 + "CAmount": decimal, // 金额 + "FCode": "string", // 病人编号 + "Origid": "string", // 原始ID + "SendDate": "string" // 发送日期 + } + ] +} +\`\`\` + +## 4. 错误码说明 + +| 错误码 | 说明 | 处理建议 | +|--------|------|----------| +| 0000 | 成功 | - | +| 0005 | 未找到病人信息 | 检查病人编号是否正确 | +| 0006 | 入院处理失败 | 检查病人状态 | +| 0007 | 病人已入院 | 无需重复入院 | +| 0008 | 系统异常 | 联系系统管理员 | + +## 5. 数据结构 + +### 5.1 金额说明 +- AmountA: A类金额,用于... +- AmountB: B类金额,用于... +- AmountC: C类金额,用于... +- FreeAmountA: A类可用金额 +- FreeAmountB: B类可用金额 + +### 5.2 状态标志说明 +- Fflag: 0-正常,1-已入院 +- Flimitflag: 0-无限制,1-有限制 +- Checkflag: 检查标志 +- BankFlag: 银行标志 + +## 6. 对接示例 + +### 6.1 Go语言示例代码 + +\`\`\`go +package main + +import ( + "encoding/json" + "fmt" + "net" + "time" +) + +// 发送请求 +func sendRequest(conn net.Conn, functionCode string, hospitalCode string, data interface{}) error { + jsonData, err := json.Marshal(data) + if err != nil { + return err + } + + // 构造消息 + message := fmt.Sprintf("%04d%s%s%s%s", + len(jsonData)+27, // 总长度 + functionCode, // 功能码 + hospitalCode, // 医院编码 + time.Now().Format("2006-01-02 15:04:05"), + string(jsonData)) + + // 发送消息 + _, err = conn.Write([]byte(message)) + return err +} + +// 接收响应 +func receiveResponse(conn net.Conn) (string, error) { + buffer := make([]byte, 4096) + n, err := conn.Read(buffer) + if err != nil { + return "", err + } + + response := string(buffer[:n]) + // 解析响应:前4位为长度,之后为JSON数据 + return response[4:], nil +} + +func main() { + // 建立连接 + conn, err := net.Dial("tcp", "192.168.1.1:8080") + if err != nil { + panic(err) + } + defer conn.Close() + + // 构造请求数据 + reqData := map[string]string{ + "FCode": "3516022343", + } + + // 发送请求 + err = sendRequest(conn, "0001", "9999", reqData) + if err != nil { + panic(err) + } + + // 接收响应 + response, err := receiveResponse(conn) + if err != nil { + panic(err) + } + + fmt.Println("Response:", response) +} +\`\`\` + +### 6.2 注意事项 + +1. 数据传输编码统一使用 UTF-8 +2. 金额字段使用 decimal 类型,避免浮点数精度问题 +3. 时间戳格式:2006-01-02 15:04:05 +4. 建议每次请求建立新的连接 +5. 注意处理连接超时情况 +6. 响应码为"0000"时表示处理成功 \ No newline at end of file diff --git a/doc/建新接口代码.txt b/doc/建新接口代码.txt new file mode 100644 index 0000000..68000c6 --- /dev/null +++ b/doc/建新接口代码.txt @@ -0,0 +1,883 @@ +// SocketServiceForm.ClientConnection +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using JXHospitalWSBLL; +using SocketServiceForm; + +public class ClientConnection +{ + private Thread threadClient; + + private Socket socket; + + private Form1 frmMain; + + private bool doesClose; + + public ClientConnection(Form1 f1, Socket socket) + { + frmMain = f1; + this.socket = socket; + threadClient = new Thread(MoniterMsg); + threadClient.IsBackground = true; + threadClient.Start(); + } + + private void MoniterMsg() + { + while (!doesClose) + { + try + { + byte[] byteMsgRec = new byte[4194304]; + int length = socket.Receive(byteMsgRec, byteMsgRec.Length, SocketFlags.None); + if (length > 0) + { + string strMsgRec = Encoding.UTF8.GetString(byteMsgRec, 0, length); + ShowMsg("从" + socket.RemoteEndPoint.ToString() + "接收消息:" + strMsgRec); + strMsgRec.Substring(0, 4); + string _JXsendObj = strMsgRec.Substring(4, strMsgRec.Length - 4); + string _fun = _JXsendObj.Substring(0, 4); + string _obj = _JXsendObj.Substring(35, _JXsendObj.Length - 35); + switch (_fun) + { + case "0001": + SendMsg(JXHospitalBLL.CriminalIn(_obj)); + break; + case "0002": + SendMsg(JXHospitalBLL.CriminalConsumedQuota(_obj)); + break; + case "0003": + SendMsg(JXHospitalBLL.CriminalOut(_obj)); + break; + case "0004": + SendMsg(JXHospitalBLL.CriminalConsume(_obj)); + break; + case "0005": + SendMsg(JXHospitalBLL.RealTimeBalance(_obj)); + break; + case "0006": + SendMsg(JXHospitalBLL.SynInvoiceResult(_obj)); + break; + case "0007": + SendMsg(JXHospitalBLL.MonitorSocketResult(_obj)); + break; + case "0008": + SendMsg(JXHospitalBLL.CancelOrderResult(_obj)); + break; + } + } + Close(); + } + catch (Exception ex) + { + if (socket != null) + { + ShowErr("客户端" + socket.RemoteEndPoint.ToString() + "断开连接:", ex); + } + frmMain.RemoveListItem(socket.RemoteEndPoint.ToString()); + return; + } + } + } + + private void ShowErr(string msg, Exception ex) + { + frmMain.ShowErr(msg, ex); + } + + private void ShowMsg(string msg) + { + frmMain.ShowReqTxt(msg); + } + + public void SendMsg(string msg) + { + try + { + byte[] msgSendByte = Encoding.UTF8.GetBytes(Encoding.UTF8.GetBytes(msg).Length.ToString("0000") + msg); + socket.Send(msgSendByte); + ShowMsg("发送消息:" + Encoding.UTF8.GetString(msgSendByte, 0, msgSendByte.Length)); + } + catch (Exception ex) + { + ShowErr("发送消息:", ex); + } + } + + public void Close() + { + doesClose = true; + threadClient.Abort(); + socket.Shutdown(SocketShutdown.Both); + socket.Close(); + socket = null; + } +} + + +// JXHospitalWSBLL.JXHospitalBLL +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Linq; +using System.Web.Script.Serialization; +using JXHospitalWSBLL; +using JXHospitalWSDAL; + +public class JXHospitalBLL +{ + public static string GetSocketIp() + { + return ConfigurationManager.ConnectionStrings["SocketIP"].ConnectionString; + } + + public static string GetSocketPort() + { + return ConfigurationManager.ConnectionStrings["SocketPort"].ConnectionString; + } + + public static string CriminalIn(string FCode) + { + ResponCriminalIn re = new ResponCriminalIn(); + JavaScriptSerializer jss = new JavaScriptSerializer(); + ReqFCode _fcode = jss.Deserialize(FCode); + string errorMsg = ""; + string errorCode = ""; + try + { + using JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom(); + re.ResultData = (from b in db.T_Criminal + join c in db.T_Criminal_card on b.FCode equals c.fcrimecode into temp + from tt in temp.DefaultIfEmpty() + where b.FCode.Equals(_fcode.FCode) + select new CriminalEntity + { + AmountB = ((tt == null) ? 0m : tt.AmountB.Value), + AmountC = ((tt == null) ? 0m : tt.AmountC.Value), + AmountA = ((tt == null) ? 0m : tt.AmountA.Value), + BankAccNo = tt.BankAccNo, + BankAmount = ((tt.BankAmount == null) ? 0m : tt.BankAmount.Value), + FCode = b.FCode, + FName = b.FName, + Fflag = (b.fflag.HasValue ? b.fflag.Value : 0), + Flimitflag = (b.flimitflag.HasValue ? b.flimitflag.Value : 0), + Flimitamt = (b.flimitamt.HasValue ? b.flimitamt.Value : 0m) + }).FirstOrDefault(); + if (re.ResultData == null) + { + re.ResultCode = "0005"; + re.ResultData = new CriminalEntity(); + } + else if (re.ResultData.Fflag == 1) + { + re.ResultCode = "0007"; + re.ResultData = new CriminalEntity(); + } + else + { + db.proc_CriminalInHospital(_fcode.FCode, ref errorMsg, ref errorCode); + if (errorCode == "1") + { + re.ResultCode = "0000"; + } + else + { + re.ResultCode = "0006"; + re.ResultData = new CriminalEntity(); + } + } + } + catch (Exception) + { + re.ResultCode = "0008"; + re.ResultData = new CriminalEntity(); + } + return jss.Serialize(re); + } + + public static string CriminalConsumedQuota(string FCode) + { + InvoiceEntity reModel = new InvoiceEntity(); + JavaScriptSerializer jss = new JavaScriptSerializer(); + ReqFCode _fcode = jss.Deserialize(FCode); + DateTime FirstDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1); + DateTime EndDate = DateTime.Parse(FirstDate.AddMonths(1).ToShortDateString()).AddSeconds(-1.0); + using (JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom()) + { + proc_CriminalConsumedResult a = db.proc_CriminalConsumed(_fcode.FCode, FirstDate, EndDate).FirstOrDefault(); + if (a != null) + { + InvoiceEntity invoiceEntity = new InvoiceEntity(); + invoiceEntity.AmountA = Convert.ToDecimal((!a.AmountA.HasValue) ? new decimal?(0m) : a.AmountA); + invoiceEntity.AmountB = Convert.ToDecimal((!a.AmountB.HasValue) ? new decimal?(0m) : a.AmountB); + invoiceEntity.FreeAmountA = Convert.ToDecimal((!a.FreeAmountA.HasValue) ? new decimal?(0m) : a.FreeAmountA); + invoiceEntity.FreeAmountB = Convert.ToDecimal((!a.FreeAmountB.HasValue) ? new decimal?(0m) : a.FreeAmountB); + invoiceEntity.Checkflag = a.checkflag.Value; + invoiceEntity.FCode = a.fcrimecode; + invoiceEntity.FCriminal = a.fcriminal; + invoiceEntity.Flag = (a.Flag.HasValue ? a.Flag.Value : 0); + reModel = invoiceEntity; + } + } + return jss.Serialize(reModel); + } + + public static string CriminalOut(string FCode) + { + ResultEntity reModel = new ResultEntity(); + JavaScriptSerializer jss = new JavaScriptSerializer(); + ReqFCode _fcode = jss.Deserialize(FCode); + string errorMsg = ""; + string errorCode = ""; + using (JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom()) + { + db.proc_CriminalOutHospital(_fcode.FCode, ref errorMsg, ref errorCode); + if (errorCode == "1") + { + reModel.Result = true; + } + else + { + reModel.Result = false; + } + reModel.ReMsg = errorMsg; + } + return jss.Serialize(reModel); + } + + public static string CriminalConsume(string reqModel) + { + JavaScriptSerializer jss = new JavaScriptSerializer(); + ReqInoiveEntity _req = jss.Deserialize(reqModel); + ResponNormalModel reModel = new ResponNormalModel(); + try + { + using (JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom()) + { + T_Invoice t_Invoice = new T_Invoice(); + t_Invoice.InvoiceNo = _req.InvoiceNo; + t_Invoice.CardCode = _req.CardCode; + t_Invoice.Amount = _req.Amount; + t_Invoice.AmountA = _req.AmountA; + t_Invoice.AmountB = _req.AmountB; + t_Invoice.Checkflag = 0; + t_Invoice.Crtby = "建新"; + t_Invoice.Crtdate = _req.CrtDate; + t_Invoice.FCrimeCode = _req.FCode; + t_Invoice.FCriminal = _req.FCriminal; + t_Invoice.Flag = 1; + t_Invoice.FreeAmountA = _req.FreeAmountA; + t_Invoice.FreeAmountB = _req.FreeAmountB; + t_Invoice.OrderDate = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")); + t_Invoice.OrderId = _req.OrderId; + t_Invoice.PayDate = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")); + t_Invoice.PType = "建新消费"; + t_Invoice.TypeFlag = 30; + t_Invoice.OrderStatus = 1; + t_Invoice.Fifoflag = -1; + T_Invoice invoice = t_Invoice; + db.T_Invoice.InsertOnSubmit(invoice); + var _criminal = (from crinimal in db.T_Criminal + join area in db.T_AREA on crinimal.FAreaCode equals area.FCode into temp + from tt in temp.DefaultIfEmpty() + where crinimal.FCode.Equals(_req.FCode) + select new + { + FAreaCode = ((crinimal.FAreaCode == null) ? "0" : crinimal.FAreaCode), + FAreaName = ((tt.FName == null) ? "0" : tt.FName) + }).FirstOrDefault(); + if (_req.AmountA > 0m) + { + string vouno = ""; + db.CREATESEQNO("vouno", 1, ref vouno); + T_Vcrd t_Vcrd = new T_Vcrd(); + t_Vcrd.Vouno = "JXVouNo" + vouno; + t_Vcrd.CardCode = _req.CardCode; + t_Vcrd.FCrimeCode = _req.FCode; + t_Vcrd.DAmount = 0m; + t_Vcrd.CAmount = _req.AmountA; + t_Vcrd.CrtBy = "建新"; + t_Vcrd.CrtDate = DateTime.Now; + t_Vcrd.DType = "建新消费"; + t_Vcrd.Depositer = ""; + t_Vcrd.Flag = 0; + t_Vcrd.FCriminal = _req.FCriminal; + t_Vcrd.Frealareacode = ""; + t_Vcrd.FrealAreaName = ""; + t_Vcrd.PType = ""; + t_Vcrd.UDate = DateTime.Now; + t_Vcrd.OrigId = _req.InvoiceNo; + t_Vcrd.CardType = 0; + t_Vcrd.TypeFlag = 30; + t_Vcrd.AccType = 0; + t_Vcrd.BankFlag = 0; + t_Vcrd.CheckFlag = 0; + t_Vcrd.pc = 0; + t_Vcrd.FAreaCode = _criminal.FAreaCode; + t_Vcrd.FAreaName = _criminal.FAreaName; + t_Vcrd.FinancePayFlag = 0; + T_Vcrd vcrd = t_Vcrd; + db.T_Vcrd.InsertOnSubmit(vcrd); + } + if (_req.AmountB > 0m) + { + string vouno2 = ""; + db.CREATESEQNO("vouno", 1, ref vouno2); + T_Vcrd t_Vcrd2 = new T_Vcrd(); + t_Vcrd2.Vouno = "JXVouNo" + vouno2; + t_Vcrd2.CardCode = _req.CardCode; + t_Vcrd2.FCrimeCode = _req.FCode; + t_Vcrd2.DAmount = 0m; + t_Vcrd2.CAmount = _req.AmountB; + t_Vcrd2.CrtBy = "建新"; + t_Vcrd2.CrtDate = DateTime.Now; + t_Vcrd2.DType = "建新消费"; + t_Vcrd2.Depositer = ""; + t_Vcrd2.Flag = 0; + t_Vcrd2.FCriminal = _req.FCriminal; + t_Vcrd2.Frealareacode = ""; + t_Vcrd2.FrealAreaName = ""; + t_Vcrd2.PType = ""; + t_Vcrd2.UDate = DateTime.Now; + t_Vcrd2.OrigId = _req.InvoiceNo; + t_Vcrd2.CardType = 0; + t_Vcrd2.TypeFlag = 30; + t_Vcrd2.AccType = 1; + t_Vcrd2.BankFlag = 0; + t_Vcrd2.CheckFlag = 0; + t_Vcrd2.pc = 0; + t_Vcrd2.FAreaCode = _criminal.FAreaCode; + t_Vcrd2.FAreaName = _criminal.FAreaName; + t_Vcrd2.FinancePayFlag = 0; + T_Vcrd vcrd2 = t_Vcrd2; + db.T_Vcrd.InsertOnSubmit(vcrd2); + } + T_Criminal_card a = db.T_Criminal_card.Where((T_Criminal_card b) => b.fcrimecode.Equals(_req.FCode)).FirstOrDefault(); + a.AmountA -= (decimal?)_req.AmountA; + a.AmountB -= (decimal?)_req.AmountB; + a.BankAmount = a.AmountA + a.AmountB + a.AmountC; + db.SubmitChanges(); + } + reModel.ResultCode = "0000"; + reModel.ResultMsg = ""; + } + catch (Exception ex) + { + reModel.ResultCode = "0008"; + reModel.ResultMsg = ex.Message; + } + return jss.Serialize(reModel); + } + + public static string RealTimeBalance(string FCode) + { + ResponCriminalIn rspModel = new ResponCriminalIn(); + JavaScriptSerializer jss = new JavaScriptSerializer(); + ReqFCode _fcode = jss.Deserialize(FCode); + try + { + using JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom(); + T_Criminal_card a = db.T_Criminal_card.Where((T_Criminal_card b) => b.fcrimecode.Equals(_fcode.FCode)).FirstOrDefault(); + if (a != null) + { + rspModel.ResultData = new CriminalEntity + { + AmountA = (a.AmountA.HasValue ? a.AmountA.Value : 0m), + AmountB = (a.AmountB.HasValue ? a.AmountB.Value : 0m), + AmountC = (a.AmountC.HasValue ? a.AmountC.Value : 0m), + BankAccNo = a.BankAccNo, + BankAmount = (a.BankAmount.HasValue ? a.BankAmount.Value : 0m), + FCode = a.fcrimecode + }; + } + rspModel.ResultCode = "0000"; + } + catch (Exception) + { + rspModel.ResultCode = "0008"; + rspModel.ResultData = new CriminalEntity(); + } + return jss.Serialize(rspModel); + } + + public static string SynInvoiceResult(string InvoiceNoList) + { + JavaScriptSerializer jss = new JavaScriptSerializer(); + RsponEntity _rsp = new RsponEntity(); + _rsp.ResultData = new List(); + List _req = jss.Deserialize>(InvoiceNoList); + try + { + using JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom(); + var reList = (from a in db.T_Vcrd + where _req.Contains(a.OrigId) + group a by new { a.CardCode, a.FCrimeCode, a.BankFlag, a.OrigId, a.SendDate } into b + select new + { + cardcode = b.Key.CardCode, + fcrimecode = b.Key.FCrimeCode, + CAMOUNT = b.Sum((T_Vcrd c) => c.CAmount), + Bankflag = b.Key.BankFlag, + origid = b.Key.OrigId, + SendDate = b.Key.SendDate + }).ToList(); + if (reList.Count > 0) + { + foreach (var re in reList) + { + _rsp.ResultData.Add(new RspVcrdEntity + { + BankFlag = (re.Bankflag.HasValue ? re.Bankflag.Value : 0), + CAmount = (re.CAMOUNT.HasValue ? re.CAMOUNT.Value : 0m), + FCode = re.fcrimecode, + Origid = re.origid, + SendDate = (re.SendDate.HasValue ? re.SendDate.Value : DateTime.Now) + }); + } + } + else + { + _rsp.ResultData = new List(); + } + _rsp.ResultCode = "0000"; + } + catch (Exception) + { + _rsp.ResultCode = "0008"; + _rsp.ResultData = new List(); + } + return jss.Serialize(_rsp); + } + + public static string MonitorSocketResult(string ReqData) + { + JavaScriptSerializer jss = new JavaScriptSerializer(); + ResponNormalModel responNormalModel = new ResponNormalModel(); + responNormalModel.ResultCode = "0000"; + responNormalModel.ResultMsg = ""; + ResponNormalModel _rsp = responNormalModel; + return jss.Serialize(_rsp); + } + + public static string CancelOrderResult(string ReqData) + { + JavaScriptSerializer jss = new JavaScriptSerializer(); + ResponNormalModel responNormalModel = new ResponNormalModel(); + responNormalModel.ResultCode = "0000"; + responNormalModel.ResultMsg = ""; + ResponNormalModel _rsp = responNormalModel; + return jss.Serialize(_rsp); + } +} + +// JXHospitalWSBLL.ResponNormalModel +public class ResponNormalModel +{ + private string _ResultCode; + + private string _ResultMsg; + + public string ResultCode + { + get + { + return _ResultCode; + } + set + { + _ResultCode = value; + } + } + + public string ResultMsg + { + get + { + return _ResultMsg; + } + set + { + _ResultMsg = value; + } + } +} +// JXHospitalWSBLL.RspVcrdEntity +using System; + +public class RspVcrdEntity +{ + private int _BankFlag; + + private decimal _CAmount; + + private string _FCode; + + private string _Origid; + + private DateTime _SendDate; + + public int BankFlag + { + get + { + return _BankFlag; + } + set + { + _BankFlag = value; + } + } + + public decimal CAmount + { + get + { + return _CAmount; + } + set + { + _CAmount = value; + } + } + + public string FCode + { + get + { + return _FCode; + } + set + { + _FCode = value; + } + } + + public string Origid + { + get + { + return _Origid; + } + set + { + _Origid = value; + } + } + + public DateTime SendDate + { + get + { + return _SendDate; + } + set + { + _SendDate = value; + } + } +} +// JXHospitalWSBLL.CriminalEntity +public class CriminalEntity +{ + private string _FCode; + + private string _FName; + + private decimal _AmountA; + + private int _fflag; + + private decimal _AmountB; + + private string _BankAccNo; + + private decimal _BankAmount; + + private decimal _AmountC; + + private int _flimitflag; + + private decimal _flimitamt; + + public string FCode + { + get + { + return _FCode; + } + set + { + _FCode = value; + } + } + + public string FName + { + get + { + return _FName; + } + set + { + _FName = value; + } + } + + public decimal AmountA + { + get + { + return _AmountA; + } + set + { + _AmountA = value; + } + } + + public int Fflag + { + get + { + return _fflag; + } + set + { + _fflag = value; + } + } + + public decimal AmountB + { + get + { + return _AmountB; + } + set + { + _AmountB = value; + } + } + + public string BankAccNo + { + get + { + return _BankAccNo; + } + set + { + _BankAccNo = value; + } + } + + public decimal BankAmount + { + get + { + return _BankAmount; + } + set + { + _BankAmount = value; + } + } + + public decimal AmountC + { + get + { + return _AmountC; + } + set + { + _AmountC = value; + } + } + + public int Flimitflag + { + get + { + return _flimitflag; + } + set + { + _flimitflag = value; + } + } + + public decimal Flimitamt + { + get + { + return _flimitamt; + } + set + { + _flimitamt = value; + } + } +} +// JXHospitalWSBLL.ReqInoiveEntity +using System; + +public class ReqInoiveEntity +{ + private string _FCode; + + private string _InvoiceNo; + + private decimal _AmountA; + + private decimal _AmountB; + + private decimal _Amount; + + private decimal _FreeAmountA; + + private decimal _FreeAmountB; + + private DateTime _CrtDate; + + private string _FCriminal; + + private string _CardCode; + + private int _OrderId; + + public string FCode + { + get + { + return _FCode; + } + set + { + _FCode = value; + } + } + + public string InvoiceNo + { + get + { + return _InvoiceNo; + } + set + { + _InvoiceNo = value; + } + } + + public decimal AmountA + { + get + { + return _AmountA; + } + set + { + _AmountA = value; + } + } + + public decimal AmountB + { + get + { + return _AmountB; + } + set + { + _AmountB = value; + } + } + + public decimal Amount + { + get + { + return _Amount; + } + set + { + _Amount = value; + } + } + + public decimal FreeAmountA + { + get + { + return _FreeAmountA; + } + set + { + _FreeAmountA = value; + } + } + + public decimal FreeAmountB + { + get + { + return _FreeAmountB; + } + set + { + _FreeAmountB = value; + } + } + + public DateTime CrtDate + { + get + { + return _CrtDate; + } + set + { + _CrtDate = value; + } + } + + public string FCriminal + { + get + { + return _FCriminal; + } + set + { + _FCriminal = value; + } + } + + public string CardCode + { + get + { + return _CardCode; + } + set + { + _CardCode = value; + } + } + + public int OrderId + { + get + { + return _OrderId; + } + set + { + _OrderId = value; + } + } +} diff --git a/doc/新建文本文档.txt b/doc/新建文本文档.txt new file mode 100644 index 0000000..5ffd66f --- /dev/null +++ b/doc/新建文本文档.txt @@ -0,0 +1,48 @@ +ϣȴͻ...... +ͻ192.168.10.2:61062ӳɹ... +192.168.10.2:61062Ϣ021600069999FJJXYY712024-07-31 04:20:45["INV210600480113","INV210600556113","INV210600575113","INV210600607113","INV210600740113","INV210600854113","INV210600857113","INV210601006113","INV210601010113","INV210601037113"] +Ϣ1197{"ResultCode":"0000","ResultData":[{"BankFlag":2,"CAmount":8.85,"FCode":"3516023594","Origid":"INV210600607113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":30.00,"FCode":"3516018601","Origid":"INV210600480113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":8.85,"FCode":"3516018601","Origid":"INV210600575113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516018601","Origid":"INV210600857113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":286.70,"FCode":"3516018601","Origid":"INV210601010113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":18.69,"FCode":"3516012606","Origid":"INV210600556113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600740113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600854113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":167.49,"FCode":"3516012606","Origid":"INV210601006113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":269.70,"FCode":"3516016258","Origid":"INV210601037113","SendDate":"\/Date(1624982400000)\/"}]} +----------------------Err begin------------------------ +ͻ192.168.10.2:61062Ͽ::Thread was being aborted. +----------------------Err end ------------------------ +192.168.10.2:61692Ϣ021600069999FJJXYY712024-07-31 10:21:58["INV210600480113","INV210600556113","INV210600575113","INV210600607113","INV210600740113","INV210600854113","INV210600857113","INV210601006113","INV210601010113","INV210601037113"] +Ϣ1197{"ResultCode":"0000","ResultData":[{"BankFlag":2,"CAmount":8.85,"FCode":"3516023594","Origid":"INV210600607113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":30.00,"FCode":"3516018601","Origid":"INV210600480113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":8.85,"FCode":"3516018601","Origid":"INV210600575113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516018601","Origid":"INV210600857113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":286.70,"FCode":"3516018601","Origid":"INV210601010113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":18.69,"FCode":"3516012606","Origid":"INV210600556113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600740113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600854113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":167.49,"FCode":"3516012606","Origid":"INV210601006113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":269.70,"FCode":"3516016258","Origid":"INV210601037113","SendDate":"\/Date(1624982400000)\/"}]} + + +----------------------Err end ------------------------ +ͻ192.168.10.2:62796ӳɹ... +192.168.10.2:62796Ϣ005700059999FJJXYY712024-08-01 09:00:44{"FCode":"3516022343"} +Ϣ0216{"ResultCode":"0000","ResultData":{"FCode":"3516022343","FName":null,"AmountA":414.54,"Fflag":0,"AmountB":0.27,"BankAccNo":"6230361101121167023","BankAmount":2440.5600,"AmountC":2025.75,"Flimitflag":0,"Flimitamt":0}} +----------------------Err begin------------------------ +ͻ192.168.10.2:62796Ͽ::Thread was being aborted. +----------------------Err end ------------------------ +192.168.10.2:62797Ϣ027000049999FJJXYY712024-08-01 09:00:47{"FCode":"3516022343","InvoiceNo":"INV240800054113","AmountA":10.00,"AmountB":0.00,"Amount":10.00,"FreeAmountA":0.00,"FreeAmountB":0.00,"CrtDate":"\/Date(1722474044000)\/","FCriminal":"","CardCode":"2405007996","OrderId":1118337} +ͻ192.168.10.2:62797ӳɹ... +Ϣ0036{"ResultCode":"0000","ResultMsg":""} +----------------------Err begin------------------------ +ͻ192.168.10.2:62797Ͽ::Thread was being aborted. +----------------------Err end ------------------------ +ͻ192.168.10.2:62802ӳɹ... +192.168.10.2:62802Ϣ005700059999FJJXYY712024-08-01 09:01:33{"FCode":"3516015811"} +Ϣ0212{"ResultCode":"0000","ResultData":{"FCode":"3516015811","FName":null,"AmountA":71.48,"Fflag":0,"AmountB":0.13,"BankAccNo":"6230361101034063160","BankAmount":124.7100,"AmountC":53.10,"Flimitflag":0,"Flimitamt":0}} +----------------------Err begin------------------------ +ͻ192.168.10.2:62802Ͽ::Thread was being aborted. +----------------------Err end ------------------------ +192.168.10.2:62803Ϣ027300049999FJJXYY712024-08-01 09:01:37{"FCode":"3516015811","InvoiceNo":"INV240800060113","AmountA":10.00,"AmountB":0.00,"Amount":10.00,"FreeAmountA":0.00,"FreeAmountB":0.00,"CrtDate":"\/Date(1722474093000)\/","FCriminal":"к","CardCode":"2407008188","OrderId":1118343} +ͻ192.168.10.2:62803ӳɹ... +Ϣ0036{"ResultCode":"0000","ResultMsg":""} +----------------------Err begin------------------------ +ͻ192.168.10.2:62803Ͽ::Thread was being aborted. +----------------------Err end ------------------------ +ͻ192.168.10.2:63014ӳɹ... +192.168.10.2:63014Ϣ021600069999FJJXYY712024-08-01 10:24:20["INV210600480113","INV210600556113","INV210600575113","INV210600607113","INV210600740113","INV210600854113","INV210600857113","INV210601006113","INV210601010113","INV210601037113"] +Ϣ1197{"ResultCode":"0000","ResultData":[{"BankFlag":2,"CAmount":8.85,"FCode":"3516023594","Origid":"INV210600607113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":30.00,"FCode":"3516018601","Origid":"INV210600480113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":8.85,"FCode":"3516018601","Origid":"INV210600575113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516018601","Origid":"INV210600857113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":286.70,"FCode":"3516018601","Origid":"INV210601010113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":18.69,"FCode":"3516012606","Origid":"INV210600556113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600740113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600854113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":167.49,"FCode":"3516012606","Origid":"INV210601006113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":269.70,"FCode":"3516016258","Origid":"INV210601037113","SendDate":"\/Date(1624982400000)\/"}]} +----------------------Err begin------------------------ +ͻ192.168.10.2:63014Ͽ::Thread was being aborted. +----------------------Err end ------------------------ +192.168.10.2:63656Ϣ021600069999FJJXYY712024-08-01 04:25:32["INV210600480113","INV210600556113","INV210600575113","INV210600607113","INV210600740113","INV210600854113","INV210600857113","INV210601006113","INV210601010113","INV210601037113"] +Ϣ1197{"ResultCode":"0000","ResultData":[{"BankFlag":2,"CAmount":8.85,"FCode":"3516023594","Origid":"INV210600607113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":30.00,"FCode":"3516018601","Origid":"INV210600480113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":8.85,"FCode":"3516018601","Origid":"INV210600575113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516018601","Origid":"INV210600857113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":286.70,"FCode":"3516018601","Origid":"INV210601010113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":18.69,"FCode":"3516012606","Origid":"INV210600556113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600740113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600854113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":167.49,"FCode":"3516012606","Origid":"INV210601006113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":269.70,"FCode":"3516016258","Origid":"INV210601037113","SendDate":"\/Date(1624982400000)\/"}]} +ͻ192.168.10.2:63656ӳɹ... +----------------------Err begin------------------------ +ͻ192.168.10.2:63656Ͽ::Thread was being aborted. +----------------------Err end ------------------------ \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c89d383 --- /dev/null +++ b/go.mod @@ -0,0 +1,71 @@ +module github.com/emsoft/HospitalPay-Go + +go 1.23.0 + +toolchain go1.23.1 + +require ( + github.com/gin-gonic/gin v1.10.0 + github.com/spf13/viper v1.20.0 + gorm.io/gorm v1.25.12 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/sse v1.0.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.25.0 // indirect + github.com/go-sql-driver/mysql v1.9.1 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/prometheus/client_golang v1.21.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.63.0 // indirect + github.com/prometheus/procfs v0.16.0 // indirect + github.com/sagikazarmark/locafero v0.8.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.14.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/arch v0.15.0 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.37.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.7 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..3d84d77 --- /dev/null +++ b/go.sum @@ -0,0 +1,225 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= +github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= +github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= +github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= +github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= +github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/locafero v0.8.0 h1:mXaMVw7IqxNBxfv3LdWt9MDmcWDQ1fagDH918lOdVaQ= +github.com/sagikazarmark/locafero v0.8.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY= +github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..ff3a59e --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,90 @@ +package config + +import ( + "errors" + "time" + + "github.com/spf13/viper" +) + +type Config struct { + Server ServerConfig `mapstructure:"server"` + Database DatabaseConfig `mapstructure:"database"` + Log LogConfig `mapstructure:"log"` + Monitoring MonitoringConfig `mapstructure:"monitoring"` +} + +type ServerConfig struct { + Port string `mapstructure:"port"` + Mode string `mapstructure:"mode"` + HospitalCode string `mapstructure:"hospital_code"` + ReadTimeout time.Duration `mapstructure:"read_timeout"` + WriteTimeout time.Duration `mapstructure:"write_timeout"` + MaxConnNum int `mapstructure:"max_conn_num"` +} + +type DatabaseConfig struct { + Driver string `mapstructure:"driver"` + Host string `mapstructure:"host"` + Port int `mapstructure:"port"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` + DBName string `mapstructure:"dbname"` + Charset string `mapstructure:"charset"` + ParseTime bool `mapstructure:"parseTime"` + Loc string `mapstructure:"loc"` + MaxIdleConns int `mapstructure:"max_idle_conns"` + MaxOpenConns int `mapstructure:"max_open_conns"` + ConnMaxLifetime time.Duration `mapstructure:"conn_max_lifetime"` +} + +type LogConfig struct { + Level string `mapstructure:"level"` + Format string `mapstructure:"format"` + OutputPath string `mapstructure:"output_path"` + MaxSize int `mapstructure:"max_size"` + MaxAge int `mapstructure:"max_age"` + MaxBackups int `mapstructure:"max_backups"` + Compress bool `mapstructure:"compress"` +} + +type MonitoringConfig struct { + Enabled bool `mapstructure:"enabled"` + PrometheusPort string `mapstructure:"prometheus_port"` +} + +var GlobalConfig Config + +func Init() error { + viper.SetConfigName("config") + viper.SetConfigType("yaml") + viper.AddConfigPath("./config") + + if err := viper.ReadInConfig(); err != nil { + return err + } + + if err := viper.Unmarshal(&GlobalConfig); err != nil { + return err + } + + // 验证配置项 + if err := validate(); err != nil { + return err + } + + return nil +} + +func validate() error { + if GlobalConfig.Server.Port == "" { + return errors.New("server port is required") + } + if GlobalConfig.Server.HospitalCode == "" { + return errors.New("hospital code is required") + } + if GlobalConfig.Database.Host == "" { + return errors.New("database host is required") + } + return nil +} diff --git a/internal/model/base.go b/internal/model/base.go new file mode 100644 index 0000000..ba9b842 --- /dev/null +++ b/internal/model/base.go @@ -0,0 +1,15 @@ +package model + +import ( + "time" + + "gorm.io/gorm" +) + +// Base 模型基础字段 +type Base struct { + ID uint `gorm:"primarykey" json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` +} diff --git a/internal/model/criminal.go b/internal/model/criminal.go new file mode 100644 index 0000000..a067e3f --- /dev/null +++ b/internal/model/criminal.go @@ -0,0 +1,70 @@ +package model + +import "time" + +// CriminalRequest 病人请求基础结构 +type CriminalRequest struct { + FCode string `json:"FCode"` // 病人编号 +} + +// CriminalResponse 病人响应基础结构 +type CriminalResponse struct { + ResultCode string `json:"ResultCode"` // 结果代码 + ResultData interface{} `json:"ResultData"` // 响应数据 + ResultMsg string `json:"ResultMsg"` // 结果消息 +} + +// CriminalInfo 病人信息 +type CriminalInfo struct { + FCode string `json:"FCode"` // 病人编号 + FName string `json:"FName"` // 病人姓名 + AmountA float64 `json:"AmountA"` // A类金额 + AmountB float64 `json:"AmountB"` // B类金额 + AmountC float64 `json:"AmountC"` // C类金额 + BankAccNo string `json:"BankAccNo"` // 银行账号 + BankAmount float64 `json:"BankAmount"` // 银行余额 + Fflag int `json:"Fflag"` // 状态标志 + Flimitflag int `json:"Flimitflag"` // 限制标志 + Flimitamt float64 `json:"Flimitamt"` // 限制金额 +} + +// ConsumeQuota 消费额度信息 +type ConsumeQuota struct { + AmountA float64 `json:"AmountA"` // A类消费金额 + AmountB float64 `json:"AmountB"` // B类消费金额 + FreeAmountA float64 `json:"FreeAmountA"` // A类可用金额 + FreeAmountB float64 `json:"FreeAmountB"` // B类可用金额 + Checkflag int `json:"Checkflag"` // 检查标志 + FCode string `json:"FCode"` // 病人编号 + FCriminal string `json:"FCriminal"` // 病人姓名 + Flag int `json:"Flag"` // 状态标志 +} + +// ConsumeRecord 消费记录 +type ConsumeRecord struct { + FCode string `json:"FCode"` // 病人编号 + InvoiceNo string `json:"InvoiceNo"` // 发票号 + AmountA float64 `json:"AmountA"` // A类金额 + AmountB float64 `json:"AmountB"` // B类金额 + Amount float64 `json:"Amount"` // 总金额 + FreeAmountA float64 `json:"FreeAmountA"` // A类可用金额 + FreeAmountB float64 `json:"FreeAmountB"` // B类可用金额 + CrtDate time.Time `json:"CrtDate"` // 创建日期 + FCriminal string `json:"FCriminal"` // 病人姓名 + CardCode string `json:"CardCode"` // 卡号 + OrderId int64 `json:"OrderId"` // 订单ID +} + +// InvoiceSync 发票同步 +type InvoiceSync struct { + InvoiceList []string `json:"InvoiceList"` // 发票号列表 +} + +// InvoiceSyncResult 发票同步结果 +type InvoiceSyncResult struct { + BankFlag int `json:"BankFlag"` // 银行标志 + CAmount float64 `json:"CAmount"` // 金额 + FCode string `json:"FCode"` // 病人编号 + Origid string `json:"Origid"` // 原始ID + SendDate time.Time `json:"SendDate"` // 发送日期 +} diff --git a/internal/pkg/database/gorm_logger.go b/internal/pkg/database/gorm_logger.go new file mode 100644 index 0000000..d0e6eb3 --- /dev/null +++ b/internal/pkg/database/gorm_logger.go @@ -0,0 +1,78 @@ +package database + +import ( + "context" + "errors" + "time" + + "github.com/emsoft/HospitalPay-Go/internal/pkg/logger" + "go.uber.org/zap" + "gorm.io/gorm" + gormlogger "gorm.io/gorm/logger" +) + +// 自定义Gorm日志适配器 +type GormLogger struct { + SlowThreshold time.Duration + LogLevel gormlogger.LogLevel +} + +// 创建新的Gorm日志适配器 +func NewGormLogger() *GormLogger { + return &GormLogger{ + SlowThreshold: 200 * time.Millisecond, + LogLevel: gormlogger.Info, + } +} + +// LogMode 设置日志级别 +func (l *GormLogger) LogMode(level gormlogger.LogLevel) gormlogger.Interface { + newLogger := *l + newLogger.LogLevel = level + return &newLogger +} + +// Info 打印信息 +func (l *GormLogger) Info(ctx context.Context, msg string, data ...interface{}) { + if l.LogLevel >= gormlogger.Info { + logger.Infof(msg, data...) + } +} + +// Warn 打印警告 +func (l *GormLogger) Warn(ctx context.Context, msg string, data ...interface{}) { + if l.LogLevel >= gormlogger.Warn { + logger.Warnf(msg, data...) + } +} + +// Error 打印错误 +func (l *GormLogger) Error(ctx context.Context, msg string, data ...interface{}) { + if l.LogLevel >= gormlogger.Error { + logger.Errorf(msg, data...) + } +} + +// Trace 打印SQL +func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { + if l.LogLevel <= gormlogger.Silent { + return + } + + elapsed := time.Since(begin) + sql, rows := fc() + fields := []zap.Field{ + zap.String("sql", sql), + zap.Int64("rows", rows), + zap.Duration("elapsed", elapsed), + } + + switch { + case err != nil && l.LogLevel >= gormlogger.Error && !errors.Is(err, gorm.ErrRecordNotFound): + logger.Error("GORM ERROR", fields...) + case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= gormlogger.Warn: + logger.Warn("GORM SLOW SQL", fields...) + case l.LogLevel >= gormlogger.Info: + logger.Debug("GORM SQL", fields...) + } +} diff --git a/internal/pkg/database/mysql.go b/internal/pkg/database/mysql.go new file mode 100644 index 0000000..473b08b --- /dev/null +++ b/internal/pkg/database/mysql.go @@ -0,0 +1,80 @@ +package database + +import ( + "fmt" + + "github.com/emsoft/HospitalPay-Go/internal/config" + "github.com/emsoft/HospitalPay-Go/internal/pkg/logger" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +var DB *gorm.DB + +// Init 初始化数据库连接 +func Init() error { + var err error + + dbConfig := config.GlobalConfig.Database + + dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%v&loc=%s", + dbConfig.Username, + dbConfig.Password, + dbConfig.Host, + dbConfig.Port, + dbConfig.DBName, + dbConfig.Charset, + dbConfig.ParseTime, + dbConfig.Loc, + ) + + DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + TablePrefix: "t_", // 表名前缀 + SingularTable: true, // 使用单数表名 + }, + Logger: NewGormLogger(), + }) + + if err != nil { + return fmt.Errorf("connect to database failed: %v", err) + } + + // 设置连接池 + sqlDB, err := DB.DB() + if err != nil { + return fmt.Errorf("get db instance failed: %v", err) + } + + sqlDB.SetMaxIdleConns(dbConfig.MaxIdleConns) + sqlDB.SetMaxOpenConns(dbConfig.MaxOpenConns) + sqlDB.SetConnMaxLifetime(dbConfig.ConnMaxLifetime) + + // 测试连接 + if err := sqlDB.Ping(); err != nil { + return fmt.Errorf("ping database failed: %v", err) + } + + logger.Info("Database connected successfully") + return nil +} + +// GetDB 获取数据库连接 +func GetDB() *gorm.DB { + return DB +} + +// Close 关闭数据库连接 +func Close() error { + sqlDB, err := DB.DB() + if err != nil { + return err + } + return sqlDB.Close() +} + +// Transaction 事务处理 +func Transaction(fn func(tx *gorm.DB) error) error { + return DB.Transaction(fn) +} diff --git a/internal/pkg/errcode/errcode.go b/internal/pkg/errcode/errcode.go new file mode 100644 index 0000000..20384dd --- /dev/null +++ b/internal/pkg/errcode/errcode.go @@ -0,0 +1,26 @@ +package errcode + +// ErrorCode 错误码结构 +type ErrorCode struct { + Code string + Message string +} + +// 系统级错误码 +var ( + Success = &ErrorCode{Code: "0000", Message: "成功"} + ServerError = &ErrorCode{Code: "0008", Message: "系统异常"} + InvalidParams = &ErrorCode{Code: "0009", Message: "请求参数错误"} + NotFound = &ErrorCode{Code: "0005", Message: "未找到病人信息"} +) + +// 业务级错误码 +var ( + CriminalInFailed = &ErrorCode{Code: "0006", Message: "入院处理失败"} + CriminalAlreadyIn = &ErrorCode{Code: "0007", Message: "病人已入院"} + CriminalOutFailed = &ErrorCode{Code: "1001", Message: "出院处理失败"} + ConsumeQuotaFailed = &ErrorCode{Code: "1002", Message: "消费额度查询失败"} + ConsumeRecordFailed = &ErrorCode{Code: "1003", Message: "消费记录保存失败"} + RealTimeBalanceFailed = &ErrorCode{Code: "1004", Message: "实时余额查询失败"} + InvoiceSyncFailed = &ErrorCode{Code: "1005", Message: "发票同步失败"} +) diff --git a/internal/pkg/logger/logger.go b/internal/pkg/logger/logger.go new file mode 100644 index 0000000..acb30ea --- /dev/null +++ b/internal/pkg/logger/logger.go @@ -0,0 +1,131 @@ +package logger + +import ( + "os" + "path/filepath" + + "github.com/emsoft/HospitalPay-Go/internal/config" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "gopkg.in/natefinch/lumberjack.v2" +) + +var Logger *zap.Logger +var SugaredLogger *zap.SugaredLogger + +// Init 初始化日志 +func Init() error { + logConfig := config.GlobalConfig.Log + + // 确保日志目录存在 + if err := os.MkdirAll(filepath.Dir(logConfig.OutputPath), 0755); err != nil { + return err + } + + // 设置日志轮转 + w := zapcore.AddSync(&lumberjack.Logger{ + Filename: logConfig.OutputPath, + MaxSize: logConfig.MaxSize, + MaxBackups: logConfig.MaxBackups, + MaxAge: logConfig.MaxAge, + Compress: logConfig.Compress, + }) + + // 设置日志级别 + var level zapcore.Level + switch logConfig.Level { + case "debug": + level = zapcore.DebugLevel + case "info": + level = zapcore.InfoLevel + case "warn": + level = zapcore.WarnLevel + case "error": + level = zapcore.ErrorLevel + case "fatal": + level = zapcore.FatalLevel + default: + level = zapcore.InfoLevel + } + + // 设置日志编码器 + encoderConfig := zapcore.EncoderConfig{ + TimeKey: "time", + LevelKey: "level", + NameKey: "logger", + CallerKey: "caller", + MessageKey: "msg", + StacktraceKey: "stacktrace", + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: zapcore.LowercaseLevelEncoder, + EncodeTime: zapcore.ISO8601TimeEncoder, + EncodeDuration: zapcore.SecondsDurationEncoder, + EncodeCaller: zapcore.ShortCallerEncoder, + } + + var encoder zapcore.Encoder + if logConfig.Format == "json" { + encoder = zapcore.NewJSONEncoder(encoderConfig) + } else { + encoder = zapcore.NewConsoleEncoder(encoderConfig) + } + + // 创建核心 + core := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(w, zapcore.AddSync(os.Stdout)), level) + + // 创建日志实例 + Logger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) + SugaredLogger = Logger.Sugar() + + return nil +} + +// Debug logs a message at debug level +func Debug(msg string, fields ...zapcore.Field) { + Logger.Debug(msg, fields...) +} + +// Info logs a message at info level +func Info(msg string, fields ...zapcore.Field) { + Logger.Info(msg, fields...) +} + +// Warn logs a message at warn level +func Warn(msg string, fields ...zapcore.Field) { + Logger.Warn(msg, fields...) +} + +// Error logs a message at error level +func Error(msg string, fields ...zapcore.Field) { + Logger.Error(msg, fields...) +} + +// Fatal logs a message at fatal level and then calls os.Exit(1) +func Fatal(msg string, fields ...zapcore.Field) { + Logger.Fatal(msg, fields...) +} + +// Debugf logs a formatted message at debug level +func Debugf(format string, args ...interface{}) { + SugaredLogger.Debugf(format, args...) +} + +// Infof logs a formatted message at info level +func Infof(format string, args ...interface{}) { + SugaredLogger.Infof(format, args...) +} + +// Warnf logs a formatted message at warn level +func Warnf(format string, args ...interface{}) { + SugaredLogger.Warnf(format, args...) +} + +// Errorf logs a formatted message at error level +func Errorf(format string, args ...interface{}) { + SugaredLogger.Errorf(format, args...) +} + +// Fatalf logs a formatted message at fatal level and then calls os.Exit(1) +func Fatalf(format string, args ...interface{}) { + SugaredLogger.Fatalf(format, args...) +} diff --git a/internal/pkg/metrics/metrics.go b/internal/pkg/metrics/metrics.go new file mode 100644 index 0000000..bf46023 --- /dev/null +++ b/internal/pkg/metrics/metrics.go @@ -0,0 +1,44 @@ +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + // RequestCounter 请求计数器 + RequestCounter = promauto.NewCounterVec( + prometheus.CounterOpts{ + Name: "hospital_pay_requests_total", + Help: "请求总数,按功能码分类", + }, + []string{"function_code"}, + ) + + // RequestDuration 请求处理时间 + RequestDuration = promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "hospital_pay_request_duration_seconds", + Help: "请求处理时间(秒)", + Buckets: prometheus.DefBuckets, + }, + []string{"function_code"}, + ) + + // ErrorCounter 错误计数器 + ErrorCounter = promauto.NewCounterVec( + prometheus.CounterOpts{ + Name: "hospital_pay_errors_total", + Help: "错误总数,按功能码和错误码分类", + }, + []string{"function_code", "error_code"}, + ) + + // ActiveConnections 活跃连接数 + ActiveConnections = promauto.NewGauge( + prometheus.GaugeOpts{ + Name: "hospital_pay_active_connections", + Help: "当前活跃连接数", + }, + ) +) diff --git a/internal/server/socket.go b/internal/server/socket.go new file mode 100644 index 0000000..60dd0b2 --- /dev/null +++ b/internal/server/socket.go @@ -0,0 +1,397 @@ +package server + +import ( + "context" + "encoding/json" + "fmt" + "net" + "os" + "os/signal" + "sync" + "syscall" + "time" + + "github.com/emsoft/HospitalPay-Go/internal/config" + "github.com/emsoft/HospitalPay-Go/internal/model" + "github.com/emsoft/HospitalPay-Go/internal/pkg/errcode" + "github.com/emsoft/HospitalPay-Go/internal/pkg/logger" + "github.com/emsoft/HospitalPay-Go/internal/pkg/metrics" + "github.com/emsoft/HospitalPay-Go/internal/service" +) + +// SocketServer Socket 服务器 +type SocketServer struct { + criminalService service.ICriminalService + listener net.Listener + connLimit chan struct{} + wg sync.WaitGroup + shutdown chan struct{} +} + +// NewSocketServer 创建 Socket 服务器 +func NewSocketServer() *SocketServer { + return &SocketServer{ + criminalService: service.NewCriminalService(), + connLimit: make(chan struct{}, config.GlobalConfig.Server.MaxConnNum), + shutdown: make(chan struct{}), + } +} + +// Start 启动服务器 +func (s *SocketServer) Start() error { + var err error + s.listener, err = net.Listen("tcp", ":"+config.GlobalConfig.Server.Port) + if err != nil { + return fmt.Errorf("failed to start socket server: %v", err) + } + + // 注册信号处理 + go s.handleSignal() + + logger.Infof("Socket server started on port %s", config.GlobalConfig.Server.Port) + + // 开始接受连接 + go s.acceptConnections() + + // 等待关闭 + <-s.shutdown + return nil +} + +// 接受连接 +func (s *SocketServer) acceptConnections() { + for { + conn, err := s.listener.Accept() + if err != nil { + select { + case <-s.shutdown: + return + default: + logger.Errorf("Failed to accept connection: %v", err) + continue + } + } + + // 记录指标 + metrics.ActiveConnections.Inc() + + // 并发控制 + select { + case s.connLimit <- struct{}{}: + s.wg.Add(1) + go func() { + defer func() { + <-s.connLimit + metrics.ActiveConnections.Dec() + s.wg.Done() + }() + s.handleConnection(conn) + }() + default: + logger.Warnf("Connection limit reached, rejecting connection from %s", conn.RemoteAddr()) + conn.Close() + } + } +} + +// 处理连接 +func (s *SocketServer) handleConnection(conn net.Conn) { + defer conn.Close() + + // 设置超时 + if err := conn.SetDeadline(time.Now().Add(config.GlobalConfig.Server.ReadTimeout)); err != nil { + logger.Errorf("Failed to set deadline: %v", err) + return + } + + // 记录连接信息 + remoteAddr := conn.RemoteAddr().String() + logger.Infof("New connection from %s", remoteAddr) + + buffer := make([]byte, 4096) + n, err := conn.Read(buffer) + if err != nil { + logger.Errorf("Failed to read from connection: %v", err) + return + } + + message := string(buffer[:n]) + if len(message) < 31 { // 最小消息长度:4(长度) + 4(功能码) + 4(医院编码) + 19(时间戳) + logger.Errorf("Invalid message format from %s: %s", remoteAddr, message) + return + } + + // 解析消息 + length := message[:4] + functionCode := message[4:8] + hospitalCode := message[8:12] + timestamp := message[12:31] + data := message[31:] + + logger.Infof("Received message from %s: length=%s, functionCode=%s, hospitalCode=%s, timestamp=%s, data=%s", + remoteAddr, length, functionCode, hospitalCode, timestamp, data) + + // 请求计数 + metrics.RequestCounter.WithLabelValues(functionCode).Inc() + start := time.Now() + + // 验证医院编码 + if hospitalCode != config.GlobalConfig.Server.HospitalCode { + logger.Warnf("Invalid hospital code from %s: %s", remoteAddr, hospitalCode) + s.sendResponse(conn, &model.CriminalResponse{ + ResultCode: errcode.InvalidParams.Code, + ResultMsg: "无效的医院编码", + }) + return + } + + // 创建上下文 + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // 处理请求 + var response *model.CriminalResponse + switch functionCode { + case "0001": + response = s.handleCriminalIn(ctx, data) + case "0002": + response = s.handleConsumeQuota(ctx, data) + case "0003": + response = s.handleCriminalOut(ctx, data) + case "0004": + response = s.handleConsumeRecord(ctx, data) + case "0005": + response = s.handleRealTimeBalance(ctx, data) + case "0006": + response = s.handleInvoiceSync(ctx, data) + default: + response = &model.CriminalResponse{ + ResultCode: errcode.ServerError.Code, + ResultMsg: "未知的功能码", + } + } + + // 记录处理时间 + duration := time.Since(start).Seconds() + metrics.RequestDuration.WithLabelValues(functionCode).Observe(duration) + + // 发送响应 + s.sendResponse(conn, response) +} + +// 处理入院登记 +func (s *SocketServer) handleCriminalIn(ctx context.Context, data string) *model.CriminalResponse { + var req model.CriminalRequest + if err := json.Unmarshal([]byte(data), &req); err != nil { + logger.Errorf("Failed to unmarshal CriminalIn request: %v", err) + metrics.ErrorCounter.WithLabelValues("0001", errcode.InvalidParams.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.InvalidParams.Code, + ResultMsg: "请求数据格式错误", + } + } + + resp, err := s.criminalService.CriminalIn(ctx, req.FCode) + if err != nil { + logger.Errorf("Failed to process CriminalIn: %v", err) + metrics.ErrorCounter.WithLabelValues("0001", errcode.ServerError.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.ServerError.Code, + ResultMsg: err.Error(), + } + } + + return resp +} + +// 处理消费额度查询 +func (s *SocketServer) handleConsumeQuota(ctx context.Context, data string) *model.CriminalResponse { + var req model.CriminalRequest + if err := json.Unmarshal([]byte(data), &req); err != nil { + logger.Errorf("Failed to unmarshal ConsumeQuota request: %v", err) + metrics.ErrorCounter.WithLabelValues("0002", errcode.InvalidParams.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.InvalidParams.Code, + ResultMsg: "请求数据格式错误", + } + } + + resp, err := s.criminalService.ConsumeQuota(ctx, req.FCode) + if err != nil { + logger.Errorf("Failed to process ConsumeQuota: %v", err) + metrics.ErrorCounter.WithLabelValues("0002", errcode.ServerError.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.ServerError.Code, + ResultMsg: err.Error(), + } + } + + return resp +} + +// 处理出院 +func (s *SocketServer) handleCriminalOut(ctx context.Context, data string) *model.CriminalResponse { + var req model.CriminalRequest + if err := json.Unmarshal([]byte(data), &req); err != nil { + logger.Errorf("Failed to unmarshal CriminalOut request: %v", err) + metrics.ErrorCounter.WithLabelValues("0003", errcode.InvalidParams.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.InvalidParams.Code, + ResultMsg: "请求数据格式错误", + } + } + + resp, err := s.criminalService.CriminalOut(ctx, req.FCode) + if err != nil { + logger.Errorf("Failed to process CriminalOut: %v", err) + metrics.ErrorCounter.WithLabelValues("0003", errcode.ServerError.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.ServerError.Code, + ResultMsg: err.Error(), + } + } + + return resp +} + +// 处理消费记录 +func (s *SocketServer) handleConsumeRecord(ctx context.Context, data string) *model.CriminalResponse { + var record model.ConsumeRecord + if err := json.Unmarshal([]byte(data), &record); err != nil { + logger.Errorf("Failed to unmarshal ConsumeRecord request: %v", err) + metrics.ErrorCounter.WithLabelValues("0004", errcode.InvalidParams.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.InvalidParams.Code, + ResultMsg: "请求数据格式错误", + } + } + + resp, err := s.criminalService.ConsumeRecord(ctx, &record) + if err != nil { + logger.Errorf("Failed to process ConsumeRecord: %v", err) + metrics.ErrorCounter.WithLabelValues("0004", errcode.ServerError.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.ServerError.Code, + ResultMsg: err.Error(), + } + } + + return resp +} + +// 处理实时余额查询 +func (s *SocketServer) handleRealTimeBalance(ctx context.Context, data string) *model.CriminalResponse { + var req model.CriminalRequest + if err := json.Unmarshal([]byte(data), &req); err != nil { + logger.Errorf("Failed to unmarshal RealTimeBalance request: %v", err) + metrics.ErrorCounter.WithLabelValues("0005", errcode.InvalidParams.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.InvalidParams.Code, + ResultMsg: "请求数据格式错误", + } + } + + resp, err := s.criminalService.RealTimeBalance(ctx, req.FCode) + if err != nil { + logger.Errorf("Failed to process RealTimeBalance: %v", err) + metrics.ErrorCounter.WithLabelValues("0005", errcode.ServerError.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.ServerError.Code, + ResultMsg: err.Error(), + } + } + + return resp +} + +// 处理发票同步 +func (s *SocketServer) handleInvoiceSync(ctx context.Context, data string) *model.CriminalResponse { + var req model.InvoiceSync + if err := json.Unmarshal([]byte(data), &req); err != nil { + logger.Errorf("Failed to unmarshal InvoiceSync request: %v", err) + metrics.ErrorCounter.WithLabelValues("0006", errcode.InvalidParams.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.InvalidParams.Code, + ResultMsg: "请求数据格式错误", + } + } + + resp, err := s.criminalService.InvoiceSync(ctx, req.InvoiceList) + if err != nil { + logger.Errorf("Failed to process InvoiceSync: %v", err) + metrics.ErrorCounter.WithLabelValues("0006", errcode.ServerError.Code).Inc() + return &model.CriminalResponse{ + ResultCode: errcode.ServerError.Code, + ResultMsg: err.Error(), + } + } + + return resp +} + +// 发送响应 +func (s *SocketServer) sendResponse(conn net.Conn, response *model.CriminalResponse) { + jsonData, err := json.Marshal(response) + if err != nil { + logger.Errorf("Failed to marshal response: %v", err) + return + } + + // 设置写超时 + if err := conn.SetWriteDeadline(time.Now().Add(config.GlobalConfig.Server.WriteTimeout)); err != nil { + logger.Errorf("Failed to set write deadline: %v", err) + return + } + + // 构造响应消息:长度(4位) + JSON数据 + message := fmt.Sprintf("%04d%s", len(jsonData), string(jsonData)) + + if _, err := conn.Write([]byte(message)); err != nil { + logger.Errorf("Failed to send response: %v", err) + return + } + + logger.Infof("Response sent to %s: %s", conn.RemoteAddr().String(), message) +} + +// 优雅关闭 +func (s *SocketServer) Stop() { + logger.Info("Stopping socket server...") + + // 关闭监听器,停止接受新连接 + if s.listener != nil { + s.listener.Close() + } + + // 等待所有连接处理完成 + logger.Info("Waiting for all connections to finish...") + done := make(chan struct{}) + go func() { + s.wg.Wait() + close(done) + }() + + // 设置超时 + select { + case <-done: + logger.Info("All connections finished") + case <-time.After(10 * time.Second): + logger.Warn("Timeout waiting for connections to finish") + } + + // 通知关闭完成 + close(s.shutdown) +} + +// 处理信号 +func (s *SocketServer) handleSignal() { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) + + // 等待信号 + sig := <-c + logger.Infof("Received signal: %v", sig) + + // 停止服务器 + s.Stop() +} diff --git a/internal/service/criminal.go b/internal/service/criminal.go new file mode 100644 index 0000000..1fd16be --- /dev/null +++ b/internal/service/criminal.go @@ -0,0 +1,151 @@ +package service + +import ( + "context" + "time" + + "github.com/emsoft/HospitalPay-Go/internal/model" + "github.com/emsoft/HospitalPay-Go/internal/pkg/database" + "github.com/emsoft/HospitalPay-Go/internal/pkg/errcode" + "github.com/emsoft/HospitalPay-Go/internal/pkg/logger" + "go.uber.org/zap" + "gorm.io/gorm" +) + +// CriminalService 病人服务实现 +type CriminalService struct { + db *gorm.DB +} + +// NewCriminalService 创建病人服务 +func NewCriminalService() *CriminalService { + return &CriminalService{ + db: database.GetDB(), + } +} + +// CriminalIn 入院登记 +func (s *CriminalService) CriminalIn(ctx context.Context, fcode string) (*model.CriminalResponse, error) { + logger.Info("开始入院登记处理", zap.String("fcode", fcode)) + + // TODO: 实现数据库操作 + // 这里是模拟实现,实际应该从数据库查询 + info := &model.CriminalInfo{ + FCode: fcode, + FName: "测试病人", + AmountA: 100.00, + AmountB: 50.00, + AmountC: 150.00, + BankAccNo: "6222021234567890", + BankAmount: 1000.00, + Fflag: 0, + Flimitflag: 0, + Flimitamt: 0, + } + + logger.Info("入院登记处理完成", zap.String("fcode", fcode)) + return &model.CriminalResponse{ + ResultCode: errcode.Success.Code, + ResultData: info, + }, nil +} + +// ConsumeQuota 消费额度查询 +func (s *CriminalService) ConsumeQuota(ctx context.Context, fcode string) (*model.CriminalResponse, error) { + logger.Info("开始消费额度查询", zap.String("fcode", fcode)) + + // TODO: 实现数据库操作 + quota := &model.ConsumeQuota{ + AmountA: 50.00, + AmountB: 30.00, + FreeAmountA: 0, + FreeAmountB: 0, + Checkflag: 0, + FCode: fcode, + FCriminal: "测试病人", + Flag: 0, + } + + logger.Info("消费额度查询完成", zap.String("fcode", fcode)) + return &model.CriminalResponse{ + ResultCode: errcode.Success.Code, + ResultData: quota, + }, nil +} + +// CriminalOut 出院处理 +func (s *CriminalService) CriminalOut(ctx context.Context, fcode string) (*model.CriminalResponse, error) { + logger.Info("开始出院处理", zap.String("fcode", fcode)) + // TODO: 实现数据库操作 + + logger.Info("出院处理完成", zap.String("fcode", fcode)) + return &model.CriminalResponse{ + ResultCode: errcode.Success.Code, + ResultMsg: "出院处理成功", + }, nil +} + +// ConsumeRecord 消费记录 +func (s *CriminalService) ConsumeRecord(ctx context.Context, record *model.ConsumeRecord) (*model.CriminalResponse, error) { + logger.Info("开始保存消费记录", + zap.String("fcode", record.FCode), + zap.String("invoiceNo", record.InvoiceNo), + zap.Float64("amount", record.Amount)) + + // TODO: 实现数据库操作 + + logger.Info("消费记录保存完成", zap.String("fcode", record.FCode)) + return &model.CriminalResponse{ + ResultCode: errcode.Success.Code, + ResultMsg: "消费记录保存成功", + }, nil +} + +// RealTimeBalance 实时余额查询 +func (s *CriminalService) RealTimeBalance(ctx context.Context, fcode string) (*model.CriminalResponse, error) { + logger.Info("开始实时余额查询", zap.String("fcode", fcode)) + + // TODO: 实现数据库操作 + info := &model.CriminalInfo{ + FCode: fcode, + FName: "测试病人", + AmountA: 100.00, + AmountB: 50.00, + AmountC: 150.00, + BankAccNo: "6222021234567890", + BankAmount: 1000.00, + Fflag: 0, + Flimitflag: 0, + Flimitamt: 0, + } + + logger.Info("实时余额查询完成", zap.String("fcode", fcode)) + return &model.CriminalResponse{ + ResultCode: errcode.Success.Code, + ResultData: info, + }, nil +} + +// InvoiceSync 发票同步 +func (s *CriminalService) InvoiceSync(ctx context.Context, invoiceList []string) (*model.CriminalResponse, error) { + logger.Info("开始发票同步", zap.Strings("invoiceList", invoiceList)) + + // TODO: 实现数据库操作 + results := make([]model.InvoiceSyncResult, 0) + for _, invoice := range invoiceList { + result := model.InvoiceSyncResult{ + BankFlag: 2, + CAmount: 100.00, + FCode: "3516022343", + Origid: invoice, + SendDate: time.Now(), + } + results = append(results, result) + } + + logger.Info("发票同步完成", zap.Int("count", len(results))) + return &model.CriminalResponse{ + ResultCode: errcode.Success.Code, + ResultData: results, + }, nil +} diff --git a/internal/service/interface.go b/internal/service/interface.go new file mode 100644 index 0000000..e25274c --- /dev/null +++ b/internal/service/interface.go @@ -0,0 +1,28 @@ +package service + +import ( + "context" + + "github.com/emsoft/HospitalPay-Go/internal/model" +) + +// ICriminalService 病人服务接口 +type ICriminalService interface { + // CriminalIn 入院登记 + CriminalIn(ctx context.Context, fcode string) (*model.CriminalResponse, error) + + // ConsumeQuota 消费额度查询 + ConsumeQuota(ctx context.Context, fcode string) (*model.CriminalResponse, error) + + // CriminalOut 出院处理 + CriminalOut(ctx context.Context, fcode string) (*model.CriminalResponse, error) + + // ConsumeRecord 消费记录 + ConsumeRecord(ctx context.Context, record *model.ConsumeRecord) (*model.CriminalResponse, error) + + // RealTimeBalance 实时余额查询 + RealTimeBalance(ctx context.Context, fcode string) (*model.CriminalResponse, error) + + // InvoiceSync 发票同步 + InvoiceSync(ctx context.Context, invoiceList []string) (*model.CriminalResponse, error) +}