package service import ( "bytes" "encoding/csv" "fmt" "strconv" "strings" "time" "hammond/db" ) func DrivvoParseExpenses(content []byte, user *db.User, vehicle *db.Vehicle) ([]db.Expense, []string) { expenseReader := csv.NewReader(bytes.NewReader(content)) expenseReader.Comment = '#' // Read headers (there is a trailing comma at the end, that's why we have to read the first line) expenseReader.Read() expenseReader.FieldsPerRecord = 6 expenseRecords, err := expenseReader.ReadAll() var errors []string if err != nil { errors = append(errors, err.Error()) println(err.Error()) return nil, errors } var expenses []db.Expense for index, record := range expenseRecords { date, err := time.Parse("2006-01-02 15:04:05", record[1]) if err != nil { errors = append(errors, "Found an invalid date/time at service/expense row "+strconv.Itoa(index+1)) } totalCost, err := strconv.ParseFloat(record[2], 32) if err != nil { errors = append(errors, "Found and invalid total cost at service/expense row "+strconv.Itoa(index+1)) } odometer, err := strconv.Atoi(record[0]) if err != nil { errors = append(errors, "Found an invalid odometer reading at service/expense row "+strconv.Itoa(index+1)) } notes := fmt.Sprintf("Location: %s\nNotes: %s\n", record[4], record[5]) expenses = append(expenses, db.Expense{ UserID: user.ID, VehicleID: vehicle.ID, Date: date, OdoReading: odometer, Amount: float32(totalCost), ExpenseType: record[3], Currency: user.Currency, DistanceUnit: user.DistanceUnit, Comments: notes, Source: "Drivvo", }) } return expenses, errors } func DrivvoParseRefuelings(content []byte, user *db.User, vehicle *db.Vehicle, importLocation bool) ([]db.Fillup, []string) { refuelingReader := csv.NewReader(bytes.NewReader(content)) refuelingReader.Comment = '#' refuelingRecords, err := refuelingReader.ReadAll() var errors []string if err != nil { errors = append(errors, err.Error()) println(err.Error()) return nil, errors } var fillups []db.Fillup for index, record := range refuelingRecords { // Skip column titles if index == 0 { continue } date, err := time.Parse("2006-01-02 15:04:05", record[1]) if err != nil { errors = append(errors, "Found an invalid date/time at refuel row "+strconv.Itoa(index+1)) } totalCost, err := strconv.ParseFloat(record[4], 32) if err != nil { errors = append(errors, "Found and invalid total cost at refuel row "+strconv.Itoa(index+1)) } odometer, err := strconv.Atoi(record[0]) if err != nil { errors = append(errors, "Found an invalid odometer reading at refuel row "+strconv.Itoa(index+1)) } location := "" if importLocation { location = record[17] } pricePerUnit, err := strconv.ParseFloat(record[3], 32) if err != nil { unit := strings.ToLower(db.FuelUnitDetails[vehicle.FuelUnit].Key) errors = append(errors, fmt.Sprintf("Found an invalid cost per %s at refuel row %d", unit, index+1)) } quantity, err := strconv.ParseFloat(record[5], 32) if err != nil { errors = append(errors, "Found an invalid quantity at refuel row "+strconv.Itoa(index+1)) } isTankFull := record[6] == "Yes" // Unfortunatly, drivvo doesn't expose this info in their export fal := false notes := fmt.Sprintf("Reason: %s\nNotes: %s\nFuel: %s\n", record[18], record[19], record[2]) fillups = append(fillups, db.Fillup{ VehicleID: vehicle.ID, UserID: user.ID, Date: date, HasMissedFillup: &fal, IsTankFull: &isTankFull, FuelQuantity: float32(quantity), PerUnitPrice: float32(pricePerUnit), FillingStation: location, OdoReading: odometer, TotalAmount: float32(totalCost), FuelUnit: vehicle.FuelUnit, Currency: user.Currency, DistanceUnit: user.DistanceUnit, Comments: notes, Source: "Drivvo", }) } return fillups, errors }