add:import alipay payroll
This commit is contained in:
parent
49ad1435bc
commit
54ef138d90
|
|
@ -76,6 +76,7 @@ func RegisterRouter(router *gin.Engine) {
|
||||||
authorized.GET("/stats/month/total", service.StatsMonthTotal)
|
authorized.GET("/stats/month/total", service.StatsMonthTotal)
|
||||||
authorized.GET("/transaction", service.QueryTransactions)
|
authorized.GET("/transaction", service.QueryTransactions)
|
||||||
authorized.POST("/transaction", service.AddTransactions)
|
authorized.POST("/transaction", service.AddTransactions)
|
||||||
|
authorized.POST("/transaction/batch", service.AddBatchTransactions)
|
||||||
authorized.GET("/transaction/payee", service.QueryTransactionPayees)
|
authorized.GET("/transaction/payee", service.QueryTransactionPayees)
|
||||||
authorized.GET("/transaction/template", service.QueryTransactionTemplates)
|
authorized.GET("/transaction/template", service.QueryTransactionTemplates)
|
||||||
authorized.POST("/transaction/template", service.AddTransactionTemplate)
|
authorized.POST("/transaction/template", service.AddTransactionTemplate)
|
||||||
|
|
@ -84,6 +85,7 @@ func RegisterRouter(router *gin.Engine) {
|
||||||
authorized.GET("/file/dir", service.QueryLedgerSourceFileDir)
|
authorized.GET("/file/dir", service.QueryLedgerSourceFileDir)
|
||||||
authorized.GET("/file/content", service.QueryLedgerSourceFileContent)
|
authorized.GET("/file/content", service.QueryLedgerSourceFileContent)
|
||||||
authorized.POST("/file", service.UpdateLedgerSourceFileContent)
|
authorized.POST("/file", service.UpdateLedgerSourceFileContent)
|
||||||
|
authorized.POST("/import/alipay", service.ImportAliPayCSV)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"github.com/beancount-gs/script"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ImportAliPayCSV(c *gin.Context) {
|
||||||
|
ledgerConfig := script.GetLedgerConfigFromContext(c)
|
||||||
|
|
||||||
|
file, _ := c.FormFile("file")
|
||||||
|
f, _ := file.Open()
|
||||||
|
reader := csv.NewReader(simplifiedchinese.GBK.NewDecoder().Reader(bufio.NewReader(f)))
|
||||||
|
|
||||||
|
result := make([]Transaction, 0)
|
||||||
|
|
||||||
|
currency := "CNY"
|
||||||
|
currencySymbol := script.GetCommoditySymbol(currency)
|
||||||
|
|
||||||
|
for {
|
||||||
|
lines, err := reader.Read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
script.LogError(ledgerConfig.Mail, err.Error())
|
||||||
|
}
|
||||||
|
if len(lines) > 11 {
|
||||||
|
fields := strings.Fields(lines[2])
|
||||||
|
status := strings.Trim(lines[15], " ")
|
||||||
|
account := ""
|
||||||
|
if status == "已收入" {
|
||||||
|
account = "Income:"
|
||||||
|
} else if status == "已支出" {
|
||||||
|
account = "Expenses:"
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fields) >= 2 {
|
||||||
|
result = append(result, Transaction{
|
||||||
|
Id: strings.Trim(lines[0], " "),
|
||||||
|
Date: strings.Trim(fields[0], " "),
|
||||||
|
Payee: strings.Trim(lines[7], " "),
|
||||||
|
Narration: strings.Trim(lines[8], " "),
|
||||||
|
Number: strings.Trim(lines[9], " "),
|
||||||
|
Account: account,
|
||||||
|
Currency: currency,
|
||||||
|
CurrencySymbol: currencySymbol,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OK(c, result)
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/beancount-gs/script"
|
"github.com/beancount-gs/script"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
@ -84,6 +85,25 @@ func sum(entries []AddTransactionEntryForm, openingBalances string) decimal.Deci
|
||||||
return sumVal
|
return sumVal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddBatchTransactions(c *gin.Context) {
|
||||||
|
var addTransactionForms []AddTransactionForm
|
||||||
|
if err := c.ShouldBindJSON(&addTransactionForms); err != nil {
|
||||||
|
BadRequest(c, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result := make([]string, 0)
|
||||||
|
ledgerConfig := script.GetLedgerConfigFromContext(c)
|
||||||
|
for _, form := range addTransactionForms {
|
||||||
|
err := saveTransaction(nil, form, ledgerConfig)
|
||||||
|
if err == nil {
|
||||||
|
result = append(result, form.Date+form.Payee+form.Desc)
|
||||||
|
} else {
|
||||||
|
script.LogError(ledgerConfig.Mail, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OK(c, result)
|
||||||
|
}
|
||||||
|
|
||||||
func AddTransactions(c *gin.Context) {
|
func AddTransactions(c *gin.Context) {
|
||||||
var addTransactionForm AddTransactionForm
|
var addTransactionForm AddTransactionForm
|
||||||
if err := c.ShouldBindJSON(&addTransactionForm); err != nil {
|
if err := c.ShouldBindJSON(&addTransactionForm); err != nil {
|
||||||
|
|
@ -91,12 +111,22 @@ func AddTransactions(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ledgerConfig := script.GetLedgerConfigFromContext(c)
|
ledgerConfig := script.GetLedgerConfigFromContext(c)
|
||||||
|
err := saveTransaction(c, addTransactionForm, ledgerConfig)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
OK(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveTransaction(c *gin.Context, addTransactionForm AddTransactionForm, ledgerConfig *script.Config) error {
|
||||||
// 账户是否平衡
|
// 账户是否平衡
|
||||||
sumVal := sum(addTransactionForm.Entries, ledgerConfig.OpeningBalances)
|
sumVal := sum(addTransactionForm.Entries, ledgerConfig.OpeningBalances)
|
||||||
val, _ := decimal.NewFromString("0.01")
|
val, _ := decimal.NewFromString("0.01")
|
||||||
if sumVal.Abs().GreaterThan(val) {
|
if sumVal.Abs().GreaterThan(val) {
|
||||||
TransactionNotBalance(c)
|
if c != nil {
|
||||||
return
|
TransactionNotBalance(c)
|
||||||
|
}
|
||||||
|
return errors.New("transaction not balance")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2021-09-29 * "支付宝" "黄金补仓X元" #Invest
|
// 2021-09-29 * "支付宝" "黄金补仓X元" #Invest
|
||||||
|
|
@ -129,8 +159,10 @@ func AddTransactions(c *gin.Context) {
|
||||||
priceLine := fmt.Sprintf("%s price %s %s %s", addTransactionForm.Date, account.Currency, entry.Price, ledgerConfig.OperatingCurrency)
|
priceLine := fmt.Sprintf("%s price %s %s %s", addTransactionForm.Date, account.Currency, entry.Price, ledgerConfig.OperatingCurrency)
|
||||||
err := script.AppendFileInNewLine(script.GetLedgerPriceFilePath(ledgerConfig.DataPath), priceLine)
|
err := script.AppendFileInNewLine(script.GetLedgerPriceFilePath(ledgerConfig.DataPath), priceLine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(c, err.Error())
|
if c != nil {
|
||||||
return
|
InternalError(c, err.Error())
|
||||||
|
}
|
||||||
|
return errors.New("internal error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -142,8 +174,10 @@ func AddTransactions(c *gin.Context) {
|
||||||
// 记账的日期
|
// 记账的日期
|
||||||
month, err := time.Parse("2006-01-02", addTransactionForm.Date)
|
month, err := time.Parse("2006-01-02", addTransactionForm.Date)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(c, err.Error())
|
if c != nil {
|
||||||
return
|
InternalError(c, err.Error())
|
||||||
|
}
|
||||||
|
return errors.New("internal error")
|
||||||
}
|
}
|
||||||
monthStr := month.Format("2006-01")
|
monthStr := month.Format("2006-01")
|
||||||
filePath := fmt.Sprintf("%s/month/%s.bean", ledgerConfig.DataPath, monthStr)
|
filePath := fmt.Sprintf("%s/month/%s.bean", ledgerConfig.DataPath, monthStr)
|
||||||
|
|
@ -152,23 +186,29 @@ func AddTransactions(c *gin.Context) {
|
||||||
if !script.FileIfExist(filePath) {
|
if !script.FileIfExist(filePath) {
|
||||||
err = script.CreateFile(filePath)
|
err = script.CreateFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(c, err.Error())
|
if c != nil {
|
||||||
return
|
InternalError(c, err.Error())
|
||||||
|
}
|
||||||
|
return errors.New("internal error")
|
||||||
}
|
}
|
||||||
// include ./2021-11.bean
|
// include ./2021-11.bean
|
||||||
err = script.AppendFileInNewLine(script.GetLedgerMonthsFilePath(ledgerConfig.DataPath), fmt.Sprintf("include \"./%s.bean\"", monthStr))
|
err = script.AppendFileInNewLine(script.GetLedgerMonthsFilePath(ledgerConfig.DataPath), fmt.Sprintf("include \"./%s.bean\"", monthStr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(c, err.Error())
|
if c != nil {
|
||||||
return
|
InternalError(c, err.Error())
|
||||||
|
}
|
||||||
|
return errors.New("internal error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = script.AppendFileInNewLine(filePath, line)
|
err = script.AppendFileInNewLine(filePath, line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
InternalError(c, err.Error())
|
if c != nil {
|
||||||
return
|
InternalError(c, err.Error())
|
||||||
|
}
|
||||||
|
return errors.New("internal error")
|
||||||
}
|
}
|
||||||
OK(c, nil)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type transactionPayee struct {
|
type transactionPayee struct {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue