소스 검색

wip:管理后台开票红冲

wangkaiyue 1 년 전
부모
커밋
a3c87d72f6
5개의 변경된 파일175개의 추가작업 그리고 105개의 파일을 삭제
  1. 29 0
      internal/consts/consts.go
  2. 65 35
      internal/service/invoiceCallback.go
  3. 38 47
      internal/service/invoiceCallback_red.go
  4. 42 23
      internal/service/invoiceMake.go
  5. 1 0
      internal/service/tripartiteCommon.go

+ 29 - 0
internal/consts/consts.go

@@ -2,8 +2,10 @@ package consts
 
 import (
 	"context"
+	"fmt"
 	"github.com/gogf/gf/v2/errors/gerror"
 	"github.com/gogf/gf/v2/frame/g"
+	"strings"
 	"time"
 )
 
@@ -16,6 +18,8 @@ var (
 	AuthTimeOut      = gerror.New("验证超时")
 	WaitTimeOut      = gerror.New("等待超时")
 	InvoiceStartTime time.Time
+
+	taxCodeItem []*TaxCodeItem
 )
 
 func init() {
@@ -27,9 +31,34 @@ func init() {
 	if err != nil {
 		g.Log().Panic(ctx, "发票开始时间异常")
 	}
+
+	if err := g.Cfg().MustGet(ctx, "taxCodeList").Struct(&taxCodeItem); err != nil {
+		g.Log().Panic(ctx, "获取维护的开票项异常")
+	}
+	fmt.Println(taxCodeItem)
 }
 
 const (
 	DateFormat_Full  = "2006-01-02 15:04:05"
 	DateFormat_Short = "2006-01-02"
 )
+
+type TaxCodeItem struct {
+	Name string
+	Code string
+}
+
+// GetTaxCodeByName 获取开票项
+func GetTaxCodeByName(name string) string {
+	if name == "" {
+		return taxCodeItem[0].Code
+	}
+	if splitArr := strings.SplitN(name, "-", 2); len(splitArr) == 2 {
+		for _, item := range taxCodeItem {
+			if item.Name == splitArr[1] {
+				return item.Code
+			}
+		}
+	}
+	return taxCodeItem[0].Code
+}

+ 65 - 35
internal/service/invoiceCallback.go

@@ -5,6 +5,7 @@ import (
 	"ElectronicInvoice/util"
 	"context"
 	"fmt"
+	"github.com/gogf/gf/v2/database/gdb"
 	"github.com/gogf/gf/v2/errors/gerror"
 	"github.com/gogf/gf/v2/frame/g"
 	"github.com/gogf/gf/v2/net/ghttp"
@@ -77,72 +78,101 @@ func updateOrderInvoiceStatus(ctx context.Context, callBackId, invoiceNum string
 	if err != nil {
 		return err
 	}
+	err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
+		record, sqlErr := tx.GetOne(fmt.Sprintf("SELECT only_Identifying,invoice_changed FROM invoice WHERE %s =? ORDER BY id desc", queryItem), queryValue)
+		if err != nil {
+			return gerror.Wrap(sqlErr, "查询订单异常")
+		}
+		if len(record) == 0 {
+			return gerror.Newf("未查询到订单%s", callBackId)
+		}
 
-	_, err = g.DB().Update(ctx, "invoice", g.Map{
-		"invoice_number": invoiceNum,
-		"url":            pdfPath,
-		"billing_time":   invoiceTime.Unix(),
-		"invoice_status": 1,
-	}, fmt.Sprintf(" %s = ? ", queryItem), queryValue)
-	if err != nil {
-		return gerror.Wrap(err, "更新发票状态异常")
-	}
+		var (
+			invoiceChanged = gconv.Int(record["only_Identifying"]) == 1                        //换票
+			isBackInvoice  = strings.HasPrefix(gconv.String(record["only_Identifying"]), "xx") //是否是管理后台的开票
+		)
+
+		//更新发票内容
+		_, err = tx.Update("invoice", g.Map{
+			"invoice_number": invoiceNum,
+			"url":            pdfPath,
+			"billing_time":   invoiceTime.Unix(),
+			"invoice_status": 1,
+		}, fmt.Sprintf(" %s = ? ", queryItem), queryValue)
+		if err != nil {
+			return gerror.Wrap(err, "更新发票状态异常")
+		}
+
+		// 管理后台非换票的开票,需要更新订单是否全部开票完成
+		if !invoiceChanged && isBackInvoice {
+			if sqlErr = selfInvoicing(tx, queryValue); err != nil {
+				return gerror.Wrap(sqlErr, "更新订单是否全部开票完成异常")
+			}
+		}
+		return nil
+	})
 
-	// 王浩说开票成功 订单状态不用更新;以下代码来自王浩
-	if queryItem == "only_Identifying" {
-		selfInvoicing(ctx, queryValue)
+	if err != nil {
+		return gerror.Wrap(err, "订单回调更新异常")
 	}
 
-	if err := SendInvoiceSuccessMail(ctx, callBackId); err != nil {
+	if err = SendInvoiceSuccessMail(ctx, callBackId); err != nil {
 		g.Log().Errorf(ctx, "%s 发送邮件失败 err: %v ", callBackId, err)
 	}
 	return nil
 }
 
 // selfInvoicing 自助开票
-func selfInvoicing(ctx context.Context, identifyingValue string) {
+func selfInvoicing(tx gdb.TX, identifyingValue string) error {
 	//自助开票
-	res, err := g.DB().GetOne(ctx, "SELECT GROUP_CONCAT(order_code) as  order_code  from invoice where only_Identifying=?", identifyingValue)
+	res, err := tx.GetOne("SELECT GROUP_CONCAT(order_code) as  order_code  from invoice where only_Identifying=?", identifyingValue)
 	if err != nil {
-		g.Log().Errorf(ctx, "自助开票异常")
+		return gerror.New("自助开票异常")
 	}
 	orderArr := strings.Split(gconv.String(res["order_code"]), ",")
 	for _, v := range orderArr {
 		if v == "" {
 			continue
 		}
+		ok, err := invoiceStatusHandle(tx, v)
+		if err != nil {
+			return gerror.Wrap(err, "回款计算异常")
+		}
 		updateData := map[string]interface{}{}
-		if invoiceStatusHandle(ctx, v) {
+		if ok {
 			updateData["applybill_status"] = 2
 		} else {
 			updateData["applybill_status"] = 3
 		}
-		_, err := g.DB().Update(ctx, "dataexport_order", updateData, " order_code=? ", v)
+		_, err = tx.Update("dataexport_order", updateData, " order_code=? ", v)
 		if err != nil {
-			g.Log().Errorf(ctx, "自助开票更新订单异常 orderCode:%v %v", v, err)
-		}
-		if err != nil {
-			g.Log().Errorf(ctx, "自助开票更新订单异常 orderCode:%v %v", v, err)
+			return gerror.Wrapf(err, "自助开票更新订单异常 orderCode:%v %v", v, err)
 		}
 	}
+	return nil
 }
 
 // InvoiceStatusHandle 判断是全额还是部分回款
-// auth :王浩
-func invoiceStatusHandle(ctx context.Context, orderCode string) bool {
-	orderData, err := g.DB().GetOne(ctx, "SELECT pay_money FROM dataexport_order WHERE order_code=?", orderCode)
-	if err != nil || orderData.IsEmpty() {
-		return false
+// copy from auth :王浩
+func invoiceStatusHandle(tx gdb.TX, orderCode string) (bool, error) {
+	orderData, err := tx.GetOne("SELECT pay_money FROM dataexport_order WHERE order_code=?", orderCode)
+	if err != nil {
+		return false, gerror.Wrap(err, "查询订单价格异常")
+	}
+	if orderData.IsEmpty() {
+		return false, gerror.Wrap(err, "未查询到订单数据")
 	}
 
-	invoiceData, err := g.DB().GetOne(ctx, "select sum(invoice_order_money) as  money  from  invoice where  order_code=?  and  invoice_status>=0  ", orderCode)
-	if err != nil || invoiceData.IsEmpty() {
-		return false
+	invoiceData, err := tx.GetOne("select sum(invoice_order_money) as  money  from  invoice where  order_code=?  and  invoice_status>=0  ", orderCode)
+	if err != nil {
+		return false, gerror.Wrap(err, "价格计算异常")
 	}
-	allMoney := gconv.Int64(invoiceData["money"])
-	payMoney := gconv.Int64(orderData["pay_money"])
-	if payMoney == allMoney {
-		return true
+	if invoiceData.IsEmpty() {
+		return false, gerror.Wrap(err, "未查询到发票数据")
+	}
+
+	if gconv.Int64(invoiceData["money"]) == gconv.Int64(orderData["pay_money"]) {
+		return true, nil
 	}
-	return false
+	return false, nil
 }

+ 38 - 47
internal/service/invoiceCallback_red.go

@@ -28,66 +28,57 @@ func InvoicingMakeRedCallBackLogic(r *ghttp.Request) error {
 	tType := r.Get("type").Int()
 	switch tType {
 	case 0: //红冲成功
-		var (
-			ctx = r.Context()
-			err error
-			res gdb.Record
+		err := g.DB().Transaction(r.Context(), func(ctx context.Context, tx gdb.TX) error {
+			var (
+				pdfBase64 = r.Get("pdf").String()
+				num       = r.Get("num").String()       //蓝票号
+				offsetNum = r.Get("offsetNum").String() //红票号
+				kptime    = r.Get("kptime").String()
 
-			pdfBase64 = r.Get("pdf").String()
-			num       = r.Get("num").String()       //蓝票号
-			offsetNum = r.Get("offsetNum").String() //红票号
-			kptime    = r.Get("kptime").String()
-		)
+				invoiceTime time.Time
+				path        string
+				redByte     []byte
 
-		if len(res) == 0 {
-			g.Log().Errorf(ctx, "InvoicingMakeRedCallBackLogic 未查询到蓝票订单,蓝票号 %d", num)
-			return nil
-		}
-
-		var (
-			invoiceTime time.Time
-			path        string
-			redByte     []byte
-		)
+				err error
+			)
+			invoiceTime, err = time.ParseInLocation(consts.DateFormat_Full, kptime, time.Local)
+			if err != nil {
+				return gerror.Wrap(err, "时间格式化异常")
+			}
 
-		invoiceTime, err = time.ParseInLocation(consts.DateFormat_Full, kptime, time.Local)
-		if err != nil {
-			return gerror.Wrap(err, "时间格式化异常")
-		}
+			path, err = util.SavePdfFile(r.Context(), fmt.Sprintf("RED_%s", num), pdfBase64)
+			if err != nil {
+				return gerror.Wrap(err, "InvoicingMakeRedCallBackLogic 保存红冲pdf文件失败")
+			}
+			//保存红票信息
+			redByte, _ = gjson.Marshal(RedMsg{
+				InvoiceNumber:    offsetNum,
+				Url:              path,
+				InvoiceSerialnum: fmt.Sprintf("RED_%s", num),
+				InvoiceStatus:    "1",
+				BillingTime:      invoiceTime.Unix(),
+			})
 
-		path, err = util.SavePdfFile(r.Context(), fmt.Sprintf("RED_%s", num), pdfBase64)
-		if err != nil {
-			return gerror.Wrap(err, "InvoicingMakeRedCallBackLogic 保存红冲pdf文件失败")
-		}
-		//保存红票信息
-		redByte, _ = gjson.Marshal(RedMsg{
-			InvoiceNumber:    offsetNum,
-			Url:              path,
-			InvoiceSerialnum: fmt.Sprintf("RED_%s", num),
-			InvoiceStatus:    "1",
-			BillingTime:      invoiceTime.Unix(),
-		})
-		err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
 			//旧蓝票状态修改已红冲
-			affect, t_err := g.DB().Update(ctx, "invoice", g.Map{
+			res1, sqlErr1 := tx.Update("invoice", g.Map{
 				"invoice_status": -2,
 				"red":            string(redByte),
 			}, "invoice_changed = 0 AND invoice_number= ? ", num)
-			if t_err != nil {
-				return t_err
-			}
-			if row, _ := affect.RowsAffected(); row != 1 {
-				return gerror.Newf("InvoicingMakeRedCallBackLogic 旧蓝票状态修改已红冲异常 sql(invoice_changed = 0 AND invoice_number= %s)", num)
+			if sqlErr1 != nil {
+				return gerror.Wrapf(sqlErr1, "InvoicingMakeRedCallBackLogic 旧蓝票状态修改已红冲异常 sql(invoice_changed = 0 AND invoice_number= %s)", num)
 			}
 			//新蓝票状态改为可以开票
-			affect, t_err = g.DB().Update(ctx, "invoice", g.Map{
+			res2, sqlErr2 := tx.Update("invoice", g.Map{
 				"invoice_status": 2,
 			}, "invoice_changed = 1 AND invoice_number= ? ", num)
-			if t_err != nil {
-				return t_err
+			if sqlErr2 != nil {
+				return gerror.Wrapf(sqlErr2, "InvoicingMakeRedCallBackLogic 新蓝票状态改为可以开票异常 sql(invoice_changed = 1 AND invoice_number= %s)", num)
 			}
-			if row, _ := affect.RowsAffected(); row != 1 {
-				return gerror.Newf("InvoicingMakeRedCallBackLogic 新蓝票状态改为可以开票异常 sql(invoice_changed = 0 AND invoice_number= %s)", num)
+			// 蓝票数量=红冲数量
+			num1, _ := res1.RowsAffected()
+			num2, _ := res2.RowsAffected()
+			if !(num1 == num2 && num1 > 1) {
+				return gerror.Newf("更新校验异常 蓝(旧%d) 蓝(新%d)", num1, num2)
 			}
 			return nil
 		})

+ 42 - 23
internal/service/invoiceMake.go

@@ -9,16 +9,19 @@ import (
 	"github.com/gogf/gf/v2/frame/g"
 	"github.com/gogf/gf/v2/util/gconv"
 	"strconv"
+	"strings"
 	"time"
 )
 
-// simpleMakeInvoice 简单开票
+// simpleMakeInvoice 简单开票(包含一个订单开多张票)
 func (im *InvoiceManager) simpleMakeInvoice(ctx context.Context) (total, okNum int, end bool, err error) {
 	var (
 		res gdb.Result
 	)
-	//查询需要开票的数据(新开发票【a.invoice_status=0 AND a.invoice_changed=0】,红冲后新开【a.invoice_status=2 AND a.invoice_changed=1】)
-	res, err = g.DB().Query(ctx, "SELECT a.*,b.pay_way,b.order_money,b.pay_money FROM invoice a INNER JOIN dataexport_order b ON a.order_code=b.order_code WHERE ((a.invoice_status=0 AND a.invoice_changed=0) or (a.invoice_status=2 AND a.invoice_changed=1 )) AND  a.invoice_variety='普通发票(电子发票)' AND a.invoice_order_code is NULL AND a.create_time > ? ", consts.InvoiceStartTime.Unix())
+	//查询需要开票的数据
+	//(新开发票【a.invoice_status=0 AND a.invoice_changed=0】,红冲后新开【a.invoice_status=2 AND a.invoice_changed=1】)
+	//线上申请发票【invoice_order_code is null 】, 管理后台一个订单拆分多个发票【invoice_order_code not like '%,%'】
+	res, err = g.DB().Query(ctx, "SELECT a.invoice_type,a.remark,a.invoice_variety,a.taxpayer_identnum,a.company_name,a.invoice_content,b.pay_way,b.order_money,b.pay_money FROM invoice a INNER JOIN dataexport_order b ON a.order_code=b.order_code WHERE a.invoice_variety like '%电子%' AND ((a.invoice_status=0 AND a.invoice_changed=0) or (a.invoice_status=2 AND a.invoice_changed=1 )) AND  (a.invoice_order_code is NULL OR a.invoice_code not like '%,%') AND a.create_time > ? ", consts.InvoiceStartTime.Unix())
 	if err != nil {
 		err = gerror.Wrap(err, "simpleMakeInvoice-查询待开票异常")
 		return
@@ -32,9 +35,11 @@ func (im *InvoiceManager) simpleMakeInvoice(ctx context.Context) (total, okNum i
 			return
 		}
 		var (
-			iType  = gconv.String(m["invoice_type"])
-			remark = gconv.String(m["remark"])
-			prices float64
+			iType          = gconv.String(m["invoice_type"])
+			remark         = gconv.String(m["remark"])
+			invoiceVariety = gconv.String(m["invoice_variety"])
+			invoiceContent = gconv.String(m["invoice_content"])
+			prices         float64
 		)
 
 		//公对公转账 账单金额可以修改 开发票应取实付金额 pay_money
@@ -47,16 +52,22 @@ func (im *InvoiceManager) simpleMakeInvoice(ctx context.Context) (total, okNum i
 
 		c := MakeInvoiceData{
 			Type:  "2",
-			Id:    fmt.Sprintf("id:%d", gconv.Int64(m["id"])), //因为orderCode不唯一,此处用订单发票数据库id
+			Id:    fmt.Sprintf("id:%d", gconv.Int64(m["id"])), //因为orderCode不唯一,此处禁止使用orderCode
 			Notes: remark,
 			Fhr:   g.Cfg().MustGet(ctx, "company.hfr", "贺鹏飞").String(),
 			InvoiceArr: []MakeInvoiceItems{{
-				Xmmc:     g.Cfg().MustGet(ctx, "company.taxCode").String(), //开票项
-				WhStatus: 1,                                                //开票项是否维护
-				Je:       strconv.FormatFloat(prices, 'f', -1, 64),         //金额
-				Sl:       "1",                                              //数量
+				Xmmc:     consts.GetTaxCodeByName(invoiceContent),  //开票项
+				WhStatus: 1,                                        //开票项是否维护
+				Je:       strconv.FormatFloat(prices, 'f', -1, 64), //金额
+				Sl:       "1",                                      //数量
 			}},
 		}
+
+		//	1 增值税专用发票;2 普通发票
+		if strings.Contains(invoiceVariety, "专用") {
+			c.Type = "1"
+		}
+
 		if iType == "单位" {
 			c.Gmfmc = gconv.String(m["company_name"])
 			c.Gmfnsrsbh = gconv.String(m["taxpayer_identnum"])
@@ -80,12 +91,13 @@ func (im *InvoiceManager) simpleMakeInvoice(ctx context.Context) (total, okNum i
 	return
 }
 
-// selfMakeInvoice 自助开票
+// selfMakeInvoice 联合开票(多个订单开一张发票)
 func (im *InvoiceManager) selfMakeInvoice(ctx context.Context) (total, okNum int, end bool, err error) {
 	var (
 		res gdb.Result
 	)
-	res, err = g.DB().Query(ctx, "SELECT a.invoice_money,a.only_Identifying,a.invoice_type,a.company_name,a.taxpayer_identnum,a.remark FROM invoice a WHERE a.invoice_status=0 AND a.invoice_changed=0 AND  a.invoice_variety='电子普通发票' AND a.invoice_order_code is not NULL AND a.create_time > ? GROUP BY invoice_order_code", consts.InvoiceStartTime.Unix())
+	//(新开发票【a.invoice_status=0 AND a.invoice_changed=0】,红冲后新开【a.invoice_status=2 AND a.invoice_changed=1】)
+	res, err = g.DB().Query(ctx, "SELECT a.invoice_type,a.remark,a.invoice_variety,a.taxpayer_identnum,a.company_name,a.invoice_content,a.invoice_money FROM invoice a WHERE a.invoice_variety like '%电子%' AND ((a.invoice_status=0 AND a.invoice_changed=0) or (a.invoice_status=2 AND a.invoice_changed=1)) AND a.invoice_code like '%,%' AND a.create_time > ? GROUP BY invoice_order_code", consts.InvoiceStartTime.Unix())
 	if err != nil {
 		err = gerror.Wrap(err, "selfMakeInvoice-查询待开票异常")
 		return
@@ -99,23 +111,30 @@ func (im *InvoiceManager) selfMakeInvoice(ctx context.Context) (total, okNum int
 			return
 		}
 		var (
-			orderCode = gconv.String(m["only_Identifying"])
-			iType     = gconv.String(m["invoice_type"])
-			prices    = gconv.Float64(m["invoice_money"]) / float64(100)
-			remark    = gconv.String(m["remark"])
+			onlyIdentifying = gconv.String(m["only_Identifying"])
+			iType           = gconv.String(m["invoice_type"])
+			prices          = gconv.Float64(m["invoice_money"]) / float64(100)
+			remark          = gconv.String(m["remark"])
+			invoiceVariety  = gconv.String(m["invoice_variety"])
+			invoiceContent  = gconv.String(m["invoice_content"])
 		)
 		c := MakeInvoiceData{
 			Type:  "2",
-			Id:    fmt.Sprintf("only_Identifying:%s", orderCode),
+			Id:    fmt.Sprintf("only_Identifying:%s", onlyIdentifying),
 			Notes: remark,
 			Fhr:   g.Cfg().MustGet(ctx, "company.hfr", "贺鹏飞").String(),
 			InvoiceArr: []MakeInvoiceItems{{
-				Xmmc:     g.Cfg().MustGet(ctx, "company.taxCode").String(), //开票项
-				WhStatus: 1,                                                //开票项是否维护
-				Je:       strconv.FormatFloat(prices, 'f', -1, 64),         //金额
-				Sl:       "1",                                              //数量
+				Xmmc:     consts.GetTaxCodeByName(invoiceContent),  //开票项
+				WhStatus: 1,                                        //开票项是否维护
+				Je:       strconv.FormatFloat(prices, 'f', -1, 64), //金额
+				Sl:       "1",                                      //数量
 			}},
 		}
+		//	1 增值税专用发票;2 普通发票
+		if strings.Contains(invoiceVariety, "专用") {
+			c.Type = "1"
+		}
+
 		if iType == "单位" {
 			c.Gmfmc = gconv.String(m["company_name"])
 			c.Gmfnsrsbh = gconv.String(m["taxpayer_identnum"])
@@ -145,7 +164,7 @@ func (im *InvoiceManager) makeRedInvoice(ctx context.Context) (total, okNum int,
 		res gdb.Result
 	)
 	//冲红任务
-	res, err = g.DB().Query(ctx, "SELECT invoice_number,billing_time FROM invoice a  WHERE a.invoice_status=0 AND a.invoice_changed=1 AND  a.invoice_variety='普通发票(电子发票)' AND a.invoice_order_code is NULL AND a.create_time > ? ", consts.InvoiceStartTime.Unix())
+	res, err = g.DB().Query(ctx, "SELECT invoice_number,billing_time FROM invoice a  WHERE a.invoice_variety like '%电子%' AND a.invoice_status=0 AND a.invoice_changed=1 AND a.invoice_order_code is NULL AND a.create_time > ? ", consts.InvoiceStartTime.Unix())
 	if err != nil {
 		err = gerror.Wrap(err, "selfMakeChangeInvoice-查询待冲红订单异常")
 		return

+ 1 - 0
internal/service/tripartiteCommon.go

@@ -21,6 +21,7 @@ type (
 
 func createTripartite() *TripartiteAuth {
 	t := &TripartiteAuth{}
+	return t
 	_, err := t.GetToken(true)
 	if err != nil {
 		g.Log().Errorf(context.Background(), "刷新token异常%v", err)