Files
2026-05-03 22:40:41 +08:00

528 lines
17 KiB
Go

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
}