528 lines
17 KiB
Go
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
|
|
}
|