package controller import ( "bop_tool/app/global" "bop_tool/app/model" "encoding/csv" "fmt" "io" "os" "strings" "github.com/shopspring/decimal" ) type wechatBill struct{} func NewWechatBill() *wechatBill { return &wechatBill{} } func (b *wechatBill) Begin() { data := readBillCsv("./resource/V2-20230817-1503284471.csv") // fmt.Println(data) // _ = data bills, err := buildBill(data) // fmt.Println(bills, err) if err != nil { panic(err) } transFee := int64(0) refundFee := int64(0) handFee := int64(0) // currency := "CNY" for _, bill := range bills { totalFee, err := decimal.NewFromString(bill.Fee) if err != nil { panic(err) } fee := totalFee.Mul(decimal.NewFromFloat(100)).IntPart() handFee += fee // if bill.CashFeeType != currency { // continue // } if bill.TradeState == "SUCCESS" { // fmt.Println(bill) // verifyOrder(bill) // Fee totalFee, err := decimal.NewFromString(bill.TotalFee) if err != nil { panic(err) } fee := totalFee.Mul(decimal.NewFromFloat(100)).IntPart() transFee += fee // } else if bill.TradeState == "REVOKED" { } else if bill.TradeState == "REFUND" || bill.TradeState == "REVOKED" { // PROCESSING ??? // verifyRefund(bill) totalFee, err := decimal.NewFromString(bill.RefundFee) if err != nil { panic(err) } fee := totalFee.Mul(decimal.NewFromFloat(100)).IntPart() refundFee += fee } else { panic("unknown trade state") } } fmt.Println(transFee, refundFee, transFee-refundFee, transFee-refundFee-handFee) } func verifyOrder(bill WechatBill) error { fmt.Printf("begin %+v %+v\n", bill.OutTransactionId, bill.SubMchId) order := model.BopOrder{} result := global.Gorm.Where("sn = ?", bill.OutTransactionId). Where("channel_mch_id = ?", bill.SubMchId). First(&order) if result.RowsAffected == 0 { fmt.Println("order not found", bill.OutTransactionId, bill.SubMchId) return fmt.Errorf("order not found") } // 验证金额 totalFee, err := decimal.NewFromString(bill.TotalFee) if err != nil { return err } if order.TotalFee != totalFee.Mul(decimal.NewFromFloat(100)).IntPart() { fmt.Println("order not equal", bill.OutTransactionId, bill.SubMchId) return fmt.Errorf("amount not equal") } if order.CashFeeType != bill.CashFeeType { fmt.Println("cash fee type not equal", bill.OutTransactionId, bill.SubMchId) return fmt.Errorf("cash fee type not equal") } if order.TradeState != "SUCCESS" && order.TradeState != "REFUND" { fmt.Println("trade state not equal", bill.OutTransactionId, bill.SubMchId) return fmt.Errorf("trade state not equal") } return nil } func verifyRefund(bill WechatBill) {} // type Order struct { // TransTime int64 `json:"trans_time"` // Transaction time // Appid string `json:"appid"` // Official account ID(appid) // MchId string `json:"mch_id"` // Vendor ID(mch_id) // SubMchId string `json:"sub_mch_id"` // Sub vendor ID(sub_mch_id) // DeviceInfo string `json:"device_info"` // Device ID(Device_info) // TransactionId string `json:"transaction_id"` // Wechat order number(transaction_id) // OutTransactionId string `json:"out_transaction_id"` // Vendor order number(out_transaction_id) // Openid string `json:"openid"` // User tag(openid) // TradeType string `json:"trade_type"` // Transaction type(trade_type) // TradeState string `json:"trade_state"` // Transaction status(trade_state) // BankType string `json:"bank_type"` // Payment bank(bank_type) // FeeType string `json:"fee_type"` // Currency type(fee_type) // TotalFee int64 `json:"total_fee"` // Total amount(total_fee) // CouponAmount int64 `json:"coupon_amount"` // Coupon amount // //RefundId string `json:"refund_id"` // Wechat refund number(refund_id) // //OutRefundNo string `json:"out_refund_no"` // Vendor refund number(out_refund_no) // //RefundFee string `json:"refund_fee"` // Refund amount(refund_fee) // //CouponRefundAmount string `json:"coupon_refund_amount"` // Coupon refund amount // //RefundType string `json:"refund_type"` // Refund type // //RefundStatus string `json:"refund_status"` // Refund status(refund_status) // ProductName string `json:"product_name"` // Product name // Attach string `json:"attach"` // Vendor's data package(attach) // Fee string `json:"fee"` // Fee // Rate string `json:"rate"` // Rate // CashFeeType string `json:"cash_fee_type"` // Payment Currency type(Cash_fee_type) // CashFee int64 `json:"cash_fee"` // Cash payment amount(Cash_fee) // SettlementCurrencyType string `json:"settlement_currency_type"` // Settlement currency type // SettlementCurrencyAmount int64 `json:"settlement_currency_amount"` // Settlement currency amount // ExchangeRate string `json:"exchange_rate"` // Exchange rate // //RefundExchangeRate string `json:"refund_exchange_rate"` // Refund exchange rate // //PayerRefundAmount string `json:"payer_refund_amount"` // Payer's Refund amount // //PayerRefundCurrencyType string `json:"payer_refund_currency_type"` // Payer's Refund currency type // //RefundCurrencyType string `json:"refund_currency_type"` // Refund currency type // //RefundSettlementCurrencyType string `json:"refund_settlement_currency_type"` // Refund settlement currency type // //RefundSettlementAmount string `json:"refund_settlement_amount"` // Refund settlement amount // } // func buildOrder(data []WechatBill) ([]Order, error) { // resp := []Order{} // for _,b := range data { // o := &Order{} // t,err:=time.ParseInLocation("2006-01-02 15:04:05", b.TransTime, time.Local) // if err != nil { // return nil, err // } // o.TransTime = t.Unix() // o.Appid = b.Appid // o.MchId = b.MchId // o.SubMchId = b.SubMchId // o.DeviceInfo = b.DeviceInfo // o.TransactionId = b.TransactionId // o.OutTransactionId = b.OutTransactionId // o.Openid = b.Openid // o.TradeType = b.TradeType // o.TradeState = b.TradeState // } // return resp, nil // } func readBillCsv(path string) []map[string]string { file, err := os.Open(path) if err != nil { panic(err) } defer file.Close() reader := csv.NewReader(file) header := []string{} data := []map[string]string{} for { record, err := reader.Read() if err == io.EOF { break } if err != nil { panic(err) } // fmt.Println(record) if len(header) == 0 { header = record for k, v := range header { // 去掉BOM头 v = strings.Trim(v, "\xEF\xBB\xBF") header[k] = v } continue } m := map[string]string{} for i, v := range header { m[v] = strings.Trim(record[i], "`") } data = append(data, m) } return data } // func preNUm(data byte) int { // str := fmt.Sprintf("%b", data) // var i int = 0 // for i < len(str) { // if str[i] != '1' { // break // } // i++ // } // return i // } // func isUtf8(data []byte) bool { // for i := 0; i < len(data); { // if data[i]&0x80 == 0x00 { // // 0XXX_XXXX // i++ // continue // } else if num := preNUm(data[i]); num > 2 { // // 110X_XXXX 10XX_XXXX // // 1110_XXXX 10XX_XXXX 10XX_XXXX // // 1111_0XXX 10XX_XXXX 10XX_XXXX 10XX_XXXX // // 1111_10XX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX // // 1111_110X 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX // // preNUm() 返回首个字节的8个bits中首个0bit前面1bit的个数,该数量也是该字符所使用的字节数 // i++ // for j := 0; j < num-1; j++ { // //判断后面的 num - 1 个字节是不是都是10开头 // if data[i]&0xc0 != 0x80 { // return false // } // i++ // } // } else { // //其他情况说明不是utf-8 // return false // } // } // return true // } // 订单 type WechatBill struct { TransTime string `json:"trans_time"` // Transaction time Appid string `json:"appid"` // Official account ID(appid) MchId string `json:"mch_id"` // Vendor ID(mch_id) SubMchId string `json:"sub_mch_id"` // Sub vendor ID(sub_mch_id) DeviceInfo string `json:"device_info"` // Device ID(Device_info) TransactionId string `json:"transaction_id"` // Wechat order number(transaction_id) OutTransactionId string `json:"out_transaction_id"` // Vendor order number(out_transaction_id) Openid string `json:"openid"` // User tag(openid) TradeType string `json:"trade_type"` // Transaction type(trade_type) TradeState string `json:"trade_state"` // Transaction status(trade_state) BankType string `json:"bank_type"` // Payment bank(bank_type) FeeType string `json:"fee_type"` // Currency type(fee_type) TotalFee string `json:"total_fee"` // Total amount(total_fee) CouponAmount string `json:"coupon_amount"` // Coupon amount RefundId string `json:"refund_id"` // Wechat refund number(refund_id) OutRefundNo string `json:"out_refund_no"` // Vendor refund number(out_refund_no) RefundFee string `json:"refund_fee"` // Refund amount(refund_fee) CouponRefundAmount string `json:"coupon_refund_amount"` // Coupon refund amount RefundType string `json:"refund_type"` // Refund type RefundStatus string `json:"refund_status"` // Refund status(refund_status) ProductName string `json:"product_name"` // Product name Attach string `json:"attach"` // Vendor's data package(attach) Fee string `json:"fee"` // Fee Rate string `json:"rate"` // Rate CashFeeType string `json:"cash_fee_type"` // Payment Currency type(Cash_fee_type) CashFee string `json:"cash_fee"` // Cash payment amount(Cash_fee) SettlementCurrencyType string `json:"settlement_currency_type"` // Settlement currency type SettlementCurrencyAmount string `json:"settlement_currency_amount"` // Settlement currency amount ExchangeRate string `json:"exchange_rate"` // Exchange rate RefundExchangeRate string `json:"refund_exchange_rate"` // Refund exchange rate PayerRefundAmount string `json:"payer_refund_amount"` // Payer's Refund amount PayerRefundCurrencyType string `json:"payer_refund_currency_type"` // Payer's Refund currency type RefundCurrencyType string `json:"refund_currency_type"` // Refund currency type RefundSettlementCurrencyType string `json:"refund_settlement_currency_type"` // Refund settlement currency type RefundSettlementAmount string `json:"refund_settlement_amount"` // Refund settlement amount } func buildBill(data []map[string]string) ([]WechatBill, error) { resps := []WechatBill{} for _, val := range data { val := val r := WechatBill{} s, ok := val["Transaction time"] if !ok { return nil, fmt.Errorf("Transaction time not found") } r.TransTime = s s, ok = val["Official account ID(appid)"] if !ok { return nil, fmt.Errorf("Official account ID(appid) not found") } r.Appid = s s, ok = val["Vendor ID(mch_id)"] if !ok { return nil, fmt.Errorf("Vendor ID(mch_id) not found") } r.MchId = s s, ok = val["Sub vendor ID(sub_mch_id)"] if !ok { return nil, fmt.Errorf("Sub vendor ID(sub_mch_id) not found") } r.SubMchId = s s, ok = val["Device ID(Device_info)"] if !ok { return nil, fmt.Errorf("Device ID(Device_info) not found") } r.DeviceInfo = s s, ok = val["Wechat order number(transaction_id)"] if !ok { return nil, fmt.Errorf("Wechat order number(transaction_id) not found") } r.TransactionId = s s, ok = val["Vendor order number(out_transaction_id)"] if !ok { return nil, fmt.Errorf("Vendor order number(out_transaction_id) not found") } r.OutTransactionId = s s, ok = val["User tag(openid)"] if !ok { return nil, fmt.Errorf("User tag(openid) not found") } r.Openid = s s, ok = val["Transaction type(trade_type)"] if !ok { return nil, fmt.Errorf("Transaction type(trade_type) not found") } r.TradeType = s s, ok = val["Transaction status(trade_state)"] if !ok { return nil, fmt.Errorf("Transaction status(trade_state) not found") } r.TradeState = s s, ok = val["Payment bank(bank_type)"] if !ok { return nil, fmt.Errorf("Payment bank(bank_type) not found") } r.BankType = s s, ok = val["Currency type(fee_type)"] if !ok { return nil, fmt.Errorf("Currency type(fee_type) not found") } r.FeeType = s s, ok = val["Total amount(total_fee)"] if !ok { return nil, fmt.Errorf("Total amount(total_fee) not found") } r.TotalFee = s s, ok = val["Coupon amount"] if !ok { return nil, fmt.Errorf("Coupon amount not found") } r.CouponAmount = s s, ok = val["Wechat refund number(refund_id)"] if !ok { return nil, fmt.Errorf("Wechat refund number(refund_id) not found") } r.RefundId = s s, ok = val["Vendor refund number(out_refund_no)"] if !ok { return nil, fmt.Errorf("Vendor refund number(out_refund_no) not found") } r.OutRefundNo = s s, ok = val["Refund amount(refund_fee)"] if !ok { return nil, fmt.Errorf("Refund amount(refund_fee) not found") } r.RefundFee = s s, ok = val["Coupon refund amount"] if !ok { return nil, fmt.Errorf("Coupon refund amount not found") } r.CouponRefundAmount = s s, ok = val["Refund type"] if !ok { return nil, fmt.Errorf("Refund type not found") } r.RefundType = s s, ok = val["Refund status(refund_status)"] if !ok { return nil, fmt.Errorf("Refund status(refund_status) not found") } r.RefundStatus = s s, ok = val["Product name"] if !ok { return nil, fmt.Errorf("Product name not found") } r.ProductName = s s, ok = val["Vendor's data package(attach)"] if !ok { return nil, fmt.Errorf("Vendor's data package(attach) not found") } r.Attach = s s, ok = val["Fee"] if !ok { return nil, fmt.Errorf("Fee not found") } r.Fee = s s, ok = val["Rate"] if !ok { return nil, fmt.Errorf("Rate not found") } r.Rate = s s, ok = val["Payment Currency type(Cash_fee_type)"] if !ok { return nil, fmt.Errorf("Payment Currency type(Cash_fee_type) not found") } r.CashFeeType = s s, ok = val["Cash payment amount(Cash_fee)"] if !ok { return nil, fmt.Errorf("Cash payment amount(Cash_fee) not found") } r.CashFee = s s, ok = val["Settlement currency type"] if !ok { return nil, fmt.Errorf("Settlement currency type not found") } r.SettlementCurrencyType = s s, ok = val["Settlement currency amount"] if !ok { return nil, fmt.Errorf("Settlement currency amount not found") } r.SettlementCurrencyAmount = s s, ok = val["Exchange rate"] if !ok { return nil, fmt.Errorf("Exchange rate not found") } r.ExchangeRate = s s, ok = val["Refund exchange rate"] if !ok { return nil, fmt.Errorf("Refund exchange rate not found") } r.RefundExchangeRate = s s, ok = val["Payer's Refund amount"] if !ok { return nil, fmt.Errorf("Payer's Refund amount not found") } r.PayerRefundAmount = s s, ok = val["Payer's Refund currency type"] if !ok { return nil, fmt.Errorf("Payer's Refund currency type not found") } r.PayerRefundCurrencyType = s s, ok = val["Refund currency type"] if !ok { return nil, fmt.Errorf("Refund currency type not found") } r.RefundCurrencyType = s s, ok = val["Refund settlement currency type"] if !ok { return nil, fmt.Errorf("Refund settlement currency type not found") } r.RefundSettlementCurrencyType = s s, ok = val["Refund settlement amount"] if !ok { return nil, fmt.Errorf("Refund settlement amount not found") } r.RefundSettlementAmount = s resps = append(resps, r) } return resps, nil }