diff --git a/README.md b/README.md index 9202783..6f6de5a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ -->
Current Version - 2021.07.14
+Current Version - 2021.07.23
A self-hosted vehicle expense tracking system with support for multiple users.
diff --git a/server/controllers/vehicle.go b/server/controllers/vehicle.go
index 83148b7..d914b7c 100644
--- a/server/controllers/vehicle.go
+++ b/server/controllers/vehicle.go
@@ -26,6 +26,7 @@ func RegisterVehicleController(router *gin.RouterGroup) {
router.GET("/me/stats", getMystats)
router.GET("/vehicles/:id/fillups", getFillupsByVehicleId)
+ router.GET("/vehicles/:id/fuelSubTypes", getFuelSubTypesByVehicleId)
router.POST("/vehicles/:id/fillups", createFillup)
router.GET("/vehicles/:id/fillups/:subId", getFillupById)
router.PUT("/vehicles/:id/fillups/:subId", updateFillup)
@@ -121,6 +122,22 @@ func getFillupsByVehicleId(c *gin.Context) {
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
}
}
+func getFuelSubTypesByVehicleId(c *gin.Context) {
+
+ var searchByIdQuery models.SearchByIdQuery
+
+ if err := c.ShouldBindUri(&searchByIdQuery); err == nil {
+
+ fuelSubtypes, err := service.GetDistinctFuelSubtypesForVehicle(searchByIdQuery.Id)
+ if err != nil {
+ c.JSON(http.StatusUnprocessableEntity, common.NewError("getFuelSubTypesByVehicleId", err))
+ return
+ }
+ c.JSON(http.StatusOK, fuelSubtypes)
+ } else {
+ c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err))
+ }
+}
func getExpensesByVehicleId(c *gin.Context) {
diff --git a/server/db/dbModels.go b/server/db/dbModels.go
index 2d09a08..c0ac9fe 100644
--- a/server/db/dbModels.go
+++ b/server/db/dbModels.go
@@ -119,6 +119,7 @@ type Fillup struct {
Currency string `json:"currency"`
DistanceUnit DistanceUnit `json:"distanceUnit"`
Source string `json:"source"`
+ FuelSubType string `json:"fuelSubType"`
}
func (v *Fillup) FuelUnitDetail() EnumDetail {
diff --git a/server/models/vehicle.go b/server/models/vehicle.go
index fc5d044..6e394b4 100644
--- a/server/models/vehicle.go
+++ b/server/models/vehicle.go
@@ -50,6 +50,7 @@ type CreateFillupRequest struct {
FillingStation string `form:"fillingStation" json:"fillingStation"`
UserID string `form:"userId" json:"userId" binding:"required"`
Date time.Time `form:"date" json:"date" binding:"required" time_format:"2006-01-02"`
+ FuelSubType string `form:"fuelSubType" json:"fuelSubType"`
}
type UpdateFillupRequest struct {
diff --git a/server/service/vehicleService.go b/server/service/vehicleService.go
index e8ee23a..5e853af 100644
--- a/server/service/vehicleService.go
+++ b/server/service/vehicleService.go
@@ -139,6 +139,7 @@ func CreateFillup(model models.CreateFillupRequest) (*db.Fillup, error) {
Date: model.Date,
Currency: user.Currency,
DistanceUnit: user.DistanceUnit,
+ FuelSubType: model.FuelSubType,
Source: "API",
}
@@ -196,6 +197,7 @@ func UpdateFillup(fillupId string, model models.UpdateFillupRequest) error {
Comments: model.Comments,
FillingStation: model.FillingStation,
UserID: model.UserID,
+ FuelSubType: model.FuelSubType,
Date: model.Date,
}).Error
}
@@ -235,6 +237,11 @@ func GetVehicleAttachments(vehicleId string) (*[]db.Attachment, error) {
return db.GetVehicleAttachments(vehicleId)
}
+func GetDistinctFuelSubtypesForVehicle(vehicleId string) ([]string, error) {
+ var names []string
+ tx := db.DB.Model(&db.Fillup{}).Where("vehicle_id=? and fuel_sub_type is not null", vehicleId).Distinct().Pluck("fuel_sub_type", &names)
+ return names, tx.Error
+}
func GetUserStats(userId string, model models.UserStatsQueryModel) ([]models.VehicleStatsModel, error) {
diff --git a/ui/src/main.js b/ui/src/main.js
index 191dd10..2ff0390 100644
--- a/ui/src/main.js
+++ b/ui/src/main.js
@@ -21,6 +21,7 @@ import {
faTrash,
faShare,
faUserFriends,
+ faTimesCircle,
} from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
@@ -51,6 +52,7 @@ library.add(
faTrash,
faShare,
faUserFriends,
+ faTimesCircle
)
Vue.use(Buefy, {
defaultIconComponent: 'vue-fontawesome',
diff --git a/ui/src/router/views/createFillup.vue b/ui/src/router/views/createFillup.vue
index d2280e6..d26cf16 100644
--- a/ui/src/router/views/createFillup.vue
+++ b/ui/src/router/views/createFillup.vue
@@ -34,6 +34,7 @@ export default {
quickEntry: null,
myVehicles: [],
users: [],
+ fuelSubTypes: [],
selectedVehicle: this.vehicle,
fillupModel: this.fillup,
processQuickEntry: false,
@@ -46,6 +47,14 @@ export default {
},
...mapState('users', ['me']),
...mapState('vehicles', ['fuelUnitMasters', 'fuelTypeMasters', 'vehicles']),
+ filteredFuelSubtypes() {
+ if (!this.fillupModel.fuelSubType) {
+ return this.fuelSubTypes
+ }
+ return this.fuelSubTypes.filter((option) => {
+ return option.toLowerCase().indexOf(this.fillupModel.fuelSubType.toLowerCase()) >= 0
+ })
+ },
},
watch: {
'fillupModel.fuelQuantity': function(old, newOne) {
@@ -64,6 +73,7 @@ export default {
this.myVehicles = this.vehicles
this.selectedVehicle = this.vehicle
this.fetchVehicleUsers()
+ this.fetchVehicleFuelSubTypes()
if (!this.fillup.id) {
this.fillupModel = this.getEmptyFillup()
this.fillupModel.userId = this.me.id
@@ -82,6 +92,14 @@ export default {
})
.catch((err) => console.log(err))
},
+ fetchVehicleFuelSubTypes() {
+ store
+ .dispatch('vehicles/fetchFuelSubtypesByVehicleId', { vehicleId: this.selectedVehicle.id })
+ .then((data) => {
+ this.fuelSubTypes = data
+ })
+ .catch((err) => console.log(err))
+ },
getEmptyFillup() {
return {
vehicleId: this.selectedVehicle.id,
@@ -96,6 +114,7 @@ export default {
fillingStation: '',
comments: '',
userId: '',
+ fuelSubType: '',
}
},
async createFillup() {
@@ -201,6 +220,17 @@ export default {
>
+
Current Version
- 2021.07.14
+ 2021.07.23
Website
diff --git a/ui/src/router/views/vehicle.vue b/ui/src/router/views/vehicle.vue
index f130420..3c96d46 100644
--- a/ui/src/router/views/vehicle.vue
+++ b/ui/src/router/views/vehicle.vue
@@ -311,6 +311,9 @@ export default {