add fuel subtype to fillup

This commit is contained in:
Akhil Gupta
2021-07-23 16:30:55 +05:30
parent 19ab2a59dd
commit 4ee44fb1f1
10 changed files with 69 additions and 2 deletions

View File

@@ -8,7 +8,7 @@
</a> --> </a> -->
<h1 align="center" style="margin-bottom:0">Hammond</h1> <h1 align="center" style="margin-bottom:0">Hammond</h1>
<p align="center">Current Version - 2021.07.14</p> <p align="center">Current Version - 2021.07.23</p>
<p align="center"> <p align="center">
A self-hosted vehicle expense tracking system with support for multiple users. A self-hosted vehicle expense tracking system with support for multiple users.

View File

@@ -26,6 +26,7 @@ func RegisterVehicleController(router *gin.RouterGroup) {
router.GET("/me/stats", getMystats) router.GET("/me/stats", getMystats)
router.GET("/vehicles/:id/fillups", getFillupsByVehicleId) router.GET("/vehicles/:id/fillups", getFillupsByVehicleId)
router.GET("/vehicles/:id/fuelSubTypes", getFuelSubTypesByVehicleId)
router.POST("/vehicles/:id/fillups", createFillup) router.POST("/vehicles/:id/fillups", createFillup)
router.GET("/vehicles/:id/fillups/:subId", getFillupById) router.GET("/vehicles/:id/fillups/:subId", getFillupById)
router.PUT("/vehicles/:id/fillups/:subId", updateFillup) router.PUT("/vehicles/:id/fillups/:subId", updateFillup)
@@ -121,6 +122,22 @@ func getFillupsByVehicleId(c *gin.Context) {
c.JSON(http.StatusUnprocessableEntity, common.NewValidatorError(err)) 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) { func getExpensesByVehicleId(c *gin.Context) {

View File

@@ -119,6 +119,7 @@ type Fillup struct {
Currency string `json:"currency"` Currency string `json:"currency"`
DistanceUnit DistanceUnit `json:"distanceUnit"` DistanceUnit DistanceUnit `json:"distanceUnit"`
Source string `json:"source"` Source string `json:"source"`
FuelSubType string `json:"fuelSubType"`
} }
func (v *Fillup) FuelUnitDetail() EnumDetail { func (v *Fillup) FuelUnitDetail() EnumDetail {

View File

@@ -50,6 +50,7 @@ type CreateFillupRequest struct {
FillingStation string `form:"fillingStation" json:"fillingStation"` FillingStation string `form:"fillingStation" json:"fillingStation"`
UserID string `form:"userId" json:"userId" binding:"required"` UserID string `form:"userId" json:"userId" binding:"required"`
Date time.Time `form:"date" json:"date" binding:"required" time_format:"2006-01-02"` Date time.Time `form:"date" json:"date" binding:"required" time_format:"2006-01-02"`
FuelSubType string `form:"fuelSubType" json:"fuelSubType"`
} }
type UpdateFillupRequest struct { type UpdateFillupRequest struct {

View File

@@ -139,6 +139,7 @@ func CreateFillup(model models.CreateFillupRequest) (*db.Fillup, error) {
Date: model.Date, Date: model.Date,
Currency: user.Currency, Currency: user.Currency,
DistanceUnit: user.DistanceUnit, DistanceUnit: user.DistanceUnit,
FuelSubType: model.FuelSubType,
Source: "API", Source: "API",
} }
@@ -196,6 +197,7 @@ func UpdateFillup(fillupId string, model models.UpdateFillupRequest) error {
Comments: model.Comments, Comments: model.Comments,
FillingStation: model.FillingStation, FillingStation: model.FillingStation,
UserID: model.UserID, UserID: model.UserID,
FuelSubType: model.FuelSubType,
Date: model.Date, Date: model.Date,
}).Error }).Error
} }
@@ -235,6 +237,11 @@ func GetVehicleAttachments(vehicleId string) (*[]db.Attachment, error) {
return db.GetVehicleAttachments(vehicleId) 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) { func GetUserStats(userId string, model models.UserStatsQueryModel) ([]models.VehicleStatsModel, error) {

View File

@@ -21,6 +21,7 @@ import {
faTrash, faTrash,
faShare, faShare,
faUserFriends, faUserFriends,
faTimesCircle,
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
@@ -51,6 +52,7 @@ library.add(
faTrash, faTrash,
faShare, faShare,
faUserFriends, faUserFriends,
faTimesCircle
) )
Vue.use(Buefy, { Vue.use(Buefy, {
defaultIconComponent: 'vue-fontawesome', defaultIconComponent: 'vue-fontawesome',

View File

@@ -34,6 +34,7 @@ export default {
quickEntry: null, quickEntry: null,
myVehicles: [], myVehicles: [],
users: [], users: [],
fuelSubTypes: [],
selectedVehicle: this.vehicle, selectedVehicle: this.vehicle,
fillupModel: this.fillup, fillupModel: this.fillup,
processQuickEntry: false, processQuickEntry: false,
@@ -46,6 +47,14 @@ export default {
}, },
...mapState('users', ['me']), ...mapState('users', ['me']),
...mapState('vehicles', ['fuelUnitMasters', 'fuelTypeMasters', 'vehicles']), ...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: { watch: {
'fillupModel.fuelQuantity': function(old, newOne) { 'fillupModel.fuelQuantity': function(old, newOne) {
@@ -64,6 +73,7 @@ export default {
this.myVehicles = this.vehicles this.myVehicles = this.vehicles
this.selectedVehicle = this.vehicle this.selectedVehicle = this.vehicle
this.fetchVehicleUsers() this.fetchVehicleUsers()
this.fetchVehicleFuelSubTypes()
if (!this.fillup.id) { if (!this.fillup.id) {
this.fillupModel = this.getEmptyFillup() this.fillupModel = this.getEmptyFillup()
this.fillupModel.userId = this.me.id this.fillupModel.userId = this.me.id
@@ -82,6 +92,14 @@ export default {
}) })
.catch((err) => console.log(err)) .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() { getEmptyFillup() {
return { return {
vehicleId: this.selectedVehicle.id, vehicleId: this.selectedVehicle.id,
@@ -96,6 +114,7 @@ export default {
fillingStation: '', fillingStation: '',
comments: '', comments: '',
userId: '', userId: '',
fuelSubType: '',
} }
}, },
async createFillup() { async createFillup() {
@@ -201,6 +220,17 @@ export default {
> >
</b-datepicker> </b-datepicker>
</b-field> </b-field>
<b-field label="Fuel Subtype">
<b-autocomplete
v-model="fillupModel.fuelSubType"
:data="filteredFuelSubtypes"
placeholder="Octane etc."
clearable
autofocus
@select="(option) => (fillupModel.fuelSubType = option)"
>
</b-autocomplete>
</b-field>
<b-field label="Quantity*" addons> <b-field label="Quantity*" addons>
<b-input v-model.number="fillupModel.fuelQuantity" type="number" step=".001" min="0" expanded required></b-input> <b-input v-model.number="fillupModel.fuelQuantity" type="number" step=".001" min="0" expanded required></b-input>
<b-select v-model="fillupModel.fuelUnit" placeholder="Fuel Unit" required> <b-select v-model="fillupModel.fuelUnit" placeholder="Fuel Unit" required>

View File

@@ -181,7 +181,7 @@ export default {
<table class="table is-hoverable"> <table class="table is-hoverable">
<tr> <tr>
<td>Current Version</td> <td>Current Version</td>
<td>2021.07.14</td> <td>2021.07.23</td>
</tr> </tr>
<tr> <tr>
<td>Website</td> <td>Website</td>

View File

@@ -311,6 +311,9 @@ export default {
<b-table-column v-slot="props" field="date" label="Date" :td-attrs="columnTdAttrs" sortable date> <b-table-column v-slot="props" field="date" label="Date" :td-attrs="columnTdAttrs" sortable date>
{{ formatDate(props.row.date) }} {{ formatDate(props.row.date) }}
</b-table-column> </b-table-column>
<b-table-column v-slot="props" field="fuelSubType" label="Fuel Sub Type" :td-attrs="columnTdAttrs">
{{ props.row.fuelSubType }}
</b-table-column>
<b-table-column v-slot="props" field="fuelQuantity" label="Qty." :td-attrs="hiddenMobile" numeric> <b-table-column v-slot="props" field="fuelQuantity" label="Qty." :td-attrs="hiddenMobile" numeric>
{{ `${props.row.fuelQuantity} ${props.row.fuelUnitDetail.short}` }} {{ `${props.row.fuelQuantity} ${props.row.fuelUnitDetail.short}` }}
</b-table-column> </b-table-column>

View File

@@ -140,6 +140,12 @@ export const actions = {
return data return data
}) })
}, },
fetchFuelSubtypesByVehicleId({ commit, state, rootState }, { vehicleId, force }) {
return axios.get(`/api/vehicles/${vehicleId}/fuelSubTypes`).then((response) => {
const data = response.data
return data
})
},
fetchStatsByVehicleId({ commit, state, rootState }, { vehicleId, force }) { fetchStatsByVehicleId({ commit, state, rootState }, { vehicleId, force }) {
if (state.vehicleStats.has(vehicleId) && !force) { if (state.vehicleStats.has(vehicleId) && !force) {
return Promise.resolve(state.vehicleStats.get(vehicleId)) return Promise.resolve(state.vehicleStats.get(vehicleId))