zoie 1 rok temu
rodzic
commit
e02bdf46ea

+ 2 - 1
common/global/constant.go

@@ -8,7 +8,8 @@ const (
 	// RedisPrefixAuth redis 权限验证前缀
 	RedisPrefixAuth = "auth:"
 	// RedisPrefixRoleApi redis 角色api
-	RedisPrefixRoleApi = "role_api:"
+	RedisPrefixRoleApi    = "role_api:"
+	RedisMSFXMedicineInfo = "msfx_info:"
 )
 
 const (

+ 7 - 2
conf/app.conf

@@ -49,10 +49,15 @@ FilterNotEnterDeptURL = "/api/medicine-template/init"
 
 # 统一身份认证
 # OAuth_baseUrl = "http://192.168.11.77:8100"
-OAuth_baseUrl = "http://127.0.0.1:8000"
+OAuth_baseUrl = "http://127.0.0.1:8001"
 # 服务发现服务信息
 Service_number = "q9YeglML"
 Service_authCode = "3EDJRaagFTVVo2Ilo80nHJfLVN1O1234"
 Service_name = "医药进销存综合管理系统"
 Service_Host = "http://127.0.0.1:8110"
-Service_RoleApiUrl = "/api/role-api"
+Service_RoleApiUrl = "/api/role-api"
+
+# 码上放心
+MSFX_baseUrl = "http://ykm.fjxtj.com/query.aspx"
+MSFX_user = "POCU9VN"
+MSFX_mock = false

+ 98 - 0
controllers/medicine.go

@@ -2,10 +2,19 @@ package controllers
 
 import (
 	"Medical_ERP/common/global"
+	"Medical_ERP/common/redis"
 	_ "Medical_ERP/common/response"
 	"Medical_ERP/dto"
 	"Medical_ERP/services"
+	"Medical_ERP/utils"
+	"encoding/json"
+	"errors"
+	"fmt"
+	beego "github.com/beego/beego/v2/server/web"
+	"github.com/go-resty/resty/v2"
 	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/beegouser"
+	"strings"
+	"time"
 )
 
 type MedicineController struct {
@@ -56,3 +65,92 @@ func (c MedicineController) BasicDataStat() {
 
 	c.OK(list, "查询成功")
 }
+
+// 码上放心药品查询
+func (c MedicineController) MSFXQuery() {
+	code := c.GetString("code")
+	if len(code) == 0 {
+		err := errors.New("码上放心追溯码不能为空")
+		c.Error(400, err, err.Error())
+		return
+	}
+	MSFX_baseUrl, _ := beego.AppConfig.String("MSFX_baseUrl")
+	MSFX_user, _ := beego.AppConfig.String("MSFX_user")
+	MSFX_mock := beego.AppConfig.DefaultBool("MSFX_mock", true)
+
+	info := make([]map[string]interface{}, 0)
+	if MSFX_mock {
+		mock := map[string]interface{}{
+			"名称":   "替硝唑片" + strings.ToUpper(utils.GenerateAppKey(2)),
+			"批号":   strings.ToUpper(utils.GenerateAppKey(4)),
+			"有效期至": "20250619",
+			"包装数量": "1",
+			"生产日期": "2023-06-20",
+			"批准文号": "国药准字H20033090",
+			"效期":   "24月",
+			"药品类别": "普通药品",
+			"规格":   "8片/盒",
+			"规格摘要": "0.5g",
+			"类型":   "片剂",
+			"厂家":   "山东鲁抗医药集团赛特有限责任公司",
+		}
+		mock_ := make(map[string]interface{})
+		mock_["product_name"] = mock["名称"]
+		mock_["enterprise_name"] = mock["厂家"]
+		mock_["spec_name"] = fmt.Sprintf("%s×%s", mock["规格摘要"], mock["规格"])
+		mock_["dosage_form_name"] = mock["类型"]
+		mock_["batch_number"] = mock["批号"]
+		date := mock["有效期至"].(string)
+		mock_["expiry_date"] = fmt.Sprintf("%s-%s-%s", date[0:4], date[4:6], date[6:8])
+		mock_["produced_date"] = mock["生产日期"]
+		mock_["approval_number"] = mock["批准文号"]
+
+		info = append(info, mock_)
+		c.OK(info, "查询成功")
+		return
+	}
+
+	err := redis.GetJson(global.RedisMSFXMedicineInfo+code, &info)
+	if err == nil {
+		c.OK(info, "查询成功")
+		return
+	}
+	client := resty.New()
+	resp, err := client.R().
+		SetQueryParams(map[string]string{
+			"user": MSFX_user,
+			"code": code,
+		}).
+		Get(MSFX_baseUrl)
+
+	if err != nil {
+		c.Error(400, err, err.Error())
+		return
+	}
+
+	if err = json.Unmarshal(resp.Body(), &info); err != nil {
+		c.Error(400, err, err.Error())
+		return
+	}
+
+	info_ := make([]map[string]interface{}, len(info))
+	for i := 0; i < len(info); i++ {
+		info_[i] = make(map[string]interface{})
+		if len(info[i]["名称"].(string)) == 0 {
+			c.Error(400, err, "药品信息不存在")
+		}
+		info_[i]["product_name"] = info[i]["名称"]
+		info_[i]["enterprise_name"] = info[i]["厂家"]
+		info_[i]["spec_name"] = fmt.Sprintf("%s×%s", info[i]["规格摘要"], info[i]["规格"])
+		info_[i]["dosage_form_name"] = info[i]["类型"]
+		info_[i]["batch_number"] = info[i]["批号"]
+		date := info[i]["有效期至"].(string)
+		info_[i]["expiry_date"] = fmt.Sprintf("%s-%s-%s", date[0:4], date[4:6], date[6:8])
+		info_[i]["produced_date"] = info[i]["生产日期"]
+		info_[i]["approval_number"] = info[i]["批准文号"]
+	}
+
+	redis.SetJson(global.RedisMSFXMedicineInfo+code, info_, 7*24*time.Hour)
+
+	c.OK(info_, "查询成功")
+}

+ 137 - 2
controllers/sales.go

@@ -9,6 +9,7 @@ import (
 	"Medical_ERP/utils"
 	"fmt"
 	"github.com/jung-kurt/gofpdf"
+	"github.com/signintech/gopdf"
 	"github.com/xuri/excelize/v2"
 	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/beegouser"
 	"os"
@@ -62,7 +63,7 @@ func (c SalesController) SalesExcel() {
 
 	deptId := beegouser.GetDeptId(c.Ctx)
 	deptName := beegouser.GetDeptName(c.Ctx)
-	list, _, err := s.SalesList(&reqData, deptId)
+	list, _, err := s.SalesListExcel(&reqData, deptId)
 	if err != nil {
 		c.Error(500, err, err.Error())
 		return
@@ -442,7 +443,7 @@ func (c SalesController) SalesStockOutExcel(reqData dto.SalesStockOutExcelReq) {
 	// 返回生成的 Excel 文件
 	c.Ctx.Output.Download("ofile/" + filename)
 }
-func (c SalesController) SalesStockOutPdf(reqData dto.SalesStockOutExcelReq) {
+func (c SalesController) SalesStockOutPdf1(reqData dto.SalesStockOutExcelReq) {
 	s := services.Sales{}
 	deptId := beegouser.GetDeptId(c.Ctx)
 	list, err := s.SalesStockOutExcel(&reqData, deptId)
@@ -573,6 +574,140 @@ func (c SalesController) SalesStockOutPdf(reqData dto.SalesStockOutExcelReq) {
 	c.Ctx.Output.Download("ofile/" + filename)
 
 }
+func (c SalesController) SalesStockOutPdf(reqData dto.SalesStockOutExcelReq) {
+	s := services.Sales{}
+	deptId := beegouser.GetDeptId(c.Ctx)
+	list, err := s.SalesStockOutExcel(&reqData, deptId)
+	if err != nil {
+		c.Error(500, err, err.Error())
+		return
+	}
+	cols := []float64{65, 29.5, 65, 53, 59, 59, 59, 29.5, 29.5, 53, 53}
+
+	header := []string{"品种", "剂型", "规格", "生产企业", "批号", "失效日期", "批准文号", "数量", "单位", "销售单价", "销售金额"}
+	rows := [][]string{}
+	money := 0.0
+	for _, row := range list {
+		temp := []string{}
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldProductName]))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldDosageFormName]))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldSpecName]))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldEnterpriseName]))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldBatchNumber]))
+		temp = append(temp, fmt.Sprintf("%s", utils.ToDate(row[models.FieldExpiryDate])))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldApprovalNumber]))
+		temp = append(temp, fmt.Sprintf("%d", utils.ToInt(row["quantity"])))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldUnitName]))
+		temp = append(temp, fmt.Sprintf("%.2f", utils.ToFloat64(row["sales_unit_price"])))
+		temp = append(temp, fmt.Sprintf("%.2f", utils.ToFloat64(row["sales_money"])))
+		rows = append(rows, temp)
+		money += utils.ToFloat64(row["sales_money"])
+	}
+	rows = append(rows, []string{"", "", "", "", "", "", "", "", "", "", ""})
+
+	pdf := &gopdf.GoPdf{}
+	pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}})
+	pdf.SetMarginTop(20)
+	pdf.SetMarginBottom(40)
+	pdf.AddPage()
+	pdf.AddTTFFont("simsun", "static/fonts/MiSans-Medium.ttf")
+	pdf.SetFont("simsun", "", 22)
+
+	titleStr := fmt.Sprintf("%s二类出库单", beegouser.GetDeptName(c.Ctx))
+	titleWd, _ := pdf.MeasureTextWidth(titleStr)
+	pdf.SetX((595 / 2) - (titleWd / 2))
+	pdf.SetY(40)
+	pdf.Text(titleStr)
+
+	curx, y := 20., 70.
+
+	pdf.SetXY(curx, y)
+
+	pdf.SetFont("simsun", "", 11)
+	pdf.Text(fmt.Sprintf("购货单位:%s", reqData.ReceivingUnit))
+	pdf.SetXY(curx+cols[0]+cols[1]+cols[2], y)
+	pdf.Text(fmt.Sprintf("下单日期:%s", reqData.Date))
+	//pdf.Text(titleX*2+20, y, fmt.Sprintf("编号:"))
+	//pdf.Text(titleX*3, y, "第1联,共3联(第1联,库房处留存)")
+
+	h := 25.0
+	pdf.SetFont("simsun", "", 12)
+	x := curx
+	y += 10
+	pdf.SetXY(curx, y)
+	for i := 0; i < len(header); i++ {
+		utils.RectFillColor(pdf, header[i], 11, x, y, cols[i], h, 0, 0, 0, gopdf.Center, gopdf.Middle)
+		x += cols[i]
+	}
+
+	pdf.SetFont("simsun", "", 10)
+	y += h
+	pdf.SetXY(curx, y)
+	h = 20.0
+	for _, row := range rows {
+		y = pdf.GetY()
+		x = curx
+
+		height := h
+
+		for j, txt := range row {
+			lineTexts, _ := pdf.SplitText(txt, cols[j])
+			//lineHt := h * float64(len(lineTexts))
+			if len(lineTexts) > 1 {
+				lineTexts, _ = pdf.SplitText(txt, cols[j]-4)
+				lineHt := h * float64(len(lineTexts)) * 0.8
+				if lineHt > height {
+					height = lineHt
+				}
+			}
+		}
+
+		for i, txt := range row {
+			width := cols[i]
+			utils.RectFillColorMultiCell(pdf, txt, 9, x, y, width, height, 0, 0, 0, gopdf.Center, gopdf.Middle)
+			x += width
+		}
+		pdf.SetNewY(y+height, height)
+	}
+
+	y = pdf.GetY()
+	pdf.SetXY(curx, y)
+	width1 := cols[0] + cols[1] + cols[2] + cols[3]
+	utils.RectFillColor(pdf, fmt.Sprintf("整单合计金额(小写):¥%.2f元", money), 9, curx, y, width1, h, 0, 0, 0, gopdf.Center, gopdf.Middle)
+	width2 := cols[4] + cols[5] + cols[6] + cols[7] + cols[8] + cols[9] + cols[10]
+	utils.RectFillColor(pdf, fmt.Sprintf("整单合计金额(大写):%s", utils.AmountConvert(money, true)), 9, curx+width1, y, width2, h, 0, 0, 0, gopdf.Center, gopdf.Middle)
+	y += h
+	y += 15
+	pdf.SetNewY(y, h+15)
+	pdf.SetX(curx)
+	pdf.Text(fmt.Sprintf("开票日期:%s", time.Now().Format("2006年01月02日")))
+	width := cols[0] + cols[1] + cols[2]
+	curx += width
+	pdf.SetX(curx)
+	pdf.Text(fmt.Sprintf("开票员:%s", reqData.Drawer))
+	width = cols[3] + cols[4]
+	curx += width
+	pdf.SetX(curx)
+
+	pdf.Text(fmt.Sprintf("发货人:%s       财务:%s", reqData.Consigner, reqData.Finance))
+	width = cols[5] + cols[6] + cols[7] + cols[8]
+	curx += width
+	pdf.SetX(curx)
+	pdf.Text(fmt.Sprintf("收货人:%s", reqData.Consignee))
+
+	filename := "二类出库单" + time.Now().Format("20060102150405") + ".pdf"
+	// 保存文件
+	if err = pdf.WritePdf("ofile/" + filename); err != nil {
+		fmt.Println(err)
+	}
+	defer func() {
+		os.Remove("ofile/" + filename)
+	}()
+
+	// 返回生成的 Excel 文件
+	c.Ctx.Output.Download("ofile/" + filename)
+
+}
 
 // SalesStockOutExport 二类出库单
 // @Summary 二类出库单

+ 509 - 20
controllers/stock_template.go

@@ -546,7 +546,7 @@ func (c StockTemplateController) StockTemplateInventoryExcel(reqData dto.StockTe
 	// 返回生成的 Excel 文件
 	c.Ctx.Output.Download("ofile/" + filename)
 }
-func (c StockTemplateController) StockTemplateInventoryPdf(reqData dto.StockTemplateInventoryExcelReq) {
+func (c StockTemplateController) StockTemplateInventoryPdf1(reqData dto.StockTemplateInventoryExcelReq) {
 	s := services.StockTemplate{}
 	deptId := beegouser.GetDeptId(c.Ctx)
 	models.InitBasicData(deptId)
@@ -764,6 +764,176 @@ func (c StockTemplateController) StockTemplateInventoryPdf(reqData dto.StockTemp
 	// 返回生成的 Excel 文件
 	c.Ctx.Output.Download("ofile/" + filename)
 }
+func (c StockTemplateController) StockTemplateInventoryPdf(reqData dto.StockTemplateInventoryExcelReq) {
+	s := services.StockTemplate{}
+	deptId := beegouser.GetDeptId(c.Ctx)
+	models.InitBasicData(deptId)
+	medicineInfo, err := s.GetMedicineInfo(deptId, map[string]interface{}{
+		"product_id":    reqData.ProductID,
+		"enterprise_id": reqData.EnterpriseID,
+		"spec_id":       reqData.SpecId,
+		"batch_number":  reqData.BatchNumber,
+	})
+	if err != nil {
+		c.Error(global.BadRequest, err, "药品信息不存在")
+		return
+	}
+	var productName, specName, unitName, dosageFormName string
+
+	if id, ok := medicineInfo[models.FieldProductID]; ok {
+		productName = models.Read_Product_Get(utils.ToInt(id))
+	}
+	if id, ok := medicineInfo[models.FieldSpecID]; ok {
+		specName = models.Read_Spec_Get(utils.ToInt(id))
+	}
+	if id, ok := medicineInfo[models.FieldUnitID]; ok {
+		unitName = models.Read_Unit_Get(utils.ToInt(id))
+	}
+	if id, ok := medicineInfo[models.FieldDosageFormID]; ok {
+		dosageFormName = models.Read_DosageForm_Get(utils.ToInt(id))
+	}
+
+	list, err := s.StockTemplateInventoryExcel(&reqData, deptId)
+	if err != nil {
+		c.Error(500, err, err.Error())
+		return
+	}
+	//cols := []float64{20, 24, 20, 18, 20, 12, 22, 20, 12, 22, 20, 12, 22, 20, 15}
+	cols := []float64{58, 73, 59, 53, 53, 35, 65, 59, 40}
+	cols1 := []float64{58, 73, 59, 53, 53, 35, 65, 59, 35, 65, 59, 35, 65, 59, 40}
+
+	rows := [][]string{}
+	for _, row := range list {
+		temp := []string{}
+		temp = append(temp, fmt.Sprintf("%v", row["date"]))
+
+		if utils.ToInt(row["stock_in_id"]) > 0 {
+			temp = append(temp, fmt.Sprintf("%s", row["forwarding_unit"]))
+		} else if utils.ToInt(row["stock_out_id"]) > 0 {
+			temp = append(temp, fmt.Sprintf("%s", row["receiving_unit"]))
+		}
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldEnterpriseName]))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldApprovalNumber]))
+		if row[models.FieldQualificationNumber] != nil {
+			temp = append(temp, fmt.Sprintf("%s", row[models.FieldQualificationNumber]))
+		} else {
+			temp = append(temp, "")
+		}
+
+		if utils.ToInt(row["stock_in_id"]) > 0 {
+			temp = append(temp, fmt.Sprintf("%d", row["total_in"]))
+			temp = append(temp, fmt.Sprintf("%s", row[models.FieldBatchNumber]))
+			temp = append(temp, fmt.Sprintf("%s", utils.ToDate(row[models.FieldExpiryDate])))
+		} else {
+			temp = append(temp, "")
+			temp = append(temp, "")
+			temp = append(temp, "")
+		}
+
+		if utils.ToInt(row["stock_out_id"]) > 0 {
+			temp = append(temp, fmt.Sprintf("%d", row["total_out"]))
+			temp = append(temp, fmt.Sprintf("%s", row[models.FieldBatchNumber]))
+			temp = append(temp, fmt.Sprintf("%s", utils.ToDate(row[models.FieldExpiryDate])))
+		} else {
+			temp = append(temp, "")
+			temp = append(temp, "")
+			temp = append(temp, "")
+		}
+
+		temp = append(temp, fmt.Sprintf("%d", row["balance"]))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldBatchNumber]))
+		temp = append(temp, fmt.Sprintf("%s", utils.ToDate(row[models.FieldExpiryDate])))
+		temp = append(temp, fmt.Sprintf("%s", row["operator"]))
+		rows = append(rows, temp)
+	}
+
+	pdf := &gopdf.GoPdf{}
+	pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 841.89, H: 595.28}})
+	pdf.SetMarginTop(20)
+	pdf.SetMarginBottom(40)
+
+	pdf.AddPage()
+	pdf.AddTTFFont("simsun", "static/fonts/MiSans-Medium.ttf")
+	pdf.SetFont("simsun", "", 22)
+	titleStr := "收发登记表"
+
+	titleWd, _ := pdf.MeasureTextWidth(titleStr)
+	pdf.SetX((842 / 2) - (titleWd / 2))
+	pdf.SetY(70)
+	pdf.Text(titleStr)
+
+	pdf.SetFont("simsun", "", 10)
+	x := 20.
+	for i := 0; i < 10; i++ {
+		x += cols1[i]
+	}
+	pdf.SetXY(x, 90)
+	pdf.Text(fmt.Sprintf("制品名称:%s 编号", productName))
+	pdf.SetXY(x, 110)
+	pdf.Text(fmt.Sprintf("剂型:%s 规格:%s 单位:%s", dosageFormName, specName, unitName))
+
+	curx := 16.
+	header := []string{"日期", "购货/发货单位", "生产企业", "批准文号", "批签发合格证编号", "收入", "支出", "结余", "经办人签字"}
+	h := 50.0
+	pdf.SetFont("simsun", "", 11)
+	x = curx
+	y := 116.
+
+	pdf.SetXY(curx, y)
+	for i := 0; i < len(header); i++ {
+		utils.RectFillColorMultiCell(pdf, header[i], 11, x, y, cols[i], h, 0, 0, 0, gopdf.Center, gopdf.Middle)
+		if header[i] == "收入" || header[i] == "支出" || header[i] == "结余" {
+			utils.RectFillColorMultiCell(pdf, header[i], 11, x, y, cols[5]+cols[6]+cols[7], h/2, 0, 0, 0, gopdf.Center, gopdf.Middle)
+			utils.RectFillColorMultiCell(pdf, "数量", 11, x, y+h/2, cols[5], h/2, 0, 0, 0, gopdf.Center, gopdf.Middle)
+			utils.RectFillColorMultiCell(pdf, "批号", 11, x+cols[5], y+h/2, cols[6], h/2, 0, 0, 0, gopdf.Center, gopdf.Middle)
+			utils.RectFillColorMultiCell(pdf, "效期", 11, x+cols[5]+cols[6], y+h/2, cols[7], h/2, 0, 0, 0, gopdf.Center, gopdf.Middle)
+			x += cols[5] + cols[6] + cols[7]
+		} else {
+			x += cols[i]
+		}
+	}
+
+	pdf.SetFont("simsun", "", 10)
+	y += h
+	pdf.SetXY(curx, y)
+	h = 20.0
+	for _, row := range rows {
+		y = pdf.GetY()
+		x = curx
+
+		height := h
+
+		for j, txt := range row {
+			lineTexts, _ := pdf.SplitText(txt, cols1[j])
+			if len(lineTexts) > 1 {
+				lineTexts, _ = pdf.SplitText(txt, cols1[j]-4)
+				lineHt := h * float64(len(lineTexts)) * 0.8
+				if lineHt > height {
+					height = lineHt
+				}
+			}
+		}
+
+		for i, txt := range row {
+			width := cols1[i]
+			utils.RectFillColorMultiCell(pdf, txt, 9, x, y, width, height, 0, 0, 0, gopdf.Center, gopdf.Middle)
+			x += width
+		}
+		pdf.SetNewY(y+height, height)
+	}
+
+	filename := "收发登记表" + time.Now().Format("20060102150405") + ".pdf"
+	// 保存文件
+	if err := pdf.WritePdf("ofile/" + filename); err != nil {
+		fmt.Println(err)
+	}
+	defer func() {
+		os.Remove("ofile/" + filename)
+	}()
+
+	// 返回生成的 Excel 文件
+	c.Ctx.Output.Download("ofile/" + filename)
+}
 func (c StockTemplateController) StockTemplateInventoryExport() {
 	reqData := dto.StockTemplateInventoryExcelReq{}
 	if err := c.ParseAndValidate(&c.Ctx.Input.RequestBody, &reqData); err != nil {
@@ -1050,7 +1220,9 @@ func (c StockTemplateController) TransportRecordWord(reqData dto.TransportRecord
 		run = para.AddRun()
 		run.Properties().SetFontFamily("宋体")
 		run.Properties().SetSize(8)
-		run.AddText(medicineInfo[models.FieldQualificationNumber].(string))
+		if medicineInfo[models.FieldQualificationNumber] != nil {
+			run.AddText(medicineInfo[models.FieldQualificationNumber].(string))
+		}
 
 		cell = row.AddCell()
 		cell.Properties().SetWidthPercent(13)
@@ -1111,7 +1283,7 @@ func (c StockTemplateController) TransportRecordWord(reqData dto.TransportRecord
 		run = para.AddRun()
 		run.Properties().SetFontFamily("宋体")
 		run.Properties().SetSize(8)
-		unitName := models.Read_Enterprise_Get(utils.ToInt(medicineInfo[models.FieldUnitID]))
+		unitName := models.Read_Unit_Get(utils.ToInt(medicineInfo[models.FieldUnitID]))
 		run.AddText(unitName)
 	}
 
@@ -1729,7 +1901,7 @@ func (c StockTemplateController) TransportRecordWord(reqData dto.TransportRecord
 	c.Ctx.Output.Download("ofile/" + filename)
 }
 
-func (c StockTemplateController) TransportRecordPdf(reqData dto.TransportRecordWordReq) {
+func (c StockTemplateController) TransportRecordPdf1(reqData dto.TransportRecordWordReq) {
 	s := services.StockTemplate{}
 	deptId := beegouser.GetDeptId(c.Ctx)
 
@@ -1739,7 +1911,7 @@ func (c StockTemplateController) TransportRecordPdf(reqData dto.TransportRecordW
 		return
 	}
 
-	cols := []float64{30, 22, 20, 27, 31, 22, 21, 11, 11}
+	cols := []float64{30, 22, 22, 27, 31, 22, 21, 11, 11}
 
 	header := []string{"品种", "生产企业", "批准文号", "批签发合格编号", "规格(剂/支或粒)", "批号", "失效日期", "数量", "单位"}
 	rows := [][]string{}
@@ -1748,7 +1920,12 @@ func (c StockTemplateController) TransportRecordPdf(reqData dto.TransportRecordW
 		temp = append(temp, fmt.Sprintf("%s", row[models.FieldProductName]))
 		temp = append(temp, fmt.Sprintf("%s", row[models.FieldEnterpriseName]))
 		temp = append(temp, fmt.Sprintf("%s", row[models.FieldApprovalNumber]))
-		temp = append(temp, fmt.Sprintf("%s", row[models.FieldQualificationNumber]))
+		if row[models.FieldQualificationNumber] == nil {
+			temp = append(temp, "")
+		} else {
+			temp = append(temp, fmt.Sprintf("%s", row[models.FieldQualificationNumber]))
+		}
+
 		temp = append(temp, fmt.Sprintf("%s", row[models.FieldSpecName]))
 		temp = append(temp, fmt.Sprintf("%s", row[models.FieldBatchNumber]))
 		temp = append(temp, fmt.Sprintf("%s", utils.ToDate(row[models.FieldExpiryDate])))
@@ -1806,12 +1983,45 @@ func (c StockTemplateController) TransportRecordPdf(reqData dto.TransportRecordW
 	marginCell := 4. // margin of top/bottom of cell
 	y = pdf.GetY()
 	pdf.SetXY(curx, y)
+	//for _, row := range rows {
+	//	curx, y = pdf.GetXY()
+	//	if y > pageh-mbottom-marginCell {
+	//		pdf.AddPage()
+	//		y = pdf.GetY()
+	//	}
+	//	x := curx
+	//
+	//	height := 0.
+	//	_, lineHt := pdf.GetFontSize()
+	//
+	//	for i, txt := range row {
+	//		lines := pdf.SplitLines([]byte(txt), cols[i])
+	//		h = float64(len(lines))*lineHt + marginCell*float64(len(lines))
+	//		if h > height {
+	//			height = h
+	//		}
+	//	}
+	//	//// add a new page if the height of the row doesn't fit on the page
+	//	//if pdf.GetY()+height > pageh-mbottom {
+	//	//	pdf.AddPage()
+	//	//	y = pdf.GetY()
+	//	//}
+	//	for i, txt := range row {
+	//		width := cols[i]
+	//		if len(txt) == 0 {
+	//			height = lineHt + marginCell
+	//		}
+	//		pdf.Rect(x, y, width, height, "")
+	//		pdf.MultiCell(width, lineHt+marginCell, txt, "", "CM", false)
+	//		x += width
+	//		pdf.SetXY(x, y)
+	//	}
+	//
+	//	pdf.SetXY(curx, y+height)
+	//}
+
 	for _, row := range rows {
 		curx, y = pdf.GetXY()
-		if y > pageh-mbottom-marginCell {
-			pdf.AddPage()
-			y = pdf.GetY()
-		}
 		x := curx
 
 		height := 0.
@@ -1824,22 +2034,19 @@ func (c StockTemplateController) TransportRecordPdf(reqData dto.TransportRecordW
 				height = h
 			}
 		}
-		//// add a new page if the height of the row doesn't fit on the page
-		//if pdf.GetY()+height > pageh-mbottom {
-		//	pdf.AddPage()
-		//	y = pdf.GetY()
-		//}
+		// add a new page if the height of the row doesn't fit on the page
+		if pdf.GetY()+height > pageh-mbottom {
+			pdf.AddPage()
+			y = pdf.GetY()
+		}
 		for i, txt := range row {
 			width := cols[i]
-			if len(txt) == 0 {
-				height = lineHt + marginCell
-			}
 			pdf.Rect(x, y, width, height, "")
-			pdf.MultiCell(width, lineHt+marginCell, txt, "", "CM", false)
+
+			pdf.MultiCell(width, lineHt+marginCell, txt, "", "C", false)
 			x += width
 			pdf.SetXY(x, y)
 		}
-
 		pdf.SetXY(curx, y+height)
 	}
 
@@ -1969,6 +2176,288 @@ func (c StockTemplateController) TransportRecordPdf(reqData dto.TransportRecordW
 	c.Ctx.Output.Download("ofile/" + filename)
 
 }
+func (c StockTemplateController) TransportRecordPdf(reqData dto.TransportRecordWordReq) {
+	s := services.StockTemplate{}
+	deptId := beegouser.GetDeptId(c.Ctx)
+
+	list, err := s.StockTemplateTransportRecordWord(&reqData, deptId)
+	if err != nil {
+		c.Error(500, err, err.Error())
+		return
+	}
+
+	cols := []float64{83, 50, 55, 72, 72, 50, 66, 50, 27, 30}
+
+	header := []string{"品种", "生产企业", "批准文号", "批签发合格编号", "规格(剂/支或粒)", "生产日期", "批号", "失效日期", "数量", "单位"}
+	rows := [][]string{}
+	for _, row := range list {
+		temp := []string{}
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldProductName]))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldEnterpriseName]))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldApprovalNumber]))
+		if row[models.FieldQualificationNumber] == nil {
+			temp = append(temp, "")
+		} else {
+			temp = append(temp, fmt.Sprintf("%s", row[models.FieldQualificationNumber]))
+		}
+
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldSpecName]))
+		temp = append(temp, fmt.Sprintf("%s", utils.ToDate(row[models.FieldProducedDate])))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldBatchNumber]))
+		temp = append(temp, fmt.Sprintf("%s", utils.ToDate(row[models.FieldExpiryDate])))
+		temp = append(temp, fmt.Sprintf("%d", utils.ToInt(row["quantity"])))
+		temp = append(temp, fmt.Sprintf("%s", row[models.FieldUnitName]))
+		rows = append(rows, temp)
+	}
+	if len(list) < 11 {
+		for i := 0; i < 11-len(list); i++ {
+			rows = append(rows, []string{"", "", "", "", "", "", "", "", "", ""})
+		}
+	}
+
+
+	pdf := &gopdf.GoPdf{}
+	pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}})
+	pdf.SetMarginTop(40)
+	pdf.SetMarginBottom(40)
+
+	pdf.AddPage()
+	pdf.AddTTFFont("simsun", "static/fonts/MiSans-Medium.ttf")
+	pdf.SetFont("simsun", "", 22)
+
+	pdf.SetMargins(2, 5, 5, 5)
+
+	titleStr := "表3-4 运输记录表"
+	textw, _ := pdf.MeasureTextWidth(titleStr)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(40)
+	pdf.Text(titleStr)
+
+	pdf.SetFont("simsun", "", 16)
+	titleStr = "(各级通用)"
+	textw, _ = pdf.MeasureTextWidth(titleStr)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(60)
+	pdf.Text(titleStr)
+
+	pdf.SetFont("simsun", "", 10)
+	curx, y := 20., pdf.GetY()
+	y += 25
+	pdf.SetXY(curx, y)
+	pdf.Text("运输工具: □冷藏车  □运输车  □普通车辆  □无  □其他")
+	y += 16
+	pdf.SetXY(curx, y)
+	pdf.Text("冷藏工具: □冷藏车  □车载冷藏箱  □冷藏箱或冷藏包  □其他")
+	y += 16
+	pdf.SetXY(curx, y)
+	pdf.Text("配送方式: □本级配送(车牌号:_______) □下级自运(车牌号:_______)")
+
+	y += 20
+	pdf.SetXY(curx, y)
+	pdf.Text("运输情况:")
+	y += 6
+	pdf.SetXY(curx, y)
+	h := 20.0
+	x := curx
+	pdf.SetFont("simsun", "", 9)
+	for i := 0; i < len(header); i++ {
+		utils.RectFillColor(pdf, header[i], 9, x, y, cols[i], h, 0, 0, 0, gopdf.Center, gopdf.Middle)
+		x += cols[i]
+	}
+	y += h
+	pdf.SetXY(curx, y)
+	pdf.SetFont("simsun", "", 8)
+
+	for _, row := range rows {
+		curx, y = pdf.GetX(), pdf.GetY()
+		x = curx
+
+		height := h
+		for i, txt := range row {
+			lineTexts, _ := pdf.SplitText(txt, cols[i])
+			//lineHt := h * float64(len(lineTexts))
+			if len(lineTexts) > 1 {
+				lineTexts, _ = pdf.SplitText(txt, cols[i]-4)
+				lineHt := h * float64(len(lineTexts)) * 0.6
+				if lineHt > height {
+					height = lineHt
+				}
+			}
+		}
+
+		for i, txt := range row {
+			width := cols[i]
+			utils.RectFillColorMultiCell(pdf, txt, 9, x, y, width, height, 0, 0, 0, gopdf.Center, gopdf.Middle)
+			x += width
+		}
+		pdf.SetNewY(y+height, height)
+		pdf.SetX(curx)
+	}
+	pdf.SetFont("simsun", "", 9)
+	y = pdf.GetY()
+	y += 20
+	pdf.SetNewY(y, 20)
+	if pdf.GetY() < 30 {
+		pdf.SetY(30)
+	}
+	pdf.SetX(curx)
+	pdf.Text("运输温度记录:")
+	header2 := []string{"", "日期/时间", "储存温度", "冰排状态", "环境温度"}
+	cols2 := []float64{55, 210, 105, 94, 91}
+	y = pdf.GetY()
+	y += 5
+	h = 35.0
+	pdf.SetNewY(y, h)
+	if pdf.GetY() < 30 {
+		pdf.SetY(30)
+	}
+	y = pdf.GetY()
+	pdf.SetX(curx)
+	x = curx
+	for i := 0; i < len(header2); i++ {
+		utils.RectFillColor(pdf, header2[i], 9, x, y, cols2[i], h, 0, 0, 0, gopdf.Center, gopdf.Middle)
+		x += cols2[i]
+	}
+	y = pdf.GetY()
+	y += h
+	pdf.SetNewY(y, h)
+	if pdf.GetY() < 30 {
+		pdf.SetY(30)
+	}
+	pdf.SetX(curx)
+	row2 := [][]string{
+		{"启运", "______年___月___日___时___分", "________℃", "", "________℃"},
+		{"途中", "______年___月___日___时___分", "________℃", "————", "________℃"},
+		{"到达", "______年___月___日___时___分", "________℃", "", "________℃"},
+	}
+
+	for j, row := range row2 {
+		curx, y = pdf.GetX(), pdf.GetY()
+		x = curx
+		pdf.SetTextColor(0, 0, 0)
+
+		height := h
+		if j == 1 {
+			height = height * 2
+		}
+		for i, txt := range row {
+			width := cols2[i]
+			txtWd, _ := pdf.MeasureTextWidth(txt)
+
+			txtX := x + (width-txtWd)/2
+
+			pdf.SetLineWidth(0.8)
+			pdf.SetFillColor(255, 255, 255) //setup fill color
+			pdf.SetLineType("")             // 线条样式
+			pdf.RectFromUpperLeftWithStyle(x, y, width, height, "FD")
+
+			if j == 1 {
+				if i == 1 || i == 2 || i == 4 {
+					txtY := y + height/5*2
+					pdf.SetXY(txtX, txtY)
+					pdf.Text(txt)
+					txtY = y + height/5*4
+					pdf.SetXY(txtX, txtY)
+					pdf.Text(txt)
+				} else {
+					txtY := y + height/5*3
+					pdf.SetXY(txtX, txtY)
+					pdf.Text(txt)
+				}
+			} else {
+				txtY := y + height/3*2
+				pdf.SetXY(txtX, txtY)
+				pdf.Text(txt)
+			}
+
+			x += width
+		}
+
+
+		pdf.SetNewY(y+height,height)
+
+		if pdf.GetY() < 30 || pdf.GetY() > 810 {
+			pdf.SetY(30)
+		}
+		pdf.SetX(curx)
+	}
+
+	y = pdf.GetY()
+	y += 20
+	pdf.SetNewY(y, 20)
+	if pdf.GetY() < 30 {
+		pdf.SetY(30)
+	}
+	pdf.SetX(curx)
+	pdf.Text("启运至到达行驶里程数:_________千米")
+
+	y = pdf.GetY()
+	y += 25
+	pdf.SetNewY(y, 25)
+	if pdf.GetY() < 30 {
+		pdf.SetY(30)
+	}
+	pdf.SetX(curx)
+	y = pdf.GetY()
+	pdf.Text("发货单位:")
+	txtWd, _ := pdf.MeasureTextWidth("发货单位:")
+	pdf.SetLineWidth(0.8)
+	pdf.SetXY(curx+txtWd, y)
+	pdf.Text(beegouser.GetDeptName(c.Ctx))
+	pdf.Line(57, y+3, 207, y+3)
+
+	pdf.SetXY(300, y)
+	pdf.Text("发货人签名:")
+	txtWd, _ = pdf.MeasureTextWidth("发货人签名:")
+	pdf.Line(345, y+3, 495, y+3)
+
+	y = pdf.GetY()
+	y += 25
+	pdf.SetNewY(y, 25)
+	if pdf.GetY() < 30 {
+		pdf.SetY(30)
+	}
+	pdf.SetX(curx)
+	y = pdf.GetY()
+	pdf.Text("收货单位:")
+	txtWd, _ = pdf.MeasureTextWidth("收货单位:")
+	pdf.SetXY(curx+txtWd, y)
+	pdf.Text(beegouser.GetDeptName(c.Ctx))
+	pdf.Line(57, y+3, 207, y+3)
+
+	pdf.SetXY(300, y)
+	pdf.Text("收货人签名:")
+	txtWd, _ = pdf.MeasureTextWidth("收货人签名:")
+	pdf.Line(345, y+3, 495, y+3)
+
+	y = pdf.GetY()
+	y += 20
+	pdf.SetNewY(y, 20)
+	if pdf.GetY() < 30 {
+		pdf.SetY(30)
+	}
+	pdf.SetX(curx)
+	pdf.SetCharSpacing(0.5)
+	txt := "填表说明:本表供疫苗配送企业、疾病预防控制机构、接种单位疫苗运输时填写;出入库单号为单位编码+年月日+2位流水号;运输超过6小时需记录途中温度,间隔不超过6小时;使用无自动温度显示的冰排保冷设备时,只在启运和达到时填写冰排状态(冻结、冰水混合物、完全融化)。"
+	pdf.MultiCell(&gopdf.Rect{W: 555, H: 50}, txt)
+
+	pdf.AddFooter(func() {
+		pdf.SetY(y + 15)
+		pdf.Cell(nil, fmt.Sprintf("第 %d 页 / 共 %d 页", pdf.GetNumberOfPages(), pdf.GetNumberOfPages()))
+	})
+	filename := "运输记录表" + time.Now().Format("20060102150405") + ".pdf"
+	// 保存文件
+	if err = pdf.WritePdf("ofile/" + filename); err != nil {
+		fmt.Println(err)
+	}
+	defer func() {
+		os.Remove("ofile/" + filename)
+	}()
+
+	// 返回生成的 Excel 文件
+	c.Ctx.Output.Download("ofile/" + filename)
+
+}
 
 // TransportRecordExport 运输记录表
 // @Summary 收发登记表word

+ 12 - 12
dto/stock_template.go

@@ -58,12 +58,12 @@ func (s *StockTemplateInDeleteReq) GetId() interface{} {
 type BatchStockTemplateInInsertReq struct {
 	StockInList []struct {
 		Id             int                    `json:"id" comment:"id" swaggerignore:"true"`
-		MedicineInfo   map[string]interface{} `json:"medicineInfo"`   // 药品信息
-		Quantity       int                    `json:"quantity"`       // 数量
-		UnitPrice      float32                `json:"unitPrice"`      // 购入单价
-		Operator       string                 `json:"operator"`       // 经办人
-		ForwardingUnit string                 `json:"forwardingUnit"` // 发货单位
-		Date           string                 `json:"date"`           // 入库日期
+		MedicineInfo   map[string]interface{} `json:"medicineInfo"`            // 药品信息
+		Quantity       int                    `json:"quantity"`                // 数量
+		UnitPrice      float32                `json:"unitPrice"`               // 购入单价
+		Operator       string                 `json:"operator"`                // 经办人
+		ForwardingUnit string                 `json:"forwardingUnit"`          // 发货单位
+		Date           string                 `json:"date" valid:"MinSize(1)"` // 入库日期
 	} `json:"stockInList"`
 
 	common.ControlBy `swaggerignore:"true"`
@@ -73,12 +73,12 @@ type BatchStockTemplateInInsertReq struct {
 type BatchStockTemplateOutInsertReq struct {
 	StockOutList []struct {
 		Id            int                    `json:"id" comment:"id" swaggerignore:"true"`
-		MedicineInfo  map[string]interface{} `json:"medicineInfo"`  // 药品信息
-		Quantity      int                    `json:"quantity"`      // 数量
-		UnitPrice     float32                `json:"unitPrice"`     // 购入单价
-		Operator      string                 `json:"operator"`      // 经办人
-		ReceivingUnit string                 `json:"receivingUnit"` // 收货单位
-		Date          string                 `json:"date"`          // 出库日期
+		MedicineInfo  map[string]interface{} `json:"medicineInfo"`            // 药品信息
+		Quantity      int                    `json:"quantity"`                // 数量
+		UnitPrice     float32                `json:"unitPrice"`               // 购入单价
+		Operator      string                 `json:"operator"`                // 经办人
+		ReceivingUnit string                 `json:"receivingUnit"`           // 收货单位
+		Date          string                 `json:"date" valid:"MinSize(1)"` // 出库日期
 	} `json:"stockOutList"`
 	common.ControlBy `swaggerignore:"true"`
 }

+ 5 - 5
go.mod

@@ -9,7 +9,7 @@ require (
 	github.com/gin-gonic/gin v1.8.1
 	github.com/go-basic/uuid v1.0.0
 	github.com/go-redis/redis/v7 v7.4.0
-	github.com/go-resty/resty/v2 v2.7.0
+	github.com/go-resty/resty/v2 v2.11.0
 	github.com/go-sql-driver/mysql v1.7.0
 	github.com/gobwas/glob v0.2.3
 	github.com/google/uuid v1.3.0
@@ -97,10 +97,10 @@ require (
 	github.com/urfave/cli v1.22.1 // indirect
 	github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect
 	github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect
-	golang.org/x/crypto v0.12.0 // indirect
-	golang.org/x/net v0.14.0 // indirect
-	golang.org/x/sys v0.11.0 // indirect
-	golang.org/x/text v0.12.0 // indirect
+	golang.org/x/crypto v0.16.0 // indirect
+	golang.org/x/net v0.19.0 // indirect
+	golang.org/x/sys v0.15.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
 	golang.org/x/tools v0.7.0 // indirect
 	google.golang.org/protobuf v1.30.0 // indirect
 	gopkg.in/AlecAivazis/survey.v1 v1.8.5 // indirect

+ 16 - 0
go.sum

@@ -202,6 +202,8 @@ github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1
 github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
 github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
 github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
+github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
+github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
@@ -666,6 +668,9 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
 golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
 golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
 golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
+golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -760,6 +765,9 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
 golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
 golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -850,6 +858,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -858,6 +869,7 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
 golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -873,11 +885,15 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
 golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

+ 1 - 0
routers/medicine.go

@@ -10,6 +10,7 @@ func init() {
 	medicine := beego.NewNamespace("/api/medicine",
 		beego.NSRouter("/batch-number", &controllers.MedicineController{}, "*:BatchNumber"),
 		beego.NSRouter("/basic-data-stat", &controllers.MedicineController{}, "*:BasicDataStat"),
+		beego.NSRouter("/msfx-query", &controllers.MedicineController{}, "*:MSFXQuery"),
 	)
 	//注册 namespace
 	beego.AddNamespace(medicine)

+ 31 - 15
services/medicine_template.go

@@ -101,42 +101,58 @@ func (e *MedicineTemplate) ListForStock(list *[]dto.MedicineTemplateForStockRes,
 
 	return nil
 }
-func (e *MedicineTemplate) ListForStockInScanCode(list *[]dto.MedicineTemplateForStockRes, count *int64, p *actions.DataPermission) error {
+func (e *MedicineTemplate) ListForStockInScanCode(res *[]dto.MedicineTemplateForStockRes, count *int64, p *actions.DataPermission) error {
 	var err error
 	var data models.MedicineTemplate
+	var list []dto.MedicineTemplateForStockRes
 
 	err = db.DB.Model(&data).
 		Scopes(
 			actions.Permission(data.TableName(), p),
 		).
 		Order("sort").
-		Find(list).Limit(-1).Offset(-1).
+		Find(&list).Limit(-1).Offset(-1).
 		Count(count).Error
 	if err != nil {
 		logs.Error("db error: %s ", err)
 		return global.GetFailedErr
 	}
-	for i := 0; i < len(*list); i++ {
-		switch (*list)[i].Type {
+	for i := 0; i < len(list); i++ {
+		switch list[i].Type {
 		case 1:
-			(*list)[i].Type = 6
-			(*list)[i].FieldName = models.FieldProductName
+			list[i].Type = 6
+			list[i].FieldName = models.FieldProductName
 		case 2:
-			(*list)[i].Type = 6
-			(*list)[i].FieldName = models.FieldEnterpriseName
+			list[i].Type = 6
+			list[i].FieldName = models.FieldEnterpriseName
 		case 3:
-			(*list)[i].Type = 6
-			(*list)[i].FieldName = models.FieldSpecName
+			list[i].Type = 6
+			list[i].FieldName = models.FieldSpecName
 		case 4:
-			(*list)[i].Type = 6
-			(*list)[i].FieldName = models.FieldDosageFormName
-		case 5:
-			(*list)[i].Type = 6
-			(*list)[i].FieldName = models.FieldUnitName
+			list[i].Type = 6
+			list[i].FieldName = models.FieldDosageFormName
+			//case 5:
+			//	(*list)[i].Type = 6
+			//	(*list)[i].FieldName = models.FieldUnitName
 		}
 
 	}
 
+	for i, v := range list {
+		if list[i].FieldName != models.FieldProductName &&
+			list[i].FieldName != models.FieldEnterpriseName &&
+			list[i].FieldName != models.FieldDosageFormName &&
+			list[i].FieldName != models.FieldSpecName &&
+			list[i].FieldName != models.FieldBatchNumber &&
+			list[i].FieldName != models.FieldExpiryDate &&
+			list[i].FieldName != models.FieldApprovalNumber &&
+			list[i].FieldName != models.FieldProducedDate {
+			continue
+		}
+		*res = append(*res, v)
+	}
+	*count = int64(len(*res))
+
 	return nil
 }
 func (e *MedicineTemplate) ListForStockOut(res *[]dto.MedicineTemplateForStockRes, count *int64, p *actions.DataPermission) error {

+ 60 - 0
services/sales.go

@@ -38,6 +38,7 @@ func (e *Sales) SalesList(c *dto.SalesPageReq, deptId int) (list []map[string]in
 		whereSql += " AND stock_out.receiving_unit like '%" + c.ReceivingUnit + "%'"
 	}
 	err = db.DB.Table("stock_out").
+		Select(mtable + ".*,stock_out.*,stock_out.unit_price as sales_unit_price").
 		Scopes(
 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
 		).
@@ -75,6 +76,63 @@ func (e *Sales) SalesList(c *dto.SalesPageReq, deptId int) (list []map[string]in
 	}
 	return list, count, nil
 }
+func (e *Sales) SalesListExcel(c *dto.SalesPageReq, deptId int) (list []map[string]interface{}, count int64, err error) {
+
+	mtable := models.GetMedicineInfoTableName(deptId)
+	whereSql := "stock_out.dept_id = " + strconv.Itoa(deptId) + " AND unit_price > 0 AND stock_out.deleted_at is null"
+	if c.ProductID > 0 {
+		whereSql += " AND " + mtable + ".product_id = " + strconv.Itoa(c.ProductID)
+	}
+	if c.EnterpriseID > 0 {
+		whereSql += " AND " + mtable + ".enterprise_id = " + strconv.Itoa(c.EnterpriseID)
+	}
+	if len(c.BatchNumber) > 0 {
+		whereSql += " AND " + mtable + ".batch_number = " + c.BatchNumber
+	}
+	if len(c.StartDate) > 0 {
+		whereSql += " AND stock_out.date >= '" + c.StartDate + "'"
+	}
+	if len(c.EndDate) > 0 {
+		whereSql += " AND stock_out.date <= '" + c.EndDate + "'"
+	}
+	if len(c.ReceivingUnit) > 0 {
+		whereSql += " AND stock_out.receiving_unit like '%" + c.ReceivingUnit + "%'"
+	}
+	err = db.DB.Table("stock_out").
+		Select(mtable + ".*,stock_out.*,stock_out.unit_price as sales_unit_price").
+		Joins("left join " + mtable + " on stock_out.medicine_id = " + mtable + ".id").
+		Where(whereSql).
+		Scan(&list).Error
+	if err != nil {
+		logs.Error("db error: %s ", err)
+		return list, count, global.GetFailedErr
+	}
+	models.InitBasicData(deptId)
+	for i := 0; i < len(list); i++ {
+		list[i]["purchase_unit_price"] = utils.ToFloat64(list[i]["purchase_unit_price"])
+		list[i]["sales_unit_price"] = utils.ToFloat64(list[i]["sales_unit_price"])
+		// 购进金额
+		list[i]["purchase_money"] = utils.ToFloat64(list[i]["purchase_unit_price"]) * utils.ToFloat64(list[i]["quantity"])
+		// 销售金额
+		list[i]["sales_money"] = utils.ToFloat64(list[i]["sales_unit_price"]) * utils.ToFloat64(list[i]["quantity"])
+		if id, ok := list[i][models.FieldProductID]; ok {
+			list[i][models.FieldProductName] = models.Read_Product_Get(utils.ToInt(id))
+		}
+		if id, ok := list[i][models.FieldEnterpriseID]; ok {
+			list[i][models.FieldEnterpriseName] = models.Read_Enterprise_Get(utils.ToInt(id))
+		}
+		if id, ok := list[i][models.FieldSpecID]; ok {
+			list[i][models.FieldSpecName] = models.Read_Spec_Get(utils.ToInt(id))
+		}
+		if id, ok := list[i][models.FieldUnitID]; ok {
+			list[i][models.FieldUnitName] = models.Read_Unit_Get(utils.ToInt(id))
+		}
+		if id, ok := list[i][models.FieldDosageFormID]; ok {
+			list[i][models.FieldDosageFormName] = models.Read_DosageForm_Get(utils.ToInt(id))
+		}
+	}
+	return list, count, nil
+}
 
 // 销售报表
 func (e *Sales) SalesReportList(c *dto.SalesPageReq, deptId int) (list []map[string]interface{}, err error) {
@@ -155,6 +213,7 @@ func (e *Sales) SalesOrderList(c *dto.SalesOrderPageReq, deptId int) (list []map
 		whereSql += " AND stock_out.receiving_unit like '%" + c.ReceivingUnit + "%'"
 	}
 	err = db.DB.Table("stock_out").
+		Select(mtable + ".*,stock_out.*,stock_out.unit_price as sales_unit_price").
 		Scopes(
 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
 		).
@@ -202,6 +261,7 @@ func (e *Sales) SalesStockOutExcel(c *dto.SalesStockOutExcelReq, deptId int) (li
 		whereSql += " AND stock_out.receiving_unit like '%" + c.ReceivingUnit + "%'"
 	}
 	err = db.DB.Table("stock_out").
+		Select(mtable + ".*,stock_out.*,stock_out.unit_price as sales_unit_price").
 		Joins("left join " + mtable + " on stock_out.medicine_id = " + mtable + ".id").
 		Where(whereSql).
 		Scan(&list).Error

+ 17 - 32
services/stock_template.go

@@ -762,44 +762,28 @@ func (e *StockTemplate) StockTemplateOutEdit(c *dto.StockTemplateOutEditReq) err
 	var err error
 	// 检查药品信息是否已存在
 	medicineInfo, err := e.GetMedicineInfo(c.DeptId, c.MedicineInfo)
-	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
+	if err != nil {
 		logs.Error("db error: %s", err)
-		return global.UpdateFailedErr
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return errors.New("药品信息不存在,禁止出库")
+		} else {
+			return global.UpdateFailedErr
+		}
+
 	}
 	var medicineInfoId int
 
 	tx := db.DB.Begin()
-	// 如果药品信息不存在,则创建新的药品信息
-	if medicineInfo == nil {
-		sql := "INSERT INTO " + models.GetMedicineInfoTableName(c.DeptId) + " SET "
-		for k, v := range c.MedicineInfo {
-			sql += fmt.Sprintf("`%s`='%v',", k, v)
-		}
-		sql += fmt.Sprintf("`%s`='%v',", "purchase_unit_price", c.UnitPrice)
 
-		sql = sql[:len(sql)-1]
-		err = tx.Exec(sql).Error
-		if err != nil {
-			tx.Rollback()
-			logs.Error("db error: %s", err)
-			return global.UpdateFailedErr
-		}
-		err = tx.Raw("SELECT LAST_INSERT_ID()").Scan(&medicineInfoId).Error
-		if err != nil {
-			tx.Rollback()
-			logs.Error("db error: %s", err)
-			return global.UpdateFailedErr
-		}
-	} else {
-		medicineInfoId = utils.ToInt(medicineInfo["id"])
-		c.MedicineInfo["purchase_unit_price"] = c.UnitPrice
-		err = tx.Table(models.GetMedicineInfoTableName(c.DeptId)).Where("id = ?", medicineInfoId).Updates(c.MedicineInfo).Error
-		if err != nil {
-			tx.Rollback()
-			logs.Error("db error: %s", err)
-			return global.UpdateFailedErr
-		}
+	medicineInfoId = utils.ToInt(medicineInfo["id"])
+	c.MedicineInfo["sales_unit_price"] = c.UnitPrice
+	err = tx.Table(models.GetMedicineInfoTableName(c.DeptId)).Where("id = ?", medicineInfoId).Updates(c.MedicineInfo).Error
+	if err != nil {
+		tx.Rollback()
+		logs.Error("db error: %s", err)
+		return global.UpdateFailedErr
 	}
+
 	var StockOutInfo models.StockOut
 	// 查询出库信息
 	err = tx.Model(StockOutInfo).Where("id = ? AND dept_id = ?", c.Id, c.DeptId).Find(&StockOutInfo).Error
@@ -1119,6 +1103,7 @@ func (e *StockTemplate) BatchStockTemplateOut(req *dto.BatchStockTemplateOutInse
 func (e *StockTemplate) StockTemplateOutScanCode(req *dto.BatchStockTemplateOutInsertReq) error {
 	tx := db.DB.Begin()
 	for _, c := range req.StockOutList {
+		medicineName := c.MedicineInfo[models.FieldProductName]
 		// 初始化药品信息
 		err := e.FirstOrCreateMedicineInfo(req.DeptId, req.CreateBy, &c.MedicineInfo)
 		if err != nil {
@@ -1151,7 +1136,7 @@ func (e *StockTemplate) StockTemplateOutScanCode(req *dto.BatchStockTemplateOutI
 		}
 		if mi.Balance < c.Quantity {
 			tx.Rollback()
-			return errors.New(fmt.Sprintf("【%s】库存量【%d】小于出库库存量【%d】,出库失败", c.MedicineInfo[models.FieldProductName], mi.Balance, c.Quantity))
+			return errors.New(fmt.Sprintf("【%s】库存量【%d】小于出库库存量【%d】,出库失败", medicineName, mi.Balance, c.Quantity))
 		}
 
 		err = tx.Table(models.GetMedicineInfoTableName(req.DeptId)).Where("id = ?", medicineInfoId).Update("sales_unit_price", c.UnitPrice).Error

+ 13 - 0
utils/comm_test.go

@@ -1,6 +1,7 @@
 package utils
 
 import (
+	"fmt"
 	"github.com/beego/beego/v2/core/logs"
 	"testing"
 )
@@ -9,5 +10,17 @@ import (
 func TestAmountConvert(t *testing.T) {
 	en := AmountConvert(521.71, true)
 	logs.Info(en)
+	cols := []float64{20, 24, 20, 18, 20, 12, 22, 20, 12, 22, 20, 12, 22, 20, 15}
 
+	sum := 0.
+	for _, col := range cols {
+		sum += col
+	}
+	cols1 := []string{}
+	for _, col := range cols {
+		fmt.Print(fmt.Sprintf("%.2f", col/sum*820), "     ")
+		cols1 = append(cols1, fmt.Sprintf("%.2f,", col/sum*820))
+	}
+
+	fmt.Println(cols1)
 }

+ 85 - 0
utils/pdf.go

@@ -0,0 +1,85 @@
+package utils
+
+import (
+	"github.com/signintech/gopdf"
+)
+
+const (
+	ValignTop    = 1
+	ValignMiddle = 2
+	ValignBottom = 3
+)
+
+const (
+	AlignLeft   = 4
+	AlignCenter = 5
+	AlignRight  = 6
+)
+
+func RectFillColor(pdf *gopdf.GoPdf,
+	text string,
+	fontSize int,
+	x, y, w, h float64,
+	r, g, b uint8,
+	align, valign int,
+) {
+
+	pdf.SetLineWidth(0.8)
+
+	pdf.SetTextColor(r, g, b)
+	pdf.SetX(x)
+
+	pdf.SetY(y)
+	pdf.CellWithOption(&gopdf.Rect{W: w, H: h}, text, gopdf.CellOption{Align: align | valign,
+		Border: gopdf.Left | gopdf.Right | gopdf.Bottom | gopdf.Top,
+	})
+
+}
+
+func RectFillColorMultiCell(pdf *gopdf.GoPdf,
+	text string,
+	fontSize int,
+	x, y, w, h float64,
+	r, g, b uint8,
+	align, valign int,
+) {
+
+	pdf.SetLineWidth(0.8)
+	pdf.SetFillColor(255, 255, 255) //setup fill color
+	pdf.RectFromUpperLeftWithStyle(x, y, w, h, "FD")
+	lineTexts, _ := pdf.SplitText(text, w)
+	if len(lineTexts) == 0 {
+		pdf.SetX(x)
+		pdf.SetY(y)
+		pdf.MultiCell(&gopdf.Rect{W: w, H: h}, "")
+		return
+	}
+
+	if len(lineTexts) > 1 {
+		w -= 4
+		lineTexts, _ = pdf.SplitText(text, w)
+		x += 4
+	} else {
+		if align == gopdf.Center {
+			textw, _ := pdf.MeasureTextWidth(lineTexts[0])
+			x = x + (w / 2) - (textw / 2)
+		} else if align == gopdf.Right {
+			textw, _ := pdf.MeasureTextWidth(lineTexts[0])
+			x = x + w - textw
+		}
+	}
+
+	pdf.SetTextColor(r, g, b)
+
+	pdf.SetX(x)
+
+	if valign == gopdf.Middle {
+		y = y + (h-float64(fontSize*len(lineTexts)))/2
+	} else if valign == gopdf.Bottom {
+		y = y + h - float64(fontSize*len(lineTexts[0]))
+	}
+
+	pdf.SetY(y)
+	pdf.MultiCell(&gopdf.Rect{W: w, H: h}, text)
+
+}