增加发票识别差额功能
This commit is contained in:
@@ -31,8 +31,9 @@ type reimbursementItemPayload struct {
|
||||
UnitPrice float64 `json:"unit_price"`
|
||||
Description string `json:"description"`
|
||||
ReceiptFlag int8 `json:"receipt_flag"`
|
||||
ReceiptFileIDs string `json:"receipt_file_ids"`
|
||||
ReceiptURLs string `json:"receipt_urls"`
|
||||
ReceiptFileIDs string `json:"receipt_file_ids"`
|
||||
ReceiptURLs string `json:"receipt_urls"`
|
||||
ReceiptAmounts *string `json:"receipt_amounts,omitempty"`
|
||||
}
|
||||
|
||||
type reimbursementPayload struct {
|
||||
@@ -122,12 +123,77 @@ func joinReceiptFileIDs(ids []uint64) string {
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
|
||||
func parseReceiptAmounts(raw string) []string {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return []string{}
|
||||
}
|
||||
parts := strings.Split(raw, ",")
|
||||
result := make([]string, len(parts))
|
||||
for i, part := range parts {
|
||||
result[i] = strings.TrimSpace(part)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func joinReceiptAmounts(parts []string) string {
|
||||
if len(parts) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
|
||||
func normalizeReceiptAmounts(raw string, idCount int) string {
|
||||
parts := parseReceiptAmounts(raw)
|
||||
if idCount <= 0 {
|
||||
return ""
|
||||
}
|
||||
if len(parts) < idCount {
|
||||
padding := make([]string, idCount-len(parts))
|
||||
parts = append(parts, padding...)
|
||||
} else if len(parts) > idCount {
|
||||
parts = parts[:idCount]
|
||||
}
|
||||
normalized := make([]string, idCount)
|
||||
for i := 0; i < idCount; i++ {
|
||||
part := strings.TrimSpace(parts[i])
|
||||
if part == "" {
|
||||
normalized[i] = ""
|
||||
continue
|
||||
}
|
||||
value, err := strconv.ParseFloat(part, 64)
|
||||
if err != nil || value < 0 {
|
||||
normalized[i] = ""
|
||||
continue
|
||||
}
|
||||
normalized[i] = fmt.Sprintf("%.2f", value)
|
||||
}
|
||||
return joinReceiptAmounts(normalized)
|
||||
}
|
||||
|
||||
func remapReceiptAmounts(oldIDs []uint64, oldAmounts []string, newIDs []uint64) string {
|
||||
oldMap := map[uint64]string{}
|
||||
for i, id := range oldIDs {
|
||||
if i < len(oldAmounts) {
|
||||
oldMap[id] = oldAmounts[i]
|
||||
}
|
||||
}
|
||||
parts := make([]string, len(newIDs))
|
||||
for i, id := range newIDs {
|
||||
if amount, ok := oldMap[id]; ok {
|
||||
parts[i] = amount
|
||||
}
|
||||
}
|
||||
return joinReceiptAmounts(parts)
|
||||
}
|
||||
|
||||
func resolveReceiptFiles(scheme, host string, item models.BackendReimbursementItem) []map[string]interface{} {
|
||||
ids := parseReceiptFileIDs(item.ReceiptFileIDs)
|
||||
if len(ids) == 0 {
|
||||
return []map[string]interface{}{}
|
||||
}
|
||||
urlParts := strings.Split(item.ReceiptURLs, ",")
|
||||
amountParts := parseReceiptAmounts(item.ReceiptAmounts)
|
||||
files := make([]map[string]interface{}, 0, len(ids))
|
||||
for i, id := range ids {
|
||||
url := ""
|
||||
@@ -147,8 +213,14 @@ func resolveReceiptFiles(scheme, host string, item models.BackendReimbursementIt
|
||||
if name == "" && url != "" {
|
||||
name = path.Base(strings.Split(url, "?")[0])
|
||||
}
|
||||
var amount interface{}
|
||||
if i < len(amountParts) && amountParts[i] != "" {
|
||||
if value, err := strconv.ParseFloat(amountParts[i], 64); err == nil {
|
||||
amount = value
|
||||
}
|
||||
}
|
||||
files = append(files, map[string]interface{}{
|
||||
"file_id": id, "url": url, "name": name,
|
||||
"file_id": id, "url": url, "name": name, "amount": amount,
|
||||
})
|
||||
}
|
||||
return files
|
||||
@@ -159,6 +231,7 @@ func syncReceiptFields(item *models.BackendReimbursementItem, scheme, host strin
|
||||
if len(files) == 0 {
|
||||
item.ReceiptFileIDs = ""
|
||||
item.ReceiptURLs = ""
|
||||
item.ReceiptAmounts = ""
|
||||
item.ReceiptFlag = 0
|
||||
return
|
||||
}
|
||||
@@ -178,21 +251,32 @@ func syncReceiptFields(item *models.BackendReimbursementItem, scheme, host strin
|
||||
}
|
||||
|
||||
func applyReceiptToItem(item *models.BackendReimbursementItem, payload reimbursementItemPayload, scheme, host string) {
|
||||
oldIDs := parseReceiptFileIDs(item.ReceiptFileIDs)
|
||||
oldAmounts := parseReceiptAmounts(item.ReceiptAmounts)
|
||||
|
||||
if payload.ReceiptFlag == 0 && strings.TrimSpace(payload.ReceiptFileIDs) == "" {
|
||||
item.ReceiptFileIDs = ""
|
||||
item.ReceiptURLs = ""
|
||||
item.ReceiptAmounts = ""
|
||||
item.ReceiptFlag = 0
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(payload.ReceiptFileIDs) != "" {
|
||||
item.ReceiptFileIDs = strings.TrimSpace(payload.ReceiptFileIDs)
|
||||
syncReceiptFields(item, scheme, host)
|
||||
newIDs := parseReceiptFileIDs(item.ReceiptFileIDs)
|
||||
if payload.ReceiptAmounts != nil {
|
||||
item.ReceiptAmounts = normalizeReceiptAmounts(*payload.ReceiptAmounts, len(newIDs))
|
||||
} else {
|
||||
item.ReceiptAmounts = remapReceiptAmounts(oldIDs, oldAmounts, newIDs)
|
||||
}
|
||||
return
|
||||
}
|
||||
item.ReceiptFlag = payload.ReceiptFlag
|
||||
item.ReceiptURLs = strings.TrimSpace(payload.ReceiptURLs)
|
||||
if item.ReceiptURLs == "" && item.ReceiptFlag == 0 {
|
||||
item.ReceiptFileIDs = ""
|
||||
item.ReceiptAmounts = ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,13 +300,16 @@ func reimbursementItemDTO(item models.BackendReimbursementItem, scheme, host str
|
||||
"amount": item.Amount, "quantity": item.Quantity, "unit_price": item.UnitPrice,
|
||||
"description": item.Description, "receipt_flag": receiptFlag,
|
||||
"receipt_file_ids": item.ReceiptFileIDs,
|
||||
"receipt_urls": receiptURLs, "receipt_files": receiptFiles,
|
||||
"receipt_urls": receiptURLs, "receipt_amounts": item.ReceiptAmounts,
|
||||
"receipt_files": receiptFiles,
|
||||
}
|
||||
}
|
||||
|
||||
func reimbursementDTO(row models.BackendReimbursement, items []models.BackendReimbursementItem, scheme, host string) map[string]interface{} {
|
||||
_, userName := services.OperationLogUser(&row.Tid, row.UserID)
|
||||
result := map[string]interface{}{
|
||||
"id": row.ID, "tid": row.Tid, "uid": row.UID, "user_id": row.UserID,
|
||||
"user_name": userName,
|
||||
"department_id": row.DepartmentID, "total_amount": row.TotalAmount,
|
||||
"status": row.Status, "apply_date": row.ApplyDate.Format("2006-01-02"),
|
||||
"description": row.Description, "current_approver_id": row.CurrentApproverID,
|
||||
|
||||
Reference in New Issue
Block a user