diff --git a/server/controllers/import.go b/server/controllers/import.go index 3ea9a9d..5d36d53 100644 --- a/server/controllers/import.go +++ b/server/controllers/import.go @@ -32,7 +32,12 @@ func drivvoImport(c *gin.Context) { c.JSON(http.StatusUnprocessableEntity, err) return } - errors := service.DrivvoImport(bytes, c.MustGet("userId").(string)) + vehicleId := c.PostForm("vehicleID") + if vehicleId == "" { + c.JSON(http.StatusUnprocessableEntity, "Missing Vehicle ID") + return + } + errors := service.DrivvoImport(bytes, c.MustGet("userId").(string), vehicleId) if len(errors) > 0 { c.JSON(http.StatusUnprocessableEntity, gin.H{"errors": errors}) return diff --git a/server/service/importService.go b/server/service/importService.go index 2c97d09..68619ea 100644 --- a/server/service/importService.go +++ b/server/service/importService.go @@ -13,7 +13,7 @@ import ( // TODO: Move drivvo stuff to separate file -func DrivvoParseExpenses(content []byte, user *db.User) ([]db.Expense, []string) { +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) @@ -53,6 +53,7 @@ func DrivvoParseExpenses(content []byte, user *db.User) ([]db.Expense, []string) notes := fmt.Sprintf("Location: %s\nNotes: %s\n", record[4], record[5]) expense.Comments = notes + expense.VehicleID = vehicle.ID expense.ExpenseType = record[3] expense.UserID = user.ID expense.Currency = user.Currency @@ -65,7 +66,7 @@ func DrivvoParseExpenses(content []byte, user *db.User) ([]db.Expense, []string) return expenses, errors } -func DrivvoParseRefuelings(content []byte, user *db.User) ([]db.Fillup, []string) { +func DrivvoParseRefuelings(content []byte, user *db.User, vehicle *db.Vehicle) ([]db.Fillup, []string) { refuelingReader := csv.NewReader(bytes.NewReader(content)) refuelingReader.Comment = '#' refuelingRecords, err := refuelingReader.ReadAll() @@ -131,6 +132,8 @@ func DrivvoParseRefuelings(content []byte, user *db.User) ([]db.Fillup, []string notes := fmt.Sprintf("Reason: %s\nNotes: %s\nFuel: %s\n", record[18], record[19], record[2]) fillup.Comments = notes + fillup.VehicleID = vehicle.ID + fillup.FuelUnit = vehicle.FuelUnit fillup.UserID = user.ID fillup.Currency = user.Currency fillup.DistanceUnit = user.DistanceUnit @@ -141,7 +144,7 @@ func DrivvoParseRefuelings(content []byte, user *db.User) ([]db.Fillup, []string return fillups, errors } -func DrivvoImport(content []byte, userId string) []string { +func DrivvoImport(content []byte, userId string, vehicleId string) []string { var errors []string user, err := GetUserById(userId) if err != nil { @@ -149,6 +152,12 @@ func DrivvoImport(content []byte, userId string) []string { return errors } + vehicle, err := GetVehicleById(vehicleId) + if err != nil { + errors = append(errors, err.Error()) + return errors + } + serviceSectionIndex := bytes.Index(content, []byte("#Service")) endParseIndex := bytes.Index(content, []byte("#Income")) @@ -165,12 +174,12 @@ func DrivvoImport(content []byte, userId string) []string { expenseSectionIndex = endParseIndex } - fillups, errors := DrivvoParseRefuelings(content[:serviceSectionIndex], user) + fillups, errors := DrivvoParseRefuelings(content[:serviceSectionIndex], user, vehicle) _ = fillups var allExpenses []db.Expense if serviceSectionIndex != -1 { - services, parseErrors := DrivvoParseExpenses(content[serviceSectionIndex:expenseSectionIndex], user) + services, parseErrors := DrivvoParseExpenses(content[serviceSectionIndex:expenseSectionIndex], user, vehicle) if parseErrors != nil { errors = append(errors, parseErrors...) } @@ -178,7 +187,7 @@ func DrivvoImport(content []byte, userId string) []string { } if expenseSectionIndex != endParseIndex { - expenses, parseErrors := DrivvoParseExpenses(content[expenseSectionIndex:endParseIndex], user) + expenses, parseErrors := DrivvoParseExpenses(content[expenseSectionIndex:endParseIndex], user, vehicle) if parseErrors != nil { errors = append(errors, parseErrors...) } @@ -189,7 +198,29 @@ func DrivvoImport(content []byte, userId string) []string { return errors } - errors = append(errors, "Not implemented") + tx := db.DB.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + if err := tx.Error; err != nil { + errors = append(errors, err.Error()) + return errors + } + if err := tx.Create(&fillups).Error; err != nil { + tx.Rollback() + errors = append(errors, err.Error()) + return errors + } + if err := tx.Create(&allExpenses).Error; err != nil { + tx.Rollback() + errors = append(errors, err.Error()) + return errors + } + if err := tx.Commit().Error; err != nil { + errors = append(errors, err.Error()) + } return errors } diff --git a/ui/src/router/views/import-drivvo.vue b/ui/src/router/views/import-drivvo.vue index f30b377..b2d12e8 100644 --- a/ui/src/router/views/import-drivvo.vue +++ b/ui/src/router/views/import-drivvo.vue @@ -9,8 +9,24 @@ export default { meta: [{ name: 'description', content: 'The Import Drivvo page.' }], }, components: { Layout }, + props: { + user: { + type: Object, + required: true, + }, + }, + data: function() { + return { + myVehicles: [], + file: null, + selectedVehicle: null, + tryingToCreate: false, + errors: [], + } + }, computed: { ...mapState('utils', ['isMobile']), + ...mapState('vehicles', ['vehicles']), uploadButtonLabel() { if (this.isMobile) { if (this.file == null) { @@ -27,18 +43,8 @@ export default { } }, }, - props: { - user: { - type: Object, - required: true, - }, - }, - data: function() { - return { - file: null, - tryingToCreate: false, - errors: [], - } + mounted() { + this.myVehicles = this.vehicles }, methods: { importDrivvo() { @@ -49,6 +55,7 @@ export default { this.tryingToCreate = true this.errorMessage = '' const formData = new FormData() + formData.append('vehicleID', this.selectedVehicle) formData.append('file', this.file, this.file.name) axios .post(`/api/import/drivvo`, formData) @@ -92,31 +99,35 @@ export default {

Steps to import data from Drivvo

    +
  1. Export your data from Drivvo in the CSV format.
  2. +
  3. Select the vehicle the exported data is for. You may need to create the vehicle in Hammond first if you haven't already done so
  4. Export your data from Fuelly in the CSV format. Steps to do that can be found - here.
  5. -
  6. Make sure that you have already created the vehicles in Hammond platform.
  7. -
  8. Make sure that the Vehicle nickname in Hammond is exactly the same as the name on Fuelly CSV or the import will not work.
  9. -
  10. Make sure that the Currency and Distance Unit are set correctly in Hammond. Import will not autodetect Currency from the - CSV but use the one set for the user.
  11. Make sure that the Currency and Distance Unit are set correctly in Hammond. Drivvo does not include this information in + their export, instead Hammond will use the values set for the user.
  12. Similiarly, make sure that the Fuel Unit and Fuel Type are correctly set in the Vehicle.
  13. -
  14. Once you have checked all these points,just import the CSV below.
  15. -
  16. Make sure that you do not import the file again and that will create repeat entries.
  17. +
  18. Once you have checked all these points, select the vehicle and import the CSV below.
  19. +
  20. Make sure that you do not import the file again as that will create repeat entries.
-
-

Choose the Drivvo CSV and press the import button.

-
+
+

Choose the vehicle, then select the Drivvo CSV and press the import button.

+
-
+
+
+ + + + + +
+ +
- + {{ uploadButtonLabel }} diff --git a/ui/src/router/views/import-fuelly.vue b/ui/src/router/views/import-fuelly.vue index 5a43d5a..76d9e03 100644 --- a/ui/src/router/views/import-fuelly.vue +++ b/ui/src/router/views/import-fuelly.vue @@ -114,7 +114,7 @@ export default {
- + {{ uploadButtonLabel }}