Compare commits
150 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5dfe430a3 | ||
|
|
331d98af0e | ||
|
|
8e70b0d8ba | ||
|
|
c8b7e3b3a1 | ||
|
|
8b4f773fe0 | ||
|
|
79a9357a62 | ||
|
|
9e34b6c6f8 | ||
|
|
c4389f6a80 | ||
|
|
dd1d646a8a | ||
|
|
bd4b389139 | ||
|
|
996b146d2c | ||
|
|
c5fdfd4ca9 | ||
|
|
6804be4f7a | ||
|
|
79e4f6ab4d | ||
|
|
5cecc82d95 | ||
|
|
298f58a738 | ||
|
|
793bac40a3 | ||
|
|
9cb65e4cda | ||
|
|
a67c460434 | ||
|
|
355739a966 | ||
|
|
71bbd6b443 | ||
|
|
6e59156c24 | ||
|
|
d786e1ad08 | ||
|
|
bb0dc22630 | ||
|
|
d81701c4fa | ||
|
|
c4f5d93b8b | ||
|
|
6132aa36af | ||
|
|
49cc485866 | ||
|
|
4ed813cd2e | ||
|
|
9bcc2cc2a0 | ||
|
|
d3d8cc268d | ||
|
|
62dcf663ff | ||
|
|
b016dadb9d | ||
|
|
b962565ed6 | ||
|
|
20b0e246fd | ||
|
|
f1a7a053f4 | ||
|
|
359f35c53f | ||
|
|
ea3423d32a | ||
|
|
6542a3bb28 | ||
|
|
35d2f1ca0b | ||
|
|
565d5701be | ||
|
|
2eb78ab73c | ||
|
|
edf4647549 | ||
|
|
e87a348b90 | ||
|
|
c15b22c71a | ||
|
|
1c9f9c7803 | ||
|
|
89bdfdefd4 | ||
|
|
2974fd783f | ||
|
|
bd22b5a497 | ||
|
|
8f6408a92b | ||
|
|
20bc28fffa | ||
|
|
3c89e75a34 | ||
|
|
5594356166 | ||
|
|
cea08a59be | ||
|
|
f16ed1a39f | ||
|
|
66032fcf55 | ||
|
|
34a9d56726 | ||
|
|
32a5d932c6 | ||
|
|
a0880ad5b6 | ||
|
|
17e8e5914e | ||
|
|
a14f298822 | ||
|
|
afe4078897 | ||
|
|
01f9b455cf | ||
|
|
c9c06f865c | ||
|
|
e2c14afc99 | ||
|
|
415d0abc83 | ||
|
|
d32fd8073d | ||
|
|
d6eab70ca6 | ||
|
|
cc82536970 | ||
|
|
094cf0d7c9 | ||
|
|
24f295c632 | ||
|
|
e9812e7e27 | ||
|
|
785ff9a089 | ||
|
|
b99c3921d7 | ||
|
|
d64777dca6 | ||
|
|
5208437ec2 | ||
|
|
654087b990 | ||
|
|
d294db34fc | ||
|
|
9f9f90fd1d | ||
|
|
051e3476a7 | ||
|
|
845dcb242a | ||
|
|
df165dae6e | ||
|
|
e389a9ac2a | ||
|
|
e2e4169787 | ||
|
|
2a8325c6ce | ||
|
|
cd2e9ebc61 | ||
|
|
1ac3a8b31b | ||
|
|
f07922763b | ||
|
|
9da21b2192 | ||
|
|
a8c85bcd7d | ||
|
|
d597a4ed30 | ||
|
|
45456280b4 | ||
|
|
1d5794e344 | ||
|
|
cd558ba744 | ||
|
|
3a2c82c789 | ||
|
|
d196536d74 | ||
|
|
630a7f2ec6 | ||
|
|
f2bc01289a | ||
|
|
a8d2b37087 | ||
|
|
7436399d90 | ||
|
|
bc3e1f0982 | ||
|
|
d429fa34bd | ||
|
|
5095cb4c61 | ||
|
|
e0df7ee80e | ||
|
|
431de8c3eb | ||
|
|
41793784ea | ||
|
|
85b5ad28bf | ||
|
|
b386012e13 | ||
|
|
df2d7288df | ||
|
|
7a6f796561 | ||
|
|
aee52d0594 | ||
|
|
f8b1de8d15 | ||
|
|
a7896340e1 | ||
|
|
f2a3bb2e9f | ||
|
|
d343619f13 | ||
|
|
adce0efa8b | ||
|
|
fc6f4bc00d | ||
|
|
a16bcf850f | ||
|
|
4ace38f8f3 | ||
|
|
63e330ffb0 | ||
|
|
fc9796081e | ||
|
|
440913af9c | ||
|
|
66d01afe6e | ||
|
|
ad4a399dc8 | ||
|
|
2137bf7702 | ||
|
|
47bdf7b505 | ||
|
|
669bffa955 | ||
|
|
05c5381a06 | ||
|
|
e623e3ad1a | ||
|
|
c43a2f639a | ||
|
|
e66e5b7724 | ||
|
|
adfd70fe98 | ||
|
|
ebebcacdc9 | ||
|
|
3299c13181 | ||
|
|
2661f8ae36 | ||
|
|
091cfdcc99 | ||
|
|
9771dc4c25 | ||
|
|
c0db2c5c1e | ||
|
|
2ecb113918 | ||
|
|
966cac280f | ||
|
|
2749707546 | ||
|
|
f1bf36bcb9 | ||
|
|
3322e2f6bd | ||
|
|
9ef929dbd5 | ||
|
|
dc33aaad49 | ||
|
|
15cf09f326 | ||
|
|
1e099ec8b6 | ||
|
|
e8f7815d8d | ||
|
|
bfaebf17d0 | ||
|
|
d314ed4a16 |
17
.github/workflows/hub.yml
vendored
17
.github/workflows/hub.yml
vendored
@@ -12,25 +12,18 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
id: qemu
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
- name: Available platforms
|
||||
run: echo ${{ steps.qemu.outputs.platforms }}
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Set up build cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Parse the git tag
|
||||
id: get_tag
|
||||
run: echo ::set-output name=TAG::$(echo $GITHUB_REF | cut -d / -f 3)
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
@@ -41,12 +34,10 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
#platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
|
||||
#platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: true
|
||||
# cache-from: type=local,src=/tmp/.buildx-cache
|
||||
|
||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Don't track .vscode directory
|
||||
.vscode
|
||||
!.vscode/launch.json
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ARG GO_VERSION=1.16.2
|
||||
ARG GO_VERSION=1.20.6
|
||||
FROM golang:${GO_VERSION}-alpine AS builder
|
||||
RUN apk update && apk add alpine-sdk git && rm -rf /var/cache/apk/*
|
||||
RUN mkdir -p /api
|
||||
@@ -9,9 +9,11 @@ RUN go mod download
|
||||
COPY ./server .
|
||||
RUN go build -o ./app ./main.go
|
||||
|
||||
FROM node:14 as build-stage
|
||||
FROM node:16-alpine as build-stage
|
||||
WORKDIR /app
|
||||
COPY ./ui/package*.json ./
|
||||
RUN apk add --no-cache autoconf automake build-base nasm libc6-compat python3 py3-pip make g++ libpng-dev zlib-dev pngquant
|
||||
|
||||
RUN npm install
|
||||
COPY ./ui .
|
||||
RUN npm run build
|
||||
@@ -25,7 +27,7 @@ ENV UID=998
|
||||
ENV PID=100
|
||||
ENV GIN_MODE=release
|
||||
VOLUME ["/config", "/assets"]
|
||||
RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*
|
||||
RUN apk update && apk add ca-certificates tzdata && rm -rf /var/cache/apk/*
|
||||
RUN mkdir -p /config; \
|
||||
mkdir -p /assets; \
|
||||
mkdir -p /api
|
||||
|
||||
16
README.md
16
README.md
@@ -1,6 +1,5 @@
|
||||
<p align="center">
|
||||
<h1 align="center" style="margin-bottom:0">Hammond</h1>
|
||||
<p align="center">Current Version - 2022.07.06</p>
|
||||
|
||||
<p align="center">
|
||||
A self-hosted vehicle expense tracking system with support for multiple users.
|
||||
@@ -116,6 +115,21 @@ services:
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Install on Kubernetes
|
||||
|
||||
You can install Hammond on Kubernetes by using Helm. The
|
||||
[Helm chart for Hammond](https://github.com/djjudas21/charts/tree/main/charts/hammond)
|
||||
is maintained by djjudas21.
|
||||
|
||||
Check out the default [`values.yaml`](https://github.com/djjudas21/charts/blob/main/charts/hammond/values.yaml)
|
||||
to see what you can override.
|
||||
|
||||
```console
|
||||
helm repo add djjudas21 https://djjudas21.github.io/charts/
|
||||
helm repo update djjudas21
|
||||
helm install djjudas21/hammond
|
||||
```
|
||||
|
||||
### Build from Source / Ubuntu Installation
|
||||
|
||||
Although personally I feel that using the docker container is the best way of using
|
||||
|
||||
3
server/.gitignore
vendored
3
server/.gitignore
vendored
@@ -14,6 +14,7 @@
|
||||
|
||||
# MS VSCode
|
||||
.vscode
|
||||
!.vscode/launch.json
|
||||
__debug_bin
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
@@ -22,4 +23,4 @@ assets/*
|
||||
keys/*
|
||||
backups/*
|
||||
nodemon.json
|
||||
dist/*
|
||||
dist/*
|
||||
|
||||
@@ -7,7 +7,8 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"hammond/db"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
@@ -25,6 +26,33 @@ func RandString(n int) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// A helper to convert from litres to gallon
|
||||
func LitreToGallon(litres float32) float32 {
|
||||
gallonConversionFactor := 0.21997
|
||||
return litres * float32(gallonConversionFactor);
|
||||
}
|
||||
|
||||
// A helper to convert from gallon to litres
|
||||
func GallonToLitre(gallons float32) float32 {
|
||||
litreConversionFactor := 3.785412
|
||||
return gallons * float32(litreConversionFactor);
|
||||
}
|
||||
|
||||
|
||||
// A helper to convert from km to miles
|
||||
func KmToMiles(km float32) float32 {
|
||||
kmConversionFactor := 0.62137119
|
||||
return km * float32(kmConversionFactor);
|
||||
}
|
||||
|
||||
// A helper to convert from miles to km
|
||||
func MilesToKm(miles float32) float32 {
|
||||
milesConversionFactor := 1.609344
|
||||
return miles * float32(milesConversionFactor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// A Util function to generate jwt_token which can be used in the request header
|
||||
func GenToken(id string, role db.Role) (string, string) {
|
||||
jwt_token := jwt.New(jwt.GetSigningMethod("HS256"))
|
||||
|
||||
@@ -7,10 +7,11 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/akhilrex/hammond/common"
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"github.com/akhilrex/hammond/service"
|
||||
"hammond/common"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
"hammond/service"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -5,10 +5,11 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/akhilrex/hammond/common"
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"github.com/akhilrex/hammond/service"
|
||||
"hammond/common"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
"hammond/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
|
||||
@@ -2,13 +2,18 @@ package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"hammond/models"
|
||||
"hammond/service"
|
||||
|
||||
"github.com/akhilrex/hammond/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisteImportController(router *gin.RouterGroup) {
|
||||
router.POST("/import/fuelly", fuellyImport)
|
||||
router.POST("/import/drivvo", drivvoImport)
|
||||
router.POST("/import/generic", genericImport)
|
||||
}
|
||||
|
||||
func fuellyImport(c *gin.Context) {
|
||||
@@ -24,3 +29,46 @@ func fuellyImport(c *gin.Context) {
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
}
|
||||
|
||||
func drivvoImport(c *gin.Context) {
|
||||
bytes, err := getFileBytes(c, "file")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnprocessableEntity, err)
|
||||
return
|
||||
}
|
||||
vehicleId := c.PostForm("vehicleID")
|
||||
if vehicleId == "" {
|
||||
c.JSON(http.StatusUnprocessableEntity, "Missing Vehicle ID")
|
||||
return
|
||||
}
|
||||
importLocation, err := strconv.ParseBool(c.PostForm("importLocation"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnprocessableEntity, "Please include importLocation option.")
|
||||
return
|
||||
}
|
||||
|
||||
errors := service.DrivvoImport(bytes, c.MustGet("userId").(string), vehicleId, importLocation)
|
||||
if len(errors) > 0 {
|
||||
c.JSON(http.StatusUnprocessableEntity, gin.H{"errors": errors})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
}
|
||||
|
||||
func genericImport(c *gin.Context) {
|
||||
var json models.ImportData
|
||||
if err := c.ShouldBindJSON(&json); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if json.VehicleId == "" {
|
||||
c.JSON(http.StatusUnprocessableEntity, "Missing Vehicle ID")
|
||||
return
|
||||
}
|
||||
errors := service.GenericImport(json, c.MustGet("userId").(string))
|
||||
if len(errors) > 0 {
|
||||
c.JSON(http.StatusUnprocessableEntity, gin.H{"errors": errors})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@ package controllers
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/akhilrex/hammond/common"
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"github.com/akhilrex/hammond/service"
|
||||
"hammond/common"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
"hammond/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"hammond/db"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/dgrijalva/jwt-go/request"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
@@ -3,9 +3,10 @@ package controllers
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/akhilrex/hammond/common"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"github.com/akhilrex/hammond/service"
|
||||
"hammond/common"
|
||||
"hammond/models"
|
||||
"hammond/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -25,7 +26,7 @@ func getMileageForVehicle(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
fillups, err := service.GetMileageByVehicleId(searchByIdQuery.Id, model.Since)
|
||||
fillups, err := service.GetMileageByVehicleId(searchByIdQuery.Id, model.Since, model.MileageOption)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnprocessableEntity, common.NewError("getMileageForVehicle", err))
|
||||
return
|
||||
|
||||
@@ -4,10 +4,11 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/akhilrex/hammond/common"
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"github.com/akhilrex/hammond/service"
|
||||
"hammond/common"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
"hammond/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@ package controllers
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/akhilrex/hammond/common"
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"github.com/akhilrex/hammond/service"
|
||||
"hammond/common"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
"hammond/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/akhilrex/hammond/common"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"github.com/akhilrex/hammond/service"
|
||||
"hammond/common"
|
||||
"hammond/models"
|
||||
"hammond/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module github.com/akhilrex/hammond
|
||||
module hammond
|
||||
|
||||
go 1.16
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/akhilrex/hammond/controllers"
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/service"
|
||||
"hammond/controllers"
|
||||
"hammond/db"
|
||||
"hammond/service"
|
||||
|
||||
"github.com/gin-contrib/location"
|
||||
"github.com/gin-gonic/contrib/static"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
@@ -3,7 +3,7 @@ package models
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"hammond/db"
|
||||
)
|
||||
|
||||
type CreateAlertModel struct {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package models
|
||||
|
||||
import "github.com/akhilrex/hammond/db"
|
||||
import "hammond/db"
|
||||
|
||||
type LoginResponse struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
22
server/models/import.go
Normal file
22
server/models/import.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package models
|
||||
|
||||
type ImportData struct {
|
||||
Data []ImportFillup `json:"data" binding:"required"`
|
||||
VehicleId string `json:"vehicleId" binding:"required"`
|
||||
TimeZone string `json:"timezone" binding:"required"`
|
||||
}
|
||||
|
||||
type ImportFillup struct {
|
||||
VehicleID string `json:"vehicleId"`
|
||||
FuelQuantity float32 `json:"fuelQuantity"`
|
||||
PerUnitPrice float32 `json:"perUnitPrice"`
|
||||
TotalAmount float32 `json:"totalAmount"`
|
||||
OdoReading int `json:"odoReading"`
|
||||
IsTankFull *bool `json:"isTankFull"`
|
||||
HasMissedFillup *bool `json:"hasMissedFillup"`
|
||||
Comments string `json:"comments"`
|
||||
FillingStation string `json:"fillingStation"`
|
||||
UserID string `json:"userId"`
|
||||
Date string `json:"date"`
|
||||
FuelSubType string `json:"fuelSubType"`
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package models
|
||||
|
||||
import "github.com/akhilrex/hammond/db"
|
||||
import "hammond/db"
|
||||
|
||||
type UpdateSettingModel struct {
|
||||
Currency string `json:"currency" form:"currency" query:"currency"`
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"hammond/db"
|
||||
)
|
||||
|
||||
type MileageModel struct {
|
||||
@@ -14,7 +14,7 @@ type MileageModel struct {
|
||||
FuelQuantity float32 `form:"fuelQuantity" json:"fuelQuantity" binding:"required"`
|
||||
PerUnitPrice float32 `form:"perUnitPrice" json:"perUnitPrice" binding:"required"`
|
||||
Currency string `json:"currency"`
|
||||
|
||||
DistanceUnit db.DistanceUnit `form:"distanceUnit" json:"distanceUnit"`
|
||||
Mileage float32 `form:"mileage" json:"mileage" binding:"mileage"`
|
||||
CostPerMile float32 `form:"costPerMile" json:"costPerMile" binding:"costPerMile"`
|
||||
OdoReading int `form:"odoReading" json:"odoReading" binding:"odoReading"`
|
||||
@@ -35,4 +35,5 @@ func (b *MileageModel) MarshalJSON() ([]byte, error) {
|
||||
|
||||
type MileageQueryModel struct {
|
||||
Since time.Time `json:"since" query:"since" form:"since"`
|
||||
MileageOption string `json:"mileageOption" query:"mileageOption" form:"mileageOption"`
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ package models
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"hammond/db"
|
||||
|
||||
_ "github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
)
|
||||
|
||||
func CreateAlert(model models.CreateAlertModel, vehicleId, userId string) (*db.VehicleAlert, error) {
|
||||
|
||||
142
server/service/drivvoImportService.go
Normal file
142
server/service/drivvoImportService.go
Normal file
@@ -0,0 +1,142 @@
|
||||
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
|
||||
}
|
||||
@@ -13,9 +13,10 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/internal/sanitize"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"hammond/db"
|
||||
"hammond/internal/sanitize"
|
||||
"hammond/models"
|
||||
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
|
||||
141
server/service/fuellyImportService.go
Normal file
141
server/service/fuellyImportService.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"hammond/db"
|
||||
|
||||
"github.com/leekchan/accounting"
|
||||
)
|
||||
|
||||
func FuellyParseAll(content []byte, userId string) ([]db.Fillup, []db.Expense, []string) {
|
||||
stream := bytes.NewReader(content)
|
||||
reader := csv.NewReader(stream)
|
||||
records, err := reader.ReadAll()
|
||||
|
||||
var errors []string
|
||||
user, err := GetUserById(userId)
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return nil, nil, errors
|
||||
}
|
||||
|
||||
vehicles, err := GetUserVehicles(userId)
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return nil, nil, errors
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return nil, nil, errors
|
||||
}
|
||||
|
||||
var vehicleMap map[string]db.Vehicle = make(map[string]db.Vehicle)
|
||||
for _, vehicle := range *vehicles {
|
||||
vehicleMap[vehicle.Nickname] = vehicle
|
||||
}
|
||||
|
||||
var fillups []db.Fillup
|
||||
var expenses []db.Expense
|
||||
layout := "2006-01-02 15:04"
|
||||
altLayout := "2006-01-02 3:04 PM"
|
||||
|
||||
for index, record := range records {
|
||||
if index == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var vehicle db.Vehicle
|
||||
var ok bool
|
||||
if vehicle, ok = vehicleMap[record[4]]; !ok {
|
||||
errors = append(errors, "Found an unmapped vehicle entry at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
dateStr := record[2] + " " + record[3]
|
||||
date, err := time.Parse(layout, dateStr)
|
||||
if err != nil {
|
||||
date, err = time.Parse(altLayout, dateStr)
|
||||
}
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid date/time at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
|
||||
totalCostStr := accounting.UnformatNumber(record[9], 3, user.Currency)
|
||||
totalCost64, err := strconv.ParseFloat(totalCostStr, 32)
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid total cost at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
|
||||
totalCost := float32(totalCost64)
|
||||
odoStr := accounting.UnformatNumber(record[5], 0, user.Currency)
|
||||
odoreading, err := strconv.Atoi(odoStr)
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid odo reading at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
location := record[12]
|
||||
|
||||
//Create Fillup
|
||||
if record[0] == "Gas" {
|
||||
rateStr := accounting.UnformatNumber(record[7], 3, user.Currency)
|
||||
ratet64, err := strconv.ParseFloat(rateStr, 32)
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid cost per gallon at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
rate := float32(ratet64)
|
||||
|
||||
quantity64, err := strconv.ParseFloat(record[8], 32)
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid quantity at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
quantity := float32(quantity64)
|
||||
|
||||
notes := fmt.Sprintf("Octane:%s\nGas Brand:%s\nLocation%s\nTags:%s\nPayment Type:%s\nTire Pressure:%s\nNotes:%s\nMPG:%s",
|
||||
record[10], record[11], record[12], record[13], record[14], record[15], record[16], record[1],
|
||||
)
|
||||
|
||||
isTankFull := record[6] == "Full"
|
||||
fal := false
|
||||
fillups = append(fillups, db.Fillup{
|
||||
VehicleID: vehicle.ID,
|
||||
FuelUnit: vehicle.FuelUnit,
|
||||
FuelQuantity: quantity,
|
||||
PerUnitPrice: rate,
|
||||
TotalAmount: totalCost,
|
||||
OdoReading: odoreading,
|
||||
IsTankFull: &isTankFull,
|
||||
Comments: notes,
|
||||
FillingStation: location,
|
||||
HasMissedFillup: &fal,
|
||||
UserID: userId,
|
||||
Date: date,
|
||||
Currency: user.Currency,
|
||||
DistanceUnit: user.DistanceUnit,
|
||||
Source: "Fuelly",
|
||||
})
|
||||
|
||||
}
|
||||
if record[0] == "Service" {
|
||||
notes := fmt.Sprintf("Tags:%s\nPayment Type:%s\nNotes:%s",
|
||||
record[13], record[14], record[16],
|
||||
)
|
||||
expenses = append(expenses, db.Expense{
|
||||
VehicleID: vehicle.ID,
|
||||
Amount: totalCost,
|
||||
OdoReading: odoreading,
|
||||
Comments: notes,
|
||||
ExpenseType: record[17],
|
||||
UserID: userId,
|
||||
Currency: user.Currency,
|
||||
Date: date,
|
||||
DistanceUnit: user.DistanceUnit,
|
||||
Source: "Fuelly",
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
return fillups, expenses, errors
|
||||
}
|
||||
47
server/service/genericImportService.go
Normal file
47
server/service/genericImportService.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GenericParseRefuelings(content []models.ImportFillup, user *db.User, vehicle *db.Vehicle, timezone string) ([]db.Fillup, []string) {
|
||||
var errors []string
|
||||
var fillups []db.Fillup
|
||||
dateLayout := "2006-01-02T15:04:05.000Z"
|
||||
loc, _ := time.LoadLocation(timezone)
|
||||
for _, record := range content {
|
||||
date, err := time.ParseInLocation(dateLayout, record.Date, loc)
|
||||
if err != nil {
|
||||
date = time.Date(2000, time.December, 0, 0, 0, 0, 0, loc)
|
||||
}
|
||||
|
||||
var missedFillup bool
|
||||
if record.HasMissedFillup == nil {
|
||||
missedFillup = false
|
||||
} else {
|
||||
missedFillup = *record.HasMissedFillup
|
||||
}
|
||||
|
||||
fillups = append(fillups, db.Fillup{
|
||||
VehicleID: vehicle.ID,
|
||||
UserID: user.ID,
|
||||
Date: date,
|
||||
IsTankFull: record.IsTankFull,
|
||||
HasMissedFillup: &missedFillup,
|
||||
FuelQuantity: float32(record.FuelQuantity),
|
||||
PerUnitPrice: float32(record.PerUnitPrice),
|
||||
FillingStation: record.FillingStation,
|
||||
OdoReading: record.OdoReading,
|
||||
TotalAmount: float32(record.TotalAmount),
|
||||
FuelUnit: vehicle.FuelUnit,
|
||||
Currency: user.Currency,
|
||||
DistanceUnit: user.DistanceUnit,
|
||||
Comments: record.Comments,
|
||||
Source: "Generic Import",
|
||||
})
|
||||
}
|
||||
|
||||
return fillups, errors
|
||||
}
|
||||
@@ -2,144 +2,13 @@ package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/leekchan/accounting"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
)
|
||||
|
||||
func FuellyImport(content []byte, userId string) []string {
|
||||
stream := bytes.NewReader(content)
|
||||
reader := csv.NewReader(stream)
|
||||
records, err := reader.ReadAll()
|
||||
|
||||
func WriteToDB(fillups []db.Fillup, expenses []db.Expense) []string {
|
||||
var errors []string
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
}
|
||||
|
||||
vehicles, err := GetUserVehicles(userId)
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
}
|
||||
user, err := GetUserById(userId)
|
||||
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
}
|
||||
|
||||
var vehicleMap map[string]db.Vehicle = make(map[string]db.Vehicle)
|
||||
for _, vehicle := range *vehicles {
|
||||
vehicleMap[vehicle.Nickname] = vehicle
|
||||
}
|
||||
|
||||
var fillups []db.Fillup
|
||||
var expenses []db.Expense
|
||||
layout := "2006-01-02 15:04"
|
||||
altLayout := "2006-01-02 3:04 PM"
|
||||
|
||||
for index, record := range records {
|
||||
if index == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var vehicle db.Vehicle
|
||||
var ok bool
|
||||
if vehicle, ok = vehicleMap[record[4]]; !ok {
|
||||
errors = append(errors, "Found an unmapped vehicle entry at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
dateStr := record[2] + " " + record[3]
|
||||
date, err := time.Parse(layout, dateStr)
|
||||
if err != nil {
|
||||
date, err = time.Parse(altLayout, dateStr)
|
||||
}
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid date/time at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
|
||||
totalCostStr := accounting.UnformatNumber(record[9], 3, user.Currency)
|
||||
totalCost64, err := strconv.ParseFloat(totalCostStr, 32)
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid total cost at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
|
||||
totalCost := float32(totalCost64)
|
||||
odoStr := accounting.UnformatNumber(record[5], 0, user.Currency)
|
||||
odoreading, err := strconv.Atoi(odoStr)
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid odo reading at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
location := record[12]
|
||||
|
||||
//Create Fillup
|
||||
if record[0] == "Gas" {
|
||||
rateStr := accounting.UnformatNumber(record[7], 3, user.Currency)
|
||||
ratet64, err := strconv.ParseFloat(rateStr, 32)
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid cost per gallon at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
rate := float32(ratet64)
|
||||
|
||||
quantity64, err := strconv.ParseFloat(record[8], 32)
|
||||
if err != nil {
|
||||
errors = append(errors, "Found an invalid quantity at row "+strconv.Itoa(index+1))
|
||||
}
|
||||
quantity := float32(quantity64)
|
||||
|
||||
notes := fmt.Sprintf("Octane:%s\nGas Brand:%s\nLocation%s\nTags:%s\nPayment Type:%s\nTire Pressure:%s\nNotes:%s\nMPG:%s",
|
||||
record[10], record[11], record[12], record[13], record[14], record[15], record[16], record[1],
|
||||
)
|
||||
|
||||
isTankFull := record[6] == "Full"
|
||||
fal := false
|
||||
fillups = append(fillups, db.Fillup{
|
||||
VehicleID: vehicle.ID,
|
||||
FuelUnit: vehicle.FuelUnit,
|
||||
FuelQuantity: quantity,
|
||||
PerUnitPrice: rate,
|
||||
TotalAmount: totalCost,
|
||||
OdoReading: odoreading,
|
||||
IsTankFull: &isTankFull,
|
||||
Comments: notes,
|
||||
FillingStation: location,
|
||||
HasMissedFillup: &fal,
|
||||
UserID: userId,
|
||||
Date: date,
|
||||
Currency: user.Currency,
|
||||
DistanceUnit: user.DistanceUnit,
|
||||
Source: "Fuelly",
|
||||
})
|
||||
|
||||
}
|
||||
if record[0] == "Service" {
|
||||
notes := fmt.Sprintf("Tags:%s\nPayment Type:%s\nNotes:%s",
|
||||
record[13], record[14], record[16],
|
||||
)
|
||||
expenses = append(expenses, db.Expense{
|
||||
VehicleID: vehicle.ID,
|
||||
Amount: totalCost,
|
||||
OdoReading: odoreading,
|
||||
Comments: notes,
|
||||
ExpenseType: record[17],
|
||||
UserID: userId,
|
||||
Currency: user.Currency,
|
||||
Date: date,
|
||||
DistanceUnit: user.DistanceUnit,
|
||||
Source: "Fuelly",
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
if len(errors) != 0 {
|
||||
return errors
|
||||
}
|
||||
|
||||
tx := db.DB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -150,19 +19,114 @@ func FuellyImport(content []byte, userId string) []string {
|
||||
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 fillups != nil {
|
||||
if err := tx.Create(&fillups).Error; err != nil {
|
||||
tx.Rollback()
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
}
|
||||
}
|
||||
if err := tx.Create(&expenses).Error; err != nil {
|
||||
tx.Rollback()
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
if expenses != nil {
|
||||
if err := tx.Create(&expenses).Error; err != nil {
|
||||
tx.Rollback()
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
}
|
||||
}
|
||||
err = tx.Commit().Error
|
||||
err := tx.Commit().Error
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
return errors
|
||||
|
||||
}
|
||||
|
||||
func DrivvoImport(content []byte, userId string, vehicleId string, importLocation bool) []string {
|
||||
var errors []string
|
||||
user, err := GetUserById(userId)
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
}
|
||||
|
||||
vehicle, err := GetVehicleById(vehicleId)
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
}
|
||||
|
||||
endParseIndex := bytes.Index(content, []byte("#Income"))
|
||||
if endParseIndex == -1 {
|
||||
endParseIndex = bytes.Index(content, []byte("#Route"))
|
||||
if endParseIndex == -1 {
|
||||
endParseIndex = len(content)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
serviceEndIndex := bytes.Index(content, []byte("#Expense"))
|
||||
if serviceEndIndex == -1 {
|
||||
serviceEndIndex = endParseIndex
|
||||
}
|
||||
|
||||
refuelEndIndex := bytes.Index(content, []byte("#Service"))
|
||||
if refuelEndIndex == -1 {
|
||||
refuelEndIndex = serviceEndIndex
|
||||
}
|
||||
|
||||
var fillups []db.Fillup
|
||||
fillups, errors = DrivvoParseRefuelings(content[:refuelEndIndex], user, vehicle, importLocation)
|
||||
|
||||
var allExpenses []db.Expense
|
||||
services, parseErrors := DrivvoParseExpenses(content[refuelEndIndex:serviceEndIndex], user, vehicle)
|
||||
if parseErrors != nil {
|
||||
errors = append(errors, parseErrors...)
|
||||
}
|
||||
allExpenses = append(allExpenses, services...)
|
||||
|
||||
expenses, parseErrors := DrivvoParseExpenses(content[serviceEndIndex:endParseIndex], user, vehicle)
|
||||
if parseErrors != nil {
|
||||
errors = append(errors, parseErrors...)
|
||||
}
|
||||
|
||||
allExpenses = append(allExpenses, expenses...)
|
||||
|
||||
if len(errors) != 0 {
|
||||
return errors
|
||||
}
|
||||
|
||||
return WriteToDB(fillups, allExpenses)
|
||||
}
|
||||
|
||||
func FuellyImport(content []byte, userId string) []string {
|
||||
fillups, expenses, errors := FuellyParseAll(content, userId)
|
||||
if len(errors) != 0 {
|
||||
return errors
|
||||
}
|
||||
|
||||
return WriteToDB(fillups, expenses)
|
||||
}
|
||||
|
||||
func GenericImport(content models.ImportData, userId string) []string {
|
||||
var errors []string
|
||||
user, err := GetUserById(userId)
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
}
|
||||
|
||||
vehicle, err := GetVehicleById(content.VehicleId)
|
||||
if err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
return errors
|
||||
}
|
||||
|
||||
var fillups []db.Fillup
|
||||
fillups, errors = GenericParseRefuelings(content.Data, user, vehicle, content.TimeZone)
|
||||
|
||||
if len(errors) != 0 {
|
||||
return errors
|
||||
}
|
||||
|
||||
return WriteToDB(fillups, nil)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"hammond/db"
|
||||
)
|
||||
|
||||
func CanInitializeSystem() (bool, error) {
|
||||
|
||||
@@ -4,11 +4,12 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"hammond/common"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
)
|
||||
|
||||
func GetMileageByVehicleId(vehicleId string, since time.Time) (mileage []models.MileageModel, err error) {
|
||||
func GetMileageByVehicleId(vehicleId string, since time.Time, mileageOption string) (mileage []models.MileageModel, err error) {
|
||||
data, err := db.GetFillupsByVehicleIdSince(vehicleId, since)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -36,14 +37,48 @@ func GetMileageByVehicleId(vehicleId string, since time.Time) (mileage []models.
|
||||
PerUnitPrice: currentFillup.PerUnitPrice,
|
||||
OdoReading: currentFillup.OdoReading,
|
||||
Currency: currentFillup.Currency,
|
||||
DistanceUnit: currentFillup.DistanceUnit,
|
||||
Mileage: 0,
|
||||
CostPerMile: 0,
|
||||
}
|
||||
|
||||
if currentFillup.IsTankFull != nil && *currentFillup.IsTankFull && (currentFillup.HasMissedFillup == nil || !(*currentFillup.HasMissedFillup)) {
|
||||
distance := float32(currentFillup.OdoReading - lastFillup.OdoReading)
|
||||
mileage.Mileage = distance / currentFillup.FuelQuantity
|
||||
mileage.CostPerMile = distance / currentFillup.TotalAmount
|
||||
currentOdoReading := float32(currentFillup.OdoReading);
|
||||
lastFillupOdoReading := float32(lastFillup.OdoReading);
|
||||
currentFuelQuantity := float32(currentFillup.FuelQuantity);
|
||||
// If miles per gallon option and distanceUnit is km, convert from km to miles
|
||||
// then check if fuel unit is litres. If it is, convert to gallons
|
||||
if (mileageOption == "mpg" && mileage.DistanceUnit == db.KILOMETERS) {
|
||||
currentOdoReading = common.KmToMiles(currentOdoReading);
|
||||
lastFillupOdoReading = common.KmToMiles(lastFillupOdoReading);
|
||||
if (mileage.FuelUnit == db.LITRE) {
|
||||
currentFuelQuantity = common.LitreToGallon(currentFuelQuantity);
|
||||
}
|
||||
}
|
||||
|
||||
// If km_litre option or litre per 100km and distanceUnit is miles, convert from miles to km
|
||||
// then check if fuel unit is not litres. If it isn't, convert to litres
|
||||
|
||||
if ((mileageOption == "km_litre" || mileageOption == "litre_100km") && mileage.DistanceUnit == db.MILES) {
|
||||
currentOdoReading = common.MilesToKm(currentOdoReading);
|
||||
lastFillupOdoReading = common.MilesToKm(lastFillupOdoReading);
|
||||
|
||||
if (mileage.FuelUnit == db.US_GALLON) {
|
||||
currentFuelQuantity = common.GallonToLitre(currentFuelQuantity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
distance := float32(currentOdoReading - lastFillupOdoReading);
|
||||
if (mileageOption == "litre_100km") {
|
||||
mileage.Mileage = currentFuelQuantity / distance * 100;
|
||||
} else {
|
||||
mileage.Mileage = distance / currentFuelQuantity;
|
||||
}
|
||||
|
||||
mileage.CostPerMile = distance / currentFillup.TotalAmount;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ package service
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
)
|
||||
|
||||
func CreateUser(userModel *models.RegisterRequest, role db.Role) error {
|
||||
|
||||
@@ -3,8 +3,9 @@ package service
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/akhilrex/hammond/db"
|
||||
"github.com/akhilrex/hammond/models"
|
||||
"hammond/db"
|
||||
"hammond/models"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
@@ -20,6 +20,7 @@ module.exports = {
|
||||
'no-console': process.env.PRE_COMMIT
|
||||
? ['error', { allow: ['warn', 'error'] }]
|
||||
: 'off',
|
||||
'vue/multi-word-component-names': 0,
|
||||
'import/no-relative-parent-imports': 'error',
|
||||
'import/order': 'error',
|
||||
'vue/array-bracket-spacing': 'error',
|
||||
|
||||
5
ui/.gitignore
vendored
5
ui/.gitignore
vendored
@@ -29,3 +29,8 @@ yarn-error.log*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw*
|
||||
|
||||
#Vs code files
|
||||
.vscode
|
||||
!.vscode/launch.json
|
||||
|
||||
|
||||
30
ui/.vscode/_components.code-snippets
vendored
30
ui/.vscode/_components.code-snippets
vendored
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"BaseButton": {
|
||||
"scope": "vue-html",
|
||||
"prefix": "BaseButton",
|
||||
"body": ["<BaseButton>", "\t${3}", "</BaseButton>"],
|
||||
"description": "<BaseButton>"
|
||||
},
|
||||
"BaseIcon": {
|
||||
"scope": "vue-html",
|
||||
"prefix": "BaseIcon",
|
||||
"body": ["<BaseIcon name=\"${1}\">", "\t${2}", "</BaseIcon>"],
|
||||
"description": "<BaseIcon>"
|
||||
},
|
||||
"BaseInputText": {
|
||||
"scope": "vue-html",
|
||||
"prefix": "BaseInputText",
|
||||
"body": ["<BaseInputText ${1}/>"],
|
||||
"description": "<BaseInputText>"
|
||||
},
|
||||
"BaseLink": {
|
||||
"scope": "vue-html",
|
||||
"prefix": "BaseLink",
|
||||
"body": [
|
||||
"<BaseLink ${1|name,:to,href|}=\"${2:route}\">",
|
||||
"\t${3}",
|
||||
"</BaseLink>"
|
||||
],
|
||||
"description": "<BaseLink>"
|
||||
}
|
||||
}
|
||||
26
ui/.vscode/_sfc-blocks.code-snippets
vendored
26
ui/.vscode/_sfc-blocks.code-snippets
vendored
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"script": {
|
||||
"scope": "vue",
|
||||
"prefix": "script",
|
||||
"body": ["<script>", "export default {", "\t${0}", "}", "</script>"],
|
||||
"description": "<script>"
|
||||
},
|
||||
"template": {
|
||||
"scope": "vue",
|
||||
"prefix": "template",
|
||||
"body": ["<template>", "\t${0}", "</template>"],
|
||||
"description": "<template>"
|
||||
},
|
||||
"style": {
|
||||
"scope": "vue",
|
||||
"prefix": "style",
|
||||
"body": [
|
||||
"<style lang=\"scss\" module>",
|
||||
"@import '@design';",
|
||||
"",
|
||||
"${0}",
|
||||
"</style>"
|
||||
],
|
||||
"description": "<style lang=\"scss\" module>"
|
||||
}
|
||||
}
|
||||
37
ui/.vscode/extensions.json
vendored
37
ui/.vscode/extensions.json
vendored
@@ -1,37 +0,0 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
// Syntax highlighting and more for .vue files
|
||||
// https://github.com/vuejs/vetur
|
||||
"octref.vetur",
|
||||
|
||||
// Peek and go-to-definition for .vue files
|
||||
// https://github.com/fuzinato/vscode-vue-peek
|
||||
"dariofuzinato.vue-peek",
|
||||
|
||||
// Lint-on-save with ESLint
|
||||
// https://github.com/microsoft/vscode-eslint
|
||||
"dbaeumer.vscode-eslint",
|
||||
|
||||
// Lint-on-save with Stylelint
|
||||
// https://github.com/stylelint/vscode-stylelint
|
||||
"stylelint.vscode-stylelint",
|
||||
|
||||
// Lint-on-save markdown in README files
|
||||
// https://github.com/DavidAnson/vscode-markdownlint
|
||||
"DavidAnson.vscode-markdownlint",
|
||||
|
||||
// Format-on-save with Prettier
|
||||
// https://github.com/prettier/prettier-vscode
|
||||
"esbenp.prettier-vscode",
|
||||
|
||||
// SCSS intellisense
|
||||
// https://github.com/mrmlnc/vscode-scss
|
||||
"mrmlnc.vscode-scss",
|
||||
|
||||
// Test `.unit.js` files on save with Jest
|
||||
// https://github.com/jest-community/vscode-jest
|
||||
"Orta.vscode-jest"
|
||||
]
|
||||
}
|
||||
93
ui/.vscode/settings.json
vendored
93
ui/.vscode/settings.json
vendored
@@ -1,93 +0,0 @@
|
||||
{
|
||||
// ===
|
||||
// Spacing
|
||||
// ===
|
||||
|
||||
"editor.insertSpaces": true,
|
||||
"editor.tabSize": 2,
|
||||
"editor.trimAutoWhitespace": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.eol": "\n",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
|
||||
// ===
|
||||
// Files
|
||||
// ===
|
||||
|
||||
"files.exclude": {
|
||||
"**/*.log": true,
|
||||
"**/*.log*": true,
|
||||
"**/dist": true,
|
||||
"**/coverage": true
|
||||
},
|
||||
"files.associations": {
|
||||
".markdownlintrc": "jsonc"
|
||||
},
|
||||
|
||||
// ===
|
||||
// Event Triggers
|
||||
// ===
|
||||
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true,
|
||||
"source.fixAll.stylelint": true,
|
||||
"source.fixAll.markdownlint": true
|
||||
},
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"vue",
|
||||
"vue-html",
|
||||
"html"
|
||||
],
|
||||
"vetur.format.enable": false,
|
||||
"vetur.completion.scaffoldSnippetSources": {
|
||||
"user": "🗒️",
|
||||
"workspace": "💼",
|
||||
"vetur": ""
|
||||
},
|
||||
"prettier.disableLanguages": [],
|
||||
|
||||
// ===
|
||||
// HTML
|
||||
// ===
|
||||
|
||||
"html.format.enable": false,
|
||||
"vetur.validation.template": false,
|
||||
"emmet.triggerExpansionOnTab": true,
|
||||
"emmet.includeLanguages": {
|
||||
"vue-html": "html"
|
||||
},
|
||||
"vetur.completion.tagCasing": "initial",
|
||||
|
||||
// ===
|
||||
// JS(ON)
|
||||
// ===
|
||||
|
||||
"jest.autoEnable": false,
|
||||
"jest.enableCodeLens": false,
|
||||
"javascript.format.enable": false,
|
||||
"json.format.enable": false,
|
||||
"vetur.validation.script": false,
|
||||
|
||||
// ===
|
||||
// CSS
|
||||
// ===
|
||||
|
||||
"stylelint.enable": true,
|
||||
"css.validate": false,
|
||||
"scss.validate": false,
|
||||
"vetur.validation.style": false,
|
||||
|
||||
// ===
|
||||
// MARKDOWN
|
||||
// ===
|
||||
|
||||
"[markdown]": {
|
||||
"editor.wordWrap": "wordWrapColumn",
|
||||
"editor.wordWrapColumn": 80
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,9 @@ WORKDIR /app
|
||||
|
||||
# Copy dependency-related files
|
||||
COPY package.json ./
|
||||
COPY yarn.lock ./
|
||||
|
||||
# Install project dependencies
|
||||
RUN yarn install
|
||||
RUN npm install
|
||||
|
||||
# Expose ports 8080, which the dev server will be bound to
|
||||
EXPOSE 8080
|
||||
|
||||
30847
ui/package-lock.json
generated
30847
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
101
ui/package.json
101
ui/package.json
@@ -6,91 +6,80 @@
|
||||
"dev": "vue-cli-service serve",
|
||||
"dev:e2e": "cross-env VUE_APP_TEST=e2e vue-cli-service test:e2e --mode=development",
|
||||
"build": "vue-cli-service build --modern",
|
||||
"build:ci": "yarn build --report",
|
||||
"build:ci": "npm build --report",
|
||||
"lint:eslint": "eslint --fix",
|
||||
"lint:stylelint": "stylelint --fix",
|
||||
"lint:markdownlint": "markdownlint",
|
||||
"lint:prettier": "prettier --write --loglevel warn",
|
||||
"lint:all:eslint": "yarn lint:eslint --ext .js,.vue .",
|
||||
"lint:all:stylelint": "yarn lint:stylelint \"src/**/*.{vue,scss}\"",
|
||||
"lint:all:markdownlint": "yarn lint:markdownlint \"docs/*.md\" \"*.md\"",
|
||||
"lint:all:prettier": "yarn lint:prettier \"**/*.{js,json,css,scss,vue,html,md}\"",
|
||||
"lint": "run-s lint:all:*",
|
||||
"test:unit": "cross-env VUE_APP_TEST=unit vue-cli-service test:unit",
|
||||
"test:unit:file": "yarn test:unit --bail --findRelatedTests",
|
||||
"test:unit:watch": "yarn test:unit --watch --notify --notifyMode change",
|
||||
"test:unit:ci": "yarn test:unit --coverage --ci",
|
||||
"test:e2e": "cross-env VUE_APP_TEST=e2e vue-cli-service test:e2e --headless",
|
||||
"test": "run-s test:unit test:e2e",
|
||||
"test:ci": "run-s test:unit:ci test:e2e",
|
||||
"new": "cross-env HYGEN_TMPLS=generators hygen new",
|
||||
"docs": "vuepress dev",
|
||||
"docker": "docker-compose exec dev yarn"
|
||||
"docs": "vuepress dev"
|
||||
},
|
||||
"gitHooks": {
|
||||
"pre-commit": "cross-env PRE_COMMIT=true lint-staged"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.27",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.12.1",
|
||||
"@fortawesome/vue-fontawesome": "0.1.9",
|
||||
"axios": "^0.27.2",
|
||||
"buefy": "^0.9.7",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.3.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.3.0",
|
||||
"@fortawesome/vue-fontawesome": "^2.0.10",
|
||||
"axios": "^1.3.2",
|
||||
"buefy": "^0.9.22",
|
||||
"chart.js": "^2.9.4",
|
||||
"core-js": "3.6.4",
|
||||
"currency-formatter": "^1.5.7",
|
||||
"date-fns": "2.10.0",
|
||||
"core-js": "^3.27.2",
|
||||
"currency-formatter": "^1.5.9",
|
||||
"date-fns": "^2.29.3",
|
||||
"lodash": "^4.17.21",
|
||||
"node-gyp": "^9.3.1",
|
||||
"normalize.css": "8.0.1",
|
||||
"nprogress": "0.2.0",
|
||||
"vue": "2.6.11",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"papaparse": "^5.4.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-chartjs": "^3.5.1",
|
||||
"vue-i18n": "^8.28.2",
|
||||
"vue-meta": "2.3.3",
|
||||
"vue-router": "3.1.6",
|
||||
"vuex": "3.1.2"
|
||||
"vue-meta": "^2.4.0",
|
||||
"vue-router": "^3.6.5",
|
||||
"vuex": "^3.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "4.2.x",
|
||||
"@vue/cli-plugin-eslint": "4.2.x",
|
||||
"@vue/cli-plugin-unit-jest": "4.2.x",
|
||||
"@vue/cli-service": "4.2.x",
|
||||
"@vue/cli-plugin-babel": "^4.5.19",
|
||||
"@vue/cli-plugin-eslint": "^4.5.19",
|
||||
"@vue/cli-plugin-unit-jest": "^4.5.19",
|
||||
"@vue/cli-service": "^4.5.19",
|
||||
"@vue/eslint-config-prettier": "6.0.x",
|
||||
"@vue/eslint-config-standard": "5.1.x",
|
||||
"@vue/test-utils": "1.0.0-beta.31",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"@vue/eslint-config-standard": "^5.1.1",
|
||||
"@vue/test-utils": "^1.3.4",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"babel-eslint": "10.1.x",
|
||||
"cross-env": "7.0.x",
|
||||
"eslint": "6.8.x",
|
||||
"eslint-plugin-import": "2.20.x",
|
||||
"eslint-plugin-node": "11.0.x",
|
||||
"eslint-plugin-promise": "4.2.x",
|
||||
"eslint-plugin-standard": "4.0.x",
|
||||
"eslint-plugin-vue": "6.2.x",
|
||||
"express": "4.17.x",
|
||||
"hygen": "4.0.x",
|
||||
"imagemin-lint-staged": "0.4.x",
|
||||
"lint-staged": "10.0.x",
|
||||
"markdownlint-cli": "^0.31.1",
|
||||
"npm-run-all": "4.1.x",
|
||||
"sass": "1.26.x",
|
||||
"sass-loader": "8.0.x",
|
||||
"stylelint": "13.2.x",
|
||||
"stylelint-config-css-modules": "2.2.x",
|
||||
"stylelint-config-prettier": "8.0.x",
|
||||
"stylelint-config-recess-order": "2.0.x",
|
||||
"stylelint-config-standard": "20.0.x",
|
||||
"stylelint-scss": "3.14.x",
|
||||
"vue-template-compiler": "2.6.11",
|
||||
"vuepress": "1.3.x"
|
||||
"cross-env": "^7.0.1",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.3.1",
|
||||
"eslint-plugin-standard": "^5.0.0",
|
||||
"eslint-plugin-vue": "^9.9.0",
|
||||
"express": "^4.18.2",
|
||||
"hygen": "^6.2.11",
|
||||
"markdownlint-cli": "^0.33.0",
|
||||
"npm-run-all": "^4.1.1",
|
||||
"sass": "^1.58.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"stylelint": "^14.16.1",
|
||||
"stylelint-config-css-modules": "^4.1.0",
|
||||
"stylelint-config-prettier": "^9.0.4",
|
||||
"stylelint-config-standard": "^29.0.0",
|
||||
"stylelint-scss": "^4.3.0",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vuepress": "^1.9.8"
|
||||
},
|
||||
"resolutions": {
|
||||
"@vue/cli-plugin-unit-jest/jest": "25.1.x",
|
||||
"@vue/cli-plugin-unit-jest/babel-jest": "25.1.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.3",
|
||||
"yarn": ">=1.0.0"
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
<link rel="shortcut icon" href="<%= webpackConfig.output.publicPath %>hammond.png" />
|
||||
<link rel="apple-touch-icon" href="<%= webpackConfig.output.publicPath %>touch-icon.png" />
|
||||
<title><%= webpackConfig.name %></title>
|
||||
<!-- Temporary until fontawesome 6 is supported in buefy (see issue: https://github.com/FortAwesome/Font-Awesome/issues/18663) -->
|
||||
<style>
|
||||
.icon svg { width: 1em; height: 1em; max-width: 80%; max-height: 80%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- This is where our app will be mounted. -->
|
||||
|
||||
@@ -95,11 +95,10 @@ export default {
|
||||
</div>
|
||||
<div class="column">
|
||||
<b-button
|
||||
tag="input"
|
||||
tag="button"
|
||||
native-type="submit"
|
||||
:disabled="tryingToCreate"
|
||||
type="is-primary"
|
||||
:value="this.$t('uploadfile')"
|
||||
class="control"
|
||||
>
|
||||
{{ $t('uploadfile') }}
|
||||
|
||||
@@ -3,9 +3,20 @@ import { Line } from 'vue-chartjs'
|
||||
|
||||
import axios from 'axios'
|
||||
import { mapState } from 'vuex'
|
||||
import { string } from 'yargs'
|
||||
export default {
|
||||
extends: Line,
|
||||
props: { vehicle: { type: Object, required: true }, since: { type: Date, default: '' }, user: { type: Object, required: true } },
|
||||
props: {
|
||||
vehicle: { type: Object, required: true },
|
||||
since: { type: Date, default: '' },
|
||||
user: { type: Object, required: true },
|
||||
mileageOption: { type: string, default: 'litre_100km' },
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
chartData: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('utils', ['isMobile']),
|
||||
},
|
||||
@@ -17,20 +28,28 @@ export default {
|
||||
this.fetchMileage()
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
chartData: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchMileage()
|
||||
},
|
||||
methods: {
|
||||
showChart() {
|
||||
let mileageLabel = ''
|
||||
switch (this.mileageOption) {
|
||||
case 'litre_100km':
|
||||
mileageLabel = 'L/100km'
|
||||
break
|
||||
case 'km_litre':
|
||||
mileageLabel = 'km/L'
|
||||
break
|
||||
case 'mpg':
|
||||
mileageLabel = 'mpg'
|
||||
break
|
||||
}
|
||||
|
||||
var labels = this.chartData.map((x) => x.date.substr(0, 10))
|
||||
var dataset = {
|
||||
steppedLine: true,
|
||||
label: `${this.$t('odometer')} (${this.$t('unit.short.' + this.user.distanceUnitDetail.key)}/${this.$t('unit.short.' + this.vehicle.fuelUnitDetail.key)})`,
|
||||
label: `Mileage (${mileageLabel})`,
|
||||
fill: true,
|
||||
data: this.chartData.map((x) => x.mileage),
|
||||
}
|
||||
@@ -41,6 +60,7 @@ export default {
|
||||
.get(`/api/vehicles/${this.vehicle.id}/mileage`, {
|
||||
params: {
|
||||
since: this.since,
|
||||
mileageOption: this.mileageOption,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
|
||||
@@ -50,7 +50,7 @@ export default {
|
||||
<b-select
|
||||
v-if="unprocessedQuickEntries.length"
|
||||
v-model="quickEntry"
|
||||
:placeholder="this.$t('referquickentry')"
|
||||
:placeholder="$t('referquickentry')"
|
||||
expanded
|
||||
@input="showQuickEntry($event)"
|
||||
>
|
||||
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
<div class="box" style="max-width:600px">
|
||||
<h1 class="subtitle">{{ $t('share') }} {{ vehicle.nickname }}</h1>
|
||||
<section>
|
||||
<div class="columns is-mobile" v-for="model in models" :key="model.id">
|
||||
<div v-for="model in models" :key="model.id" class="columns is-mobile">
|
||||
<div class="column is-one-third">
|
||||
<b-field>
|
||||
<b-switch v-model="model.isShared" :disabled="model.isOwner" @input="changeShareStatus(model)">
|
||||
|
||||
@@ -10,10 +10,10 @@ $size-input-padding-vertical: 0.75em;
|
||||
$size-input-padding-horizontal: 1em;
|
||||
$size-input-padding: $size-input-padding-vertical $size-input-padding-horizontal;
|
||||
$size-input-border: 1px;
|
||||
$size-input-border-radius: (1em + $size-input-padding-vertical * 2) / 10;
|
||||
$size-input-border-radius: calc((1em + $size-input-padding-vertical * 2) / 10);
|
||||
|
||||
// BUTTONS
|
||||
$size-button-padding-vertical: $size-grid-padding / 2;
|
||||
$size-button-padding-horizontal: $size-grid-padding / 1.5;
|
||||
$size-button-padding-vertical: calc($size-grid-padding / 2);
|
||||
$size-button-padding-horizontal: calc($size-grid-padding / 1.5);
|
||||
$size-button-padding: $size-button-padding-vertical
|
||||
$size-button-padding-horizontal;
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
$max-screen,
|
||||
$max-value
|
||||
) {
|
||||
$a: ($max-value - $min-value) / ($max-screen - $min-screen);
|
||||
$a: calc(($max-value - $min-value) / ($max-screen - $min-screen));
|
||||
$b: $min-value - $a * $min-screen;
|
||||
|
||||
$sign: '+';
|
||||
|
||||
231
ui/src/locales/da.json
Normal file
231
ui/src/locales/da.json
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"quickentry": "Ingen hurtige indtastninger | Hurtig indtastning | Hurtige indtastninger",
|
||||
"statistics": "Statistik",
|
||||
"thisweek": "Denne uge",
|
||||
"thismonth": "Denne måned",
|
||||
"pastxdays": "Forrige en dag | Forrige {count} dage",
|
||||
"pastxmonths": "Forrige en måned | Forrige {count} måneder",
|
||||
"thisyear": "Dette år",
|
||||
"alltime": "Hele tiden",
|
||||
"noattachments": "Ingen vedhæftede filer indtil videre",
|
||||
"attachments": "Vedhæftede filer",
|
||||
"choosefile": "Vælg fil",
|
||||
"addattachment": "Tilføj vedhæftning",
|
||||
"sharedwith": "Delt med",
|
||||
"share": "Del",
|
||||
"you": "Du",
|
||||
"addfillup": "Tilføj påfyldning",
|
||||
"createfillup": "Opret påfyldning",
|
||||
"deletefillup": "Slet denne påfyldning",
|
||||
"addexpense": "Tilføj udgift",
|
||||
"createexpense": "Opret udgift",
|
||||
"deleteexpense": "Slet denne udgift",
|
||||
"nofillups": "Ingen påfyldninger indtil videre",
|
||||
"transfervehicle": "Overfør køretøj",
|
||||
"settingssaved": "Indstillingerne er gemt",
|
||||
"yoursettings": "Dine indstillinger",
|
||||
"settings": "Indstillinger",
|
||||
"changepassword": "Skift adgangskode",
|
||||
"oldpassword": "Gammel adgangskode",
|
||||
"newpassword": "Ny adgangskode",
|
||||
"repeatnewpassword": "Gentag ny adgangskode",
|
||||
"passworddontmatch": "Adgangskoderne stemmer ikke overens",
|
||||
"save": "Gem",
|
||||
"supportthedeveloper": "Støt udvikleren",
|
||||
"buyhimabeer": "Køb ham en øl!",
|
||||
"featurerequest": "Ønske om funktion",
|
||||
"foundabug": "Fundet en fejl",
|
||||
"currentversion": "Nuværende version",
|
||||
"moreinfo": "Mere info",
|
||||
"currency": "Valuta",
|
||||
"distanceunit": "Afstandsenhed",
|
||||
"dateformat": "Datoformat",
|
||||
"createnow": "Opret nu",
|
||||
"yourvehicles": "Dine køretøjer",
|
||||
"menu": {
|
||||
"quickentries": "Hurtige indtastninger",
|
||||
"logout": "Log ud",
|
||||
"import": "Import",
|
||||
"home": "Hjem",
|
||||
"settings": "Indstillinger",
|
||||
"admin": "Admin",
|
||||
"sitesettings": "Webstedsindstillinger",
|
||||
"users": "Brugere",
|
||||
"login": "Log ind"
|
||||
},
|
||||
"enterusername": "Indtast dit brugernavn",
|
||||
"enterpassword": "Indtast din adgangskode",
|
||||
"email": "E-mail",
|
||||
"password": "Adgangskode",
|
||||
"login": "Log ind",
|
||||
"totalexpenses": "Samlede udgifter",
|
||||
"fillupcost": "Tankningsomkostninger",
|
||||
"otherexpenses": "Andre udgifter",
|
||||
"addvehicle": "Tilføj køretøj",
|
||||
"editvehicle": "Rediger køretøj",
|
||||
"deletevehicle": "Slet køretøj",
|
||||
"sharevehicle": "Del køretøj",
|
||||
"makeowner": "Gør til ejer",
|
||||
"lastfillup": "Seneste tankning",
|
||||
"quickentrydesc": "Tag et billede af fakturaen eller brændstofpumpens display for at foretage en indtastning senere.",
|
||||
"quickentrycreatedsuccessfully": "Hurtig indtastning oprettet med succes",
|
||||
"uploadfile": "Upload fil",
|
||||
"uploadphoto": "Upload foto",
|
||||
"details": "Detaljer",
|
||||
"odometer": "Kilometertæller",
|
||||
"language": "Sprog",
|
||||
"date": "Dato",
|
||||
"pastfillups": "Tidligere tankninger",
|
||||
"fuelsubtype": "Brændstoftype",
|
||||
"fueltype": "Brændstoftype",
|
||||
"quantity": "Mængde",
|
||||
"gasstation": "Tankstation",
|
||||
"fuel": {
|
||||
"petrol": "Benzin",
|
||||
"diesel": "Diesel",
|
||||
"cng": "CNG",
|
||||
"lpg": "LPG",
|
||||
"electric": "Elektrisk",
|
||||
"ethanol": "Ethanol"
|
||||
},
|
||||
"unit": {
|
||||
"long": {
|
||||
"litre": "Liter",
|
||||
"gallon": "Gallon",
|
||||
"kilowatthour": "Kilowatt-time",
|
||||
"kilogram": "Kilogram",
|
||||
"usgallon": "US Gallon",
|
||||
"minutes": "Minutter",
|
||||
"kilometers": "Kilometer",
|
||||
"miles": "Miles"
|
||||
},
|
||||
"short": {
|
||||
"litre": "L",
|
||||
"gallon": "Gal",
|
||||
"kilowatthour": "KwH",
|
||||
"kilogram": "Kg",
|
||||
"usgallon": "US Gal",
|
||||
"minutes": "Min",
|
||||
"kilometers": "Km",
|
||||
"miles": "Mi"
|
||||
}
|
||||
},
|
||||
"avgfillupqty": "Gns. påfyldningsmængde",
|
||||
"avgfillupexpense": "Gns. påfyldningsudgift",
|
||||
"avgfuelcost": "Gns. brændstofpris",
|
||||
"per": "{0} per {1}",
|
||||
"price": "Pris",
|
||||
"total": "Total",
|
||||
"fulltank": "Tank fuld",
|
||||
"partialfillup": "Delvis påfyldning",
|
||||
"getafulltank": "Fik du en fuld tank?",
|
||||
"tankpartialfull": "Hvad sporer du?",
|
||||
"by": "Ved",
|
||||
"expenses": "Udgifter",
|
||||
"expensetype": "Udgiftstype",
|
||||
"noexpenses": "Ingen udgifter indtil videre",
|
||||
"download": "Download",
|
||||
"title": "Titel",
|
||||
"name": "Navn",
|
||||
"delete": "Slet",
|
||||
"importdata": "Importer data til Hammond",
|
||||
"importdatadesc": "Vælg en af følgende muligheder for at importere data til Hammond",
|
||||
"import": "Importer",
|
||||
"importcsv": "Hvis du har brugt {name} til at gemme dine køretøjsdata, skal du eksportere CSV-filen fra {name} og klikke her for at importere.",
|
||||
"importgeneric": "Generisk påfyldningsimport",
|
||||
"importgenericdesc": "CSV-import af påfyldninger.",
|
||||
"choosecsv": "Vælg CSV",
|
||||
"choosephoto": "Vælg foto",
|
||||
"importsuccessfull": "Data importeret med succes",
|
||||
"importerror": "Der opstod et problem med at importere filen. Kontrollér fejlmeddelelsen",
|
||||
"importfrom": "Importer fra {0}",
|
||||
"stepstoimport": "Trin til import af data fra {name}",
|
||||
"choosecsvimport": "Vælg {name} CSV-filen og klik på importknappen.",
|
||||
"choosedatafile": "Vælg CSV-filen og klik derefter på importknappen.",
|
||||
"dontimportagain": "Sørg for ikke at importere filen igen, da det vil skabe gentagne indtastninger.",
|
||||
"checkpointsimportcsv": "Når du har kontrolleret alle disse punkter, kan du blot importere CSV'en nedenfor.",
|
||||
"importhintunits": "På samme måde skal du sørge for, at <u>Brændstofenhed</u> og <u>Brændstoftype</u> er korrekt indstillet for køretøjet.",
|
||||
"importhintcurrdist": "Sørg for, at <u>Valuta</u> og <u>Afstandsenhed</u> er korrekt indstillet i Hammond. Importen vil ikke automatisk registrere valutaen fra filen, men bruge den valuta, der er indstillet for brugeren.",
|
||||
"importhintnickname": "Sørg for, at køretøjets kaldenavn i Hammond er præcis det samme som navnet i Fuelly CSV-filen, ellers vil importen ikke fungere.",
|
||||
"importhintvehiclecreated": "Sørg for, at du allerede har oprettet køretøjerne i Hammond-platformen.",
|
||||
"importhintcreatecsv": "Eksportér dine data fra {name} i CSV-format. Instruktioner til at gøre dette kan findes",
|
||||
"importgenerichintdata": "Data skal være i CSV-format.",
|
||||
"here": "her",
|
||||
"unprocessedquickentries": "Du har en hurtig indtastning, der skal behandles. | Du har {0} hurtige indtastninger, der venter på at blive behandlet.",
|
||||
"show": "Vis",
|
||||
"loginerror": "Der opstod en fejl ved login til din konto. {msg}",
|
||||
"showunprocessed": "Vis kun ubehandlede",
|
||||
"unprocessed": "ubehandlede",
|
||||
"sitesettingdesc": "Opdater indstillinger på webstedsniveau. Disse vil blive brugt som standardværdier for nye brugere.",
|
||||
"settingdesc": "Disse vil blive brugt som standardværdier, når du opretter en ny påfyldning eller udgift.",
|
||||
"areyousure": "Er du sikker på, at du vil fortsætte med dette?",
|
||||
"adduser": "Tilføj bruger",
|
||||
"usercreatedsuccessfully": "Bruger oprettet med succes",
|
||||
"userdisabledsuccessfully": "Bruger deaktiveret med succes",
|
||||
"userenabledsuccessfully": "Bruger aktiveret med succes",
|
||||
"role": "Rolle",
|
||||
"created": "Oprettet",
|
||||
"createnewuser": "Opret ny bruger",
|
||||
"cancel": "Annuller",
|
||||
"novehicles": "Det ser ud til, at du endnu ikke har oprettet et køretøj i systemet. Begynd med at oprette en indtastning for et af de køretøjer, du gerne vil spore.",
|
||||
"processed": "Marker som behandlet",
|
||||
"notfound": "Ikke fundet",
|
||||
"timeout": "Siden fik en timeout under indlæsningen. Er du stadig forbundet til internettet?",
|
||||
"clicktoselect": "Klik for at vælge...",
|
||||
"expenseby": "Udgift af",
|
||||
"selectvehicle": "Vælg et køretøj",
|
||||
"expensedate": "Udgiftsdato",
|
||||
"totalamountpaid": "Samlet betalt beløb",
|
||||
"fillmoredetails": "Udfyld flere oplysninger",
|
||||
"markquickentryprocessed": "Marker valgt hurtig indtastning som behandlet",
|
||||
"referquickentry": "Henvis hurtig indtastning",
|
||||
"deletequickentry": "Dette vil slette denne hurtige indtastning. Dette trin kan ikke fortrydes. Er du sikker?",
|
||||
"fuelunit": "Brændstofenhed",
|
||||
"fillingstation": "Navn på tankstation",
|
||||
"comments": "Kommentarer",
|
||||
"missfillupbefore": "Glemte du at indtaste påfyldningen før denne?",
|
||||
"missedfillup": "Glemt påfyldning",
|
||||
"fillupdate": "Påfyldningsdato",
|
||||
"fillupsavedsuccessfully": "Påfyldning gemt med succes",
|
||||
"expensesavedsuccessfully": "Udgift gemt med succes",
|
||||
"vehiclesavedsuccessfully": "Køretøj gemt med succes",
|
||||
"settingssavedsuccessfully": "Indstillinger gemt med succes",
|
||||
"back": "Tilbage",
|
||||
"nickname": "Kælenavn",
|
||||
"registration": "Registrering",
|
||||
"createvehicle": "Opret køretøj",
|
||||
"make": "Mærke / Firma",
|
||||
"model": "Model",
|
||||
"yearmanufacture": "Produktionsår",
|
||||
"enginesize": "Motorsize (i cc)",
|
||||
"mysqlconnstr": "MySQL-forbindelsesstreng",
|
||||
"testconn": "Test forbindelse",
|
||||
"migrate": "Migrer",
|
||||
"init": {
|
||||
"migrateclarkson": "Migrer fra Clarkson",
|
||||
"migrateclarksondesc": "Hvis du har en eksisterende Clarkson-installation, og du vil migrere dine data fra den, skal du trykke på følgende knap.",
|
||||
"freshinstall": "Ny installation",
|
||||
"freshinstalldesc": "Hvis du vil have en ny installation af Hammond, skal du trykke på følgende knap.",
|
||||
"clarkson": {
|
||||
"desc": "<p>Du skal sørge for, at denne installation af Hammond kan få adgang til MySQL-databasen, der bruges af Clarkson.</p><p>Hvis det ikke er direkte muligt, kan du lave en kopi af den database et sted, der er tilgængeligt fra denne instans.</p><p>Når det er gjort, skal du indtaste forbindelsesstrengen til MySQL-instansen i følgende format.</p><p>Alle brugerne importeret fra Clarkson vil have deres brugernavn som deres e-mail i Clarkson-databasen, og adgangskoden er indstillet til<span class='' style='font-weight:bold'>hammond</span></p><code>bruger:adgangskode@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local</code><br/><br/>",
|
||||
"success": "Vi har migreret dataene fra Clarkson med succes. Du vil snart blive omdirigeret til login-siden, hvor du kan logge ind med din eksisterende e-mail og adgangskode: hammond"
|
||||
},
|
||||
"fresh": {
|
||||
"setupadminuser": "Opsætning af administratorbrugere",
|
||||
"yourpassword": "Din adgangskode",
|
||||
"youremail": "Din e-mail",
|
||||
"yourname": "Dit navn",
|
||||
"success": "Du er blevet registreret med succes. Du vil snart blive omdirigeret til login-siden, hvor du kan logge ind og begynde at bruge systemet."
|
||||
}
|
||||
},
|
||||
"roles": {
|
||||
"ADMIN": "ADMIN",
|
||||
"USER": "BRUGER"
|
||||
},
|
||||
"profile": "Profil",
|
||||
"processedon": "Behandlet den",
|
||||
"enable": "Aktivér",
|
||||
"disable": "Deaktiver",
|
||||
"confirm": "Fortsæt",
|
||||
"labelforfile": "Mærke for denne fil"
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
"addattachment": "Anhang hinzufügen",
|
||||
"sharedwith": "Geteilt mit",
|
||||
"share": "Teile",
|
||||
"you": "Sie",
|
||||
"you": "du",
|
||||
"addfillup": "Tankfüllung erfassen",
|
||||
"createfillup": "Erfasse Tankfüllung",
|
||||
"deletefillup": "Lösche diese Tankfüllung",
|
||||
@@ -28,7 +28,7 @@
|
||||
"changepassword": "Passwort ändern",
|
||||
"oldpassword": "Bisheriges Passwort",
|
||||
"newpassword": "Neues Passwort",
|
||||
"repeatnewpassword": "Neues Passwort wiederhiolen",
|
||||
"repeatnewpassword": "Neues Passwort wiederholen",
|
||||
"passworddontmatch": "Passwörter stimmen nicht überein",
|
||||
"save": "Speichern",
|
||||
"supportthedeveloper": "Unterstütze den Entwickler",
|
||||
@@ -56,7 +56,7 @@
|
||||
"password": "Passwort",
|
||||
"login": "Anmelden",
|
||||
"totalexpenses": "Gesamtausgaben",
|
||||
"fillupcost": "Tank Ausgaben",
|
||||
"fillupcost": "Tank-Ausgaben",
|
||||
"otherexpenses": "Andere Ausgaben",
|
||||
"addvehicle": "Fahrzeug hinzufügen",
|
||||
"editvehicle": "Fahrzeug bearbeiten",
|
||||
@@ -124,20 +124,20 @@
|
||||
"name": "Name",
|
||||
"delete": "Löschen",
|
||||
"importdata": "Importiere Daten in Hammond",
|
||||
"importdatadesc": "Wähle eine der folgenden Optionen um Daten in Hammond zu importieren",
|
||||
"importdatadesc": "Wähle eine der folgenden Optionen, um Daten in Hammond zu importieren",
|
||||
"import": "Importieren",
|
||||
"importcsv": "Wenn du {name} nutzt um deine Fahrzeugdaten zu verwalten, exportiere die CSV Datei aus {name} und klicke hier zum importieren.",
|
||||
"importcsv": "Wenn du {name} nutzt, um deine Fahrzeugdaten zu verwalten, exportiere die CSV Datei aus {name} und klicke hier, um zu importieren.",
|
||||
"choosecsv": "CSV auswählen",
|
||||
"choosephoto": "Foto auswählen",
|
||||
"importsuccessfull": "Daten erfolgreich importiert",
|
||||
"importerror": "Beim importieren der Datei ist ein Fehler aufgetreten. Details findest du in der Fehlermeldung",
|
||||
"importerror": "Beim Importieren der Datei ist ein Fehler aufgetreten. Details findest du in der Fehlermeldung",
|
||||
"importfrom": "Importiere von {name}",
|
||||
"stepstoimport": "Schritte um Daten aus {name} zu importieren",
|
||||
"choosecsvimport": "Wähle die {name} CSV aus und klicke den Button zum importieren.",
|
||||
"dontimportagain": "Achte darauf, dass du die Datei nicht erneut importierst, da dies zu wiederholten Einträgen führen würde.",
|
||||
"stepstoimport": "Schritte, um Daten aus {name} zu importieren",
|
||||
"choosecsvimport": "Wähle die {name} CSV aus und klicke den Button, um zu importieren.",
|
||||
"dontimportagain": "Achte darauf, dass du die Datei nicht erneut importierst, da dies zu mehrfachen Einträgen führen würde.",
|
||||
"checkpointsimportcsv": "Wenn du alle diese Punkte überprüft hast kannst du unten die CSV importieren.",
|
||||
"importhintunits": "Vergewissere dich ebenfalls, dass die <u>Kraftstoffeinheit</u> und der <u>Kraftstofftyp</u> im Fahrzeug richtig eingestellt sind.",
|
||||
"importhintcurrdist": "Stelle sicher, dass die <u>Währung</u> und die <u>Entfernungseinheit</u> in Hammond korrekt eingestellt sind. Der Import erkennt die Währung nicht automatisch aus der CSV-Datei, sondern verwendet die für den Benutzer eingestellte Währung.",
|
||||
"importhintcurrdist": "Stelle sicher, dass die <u>Währung</u> und die <u>Entfernungseinheit</u> in Hammond korrekt eingestellt sind. Der Import erkennt die Währung nicht automatisch aus der datei, sondern verwendet die für den Benutzer eingestellte Währung.",
|
||||
"importhintnickname": "Vergewissere dich, dass der Fahrzeugname in Hammond genau mit dem Namen in der Fuelly-CSV-Datei übereinstimmt, sonst funktioniert der Import nicht.",
|
||||
"importhintvehiclecreated": "Vergewissere dich, dass du die Fahrzeuge bereits in Hammond erstellt hast.",
|
||||
"importhintcreatecsv": "Exportiere deine Daten aus {name} im CSV-Format. Die Schritte dazu findest du",
|
||||
@@ -156,11 +156,11 @@
|
||||
"created": "Erstellt",
|
||||
"createnewuser": "Erstelle neuen Benutzer",
|
||||
"cancel": "Abbrechen",
|
||||
"novehicles": "Du hast noch kein Fahrzeug erstellt. Lege jetzt einen Eintrag für das zu Verwaltende Auto an.",
|
||||
"novehicles": "Du hast noch kein Fahrzeug erstellt. Lege jetzt einen Eintrag für das zu verwaltende Fahrzeug an.",
|
||||
"processed": "Bearbeitet",
|
||||
"notfound": "Nicht gefunden",
|
||||
"timeout": "Das Laden der Seite hat eine Zeitüberschreitung verursacht. Bist du sicher, dass du noch mit dem Internet verbunden bist?",
|
||||
"clicktoselect": "Klicke zum auswählen...",
|
||||
"clicktoselect": "Klicke, um auszuwählen...",
|
||||
"expenseby": "Ausgabe von",
|
||||
"selectvehicle": "Wähle ein Fahrzeug aus",
|
||||
"expensedate": "Datum der Ausgabe",
|
||||
@@ -168,11 +168,11 @@
|
||||
"fillmoredetails": "Weitere Details ausfüllen",
|
||||
"markquickentryprocessed": "Markiere gewählten Schnelleintrag als bearbeitet",
|
||||
"referquickentry": "Wähle Schnelleintrag",
|
||||
"deletequickentry": "Willst du diesen Schnelleintrag wirklcih Löschen? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"deletequickentry": "Willst du diesen Schnelleintrag wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden!",
|
||||
"fuelunit": "Kraftstoffeinheit",
|
||||
"fillingstation": "Tankstelle",
|
||||
"comments": "Kommentare",
|
||||
"missfillupbefore": "Hast du vergessen die vorherige Tankfüllung zu erfassen?",
|
||||
"missfillupbefore": "Hast du vergessen, die vorherige Tankfüllung zu erfassen?",
|
||||
"fillupdate": "Tankdatum",
|
||||
"fillupsavedsuccessfully": "Tankfüllung erfolgreich gespeichert",
|
||||
"expensesavedsuccessfully": "Ausgabe erfolgreich gespeichert",
|
||||
@@ -184,7 +184,7 @@
|
||||
"make": "Marke",
|
||||
"model": "Modell",
|
||||
"yearmanufacture": "Jahr der Erstzulassung",
|
||||
"enginesize": "Hubraum (in cc)",
|
||||
"enginesize": "Hubraum (in ccm)",
|
||||
"testconn": "Teste Verbindung",
|
||||
"migrate": "Migrieren",
|
||||
"init": {
|
||||
@@ -199,7 +199,7 @@
|
||||
"fresh": {
|
||||
"setupadminuser": "Erstelle einen Administrator",
|
||||
"yourpassword": "Dein Passwort",
|
||||
"youremail": "Deine E-Mail Adresse",
|
||||
"youremail": "Deine E-Mail-Adresse",
|
||||
"yourname": "Dein Name",
|
||||
"success": "Du hast dich erfolgreich registriert. Du wirst in kürze zur Anmeldung weitergeleitet und kannst Anfangen Hammond zu verwenden."
|
||||
}
|
||||
@@ -214,4 +214,4 @@
|
||||
"disable": "Sperren",
|
||||
"confirm": "Bestätigen",
|
||||
"labelforfile": "Bezeichnung für diese Datei"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"thismonth": "This month",
|
||||
"pastxdays": "Past one day | Past {count} days",
|
||||
"pastxmonths": "Past one month | Past {count} months",
|
||||
"thisyear": "This year",
|
||||
"thisyear": "This year",
|
||||
"alltime": "All Time",
|
||||
"noattachments": "No Attachments so far",
|
||||
"attachments": "Attachments",
|
||||
@@ -43,15 +43,15 @@
|
||||
"createnow": "Create Now",
|
||||
"yourvehicles": "Your Vehicles",
|
||||
"menu": {
|
||||
"quickentries": "Quick Entries",
|
||||
"logout": "Log out",
|
||||
"import": "Import",
|
||||
"home": "Home",
|
||||
"settings": "Settings",
|
||||
"admin": "Admin",
|
||||
"sitesettings": "Site Settings",
|
||||
"users": "Users",
|
||||
"login": "Log in"
|
||||
"quickentries": "Quick Entries",
|
||||
"logout": "Log out",
|
||||
"import": "Import",
|
||||
"home": "Home",
|
||||
"settings": "Settings",
|
||||
"admin": "Admin",
|
||||
"sitesettings": "Site Settings",
|
||||
"users": "Users",
|
||||
"login": "Log in"
|
||||
},
|
||||
"enterusername": "Enter your username",
|
||||
"enterpassword": "Enter your password",
|
||||
@@ -81,34 +81,34 @@
|
||||
"quantity": "Quantity",
|
||||
"gasstation": "Gas Station",
|
||||
"fuel": {
|
||||
"petrol": "Petrol",
|
||||
"diesel": "Diesel",
|
||||
"cng": "CNG",
|
||||
"lpg": "LPG",
|
||||
"electric": "Electric",
|
||||
"ethanol": "Ethanol"
|
||||
"petrol": "Petrol",
|
||||
"diesel": "Diesel",
|
||||
"cng": "CNG",
|
||||
"lpg": "LPG",
|
||||
"electric": "Electric",
|
||||
"ethanol": "Ethanol"
|
||||
},
|
||||
"unit": {
|
||||
"long": {
|
||||
"litre": "Litre",
|
||||
"gallon": "Gallon",
|
||||
"kilowatthour": "Kilowatt Hour",
|
||||
"kilogram": "Kilogram",
|
||||
"usgallon": "US Gallon",
|
||||
"minutes": "Minutes",
|
||||
"kilometers": "Kilometers",
|
||||
"miles": "Miles"
|
||||
},
|
||||
"short": {
|
||||
"litre": "Lt",
|
||||
"gallon": "Gal",
|
||||
"kilowatthour": "KwH",
|
||||
"kilogram": "Kg",
|
||||
"usgallon": "US Gal",
|
||||
"minutes": "Mins",
|
||||
"kilometers": "Km",
|
||||
"miles": "Mi"
|
||||
}
|
||||
"long": {
|
||||
"litre": "Litre",
|
||||
"gallon": "Gallon",
|
||||
"kilowatthour": "Kilowatt Hour",
|
||||
"kilogram": "Kilogram",
|
||||
"usgallon": "US Gallon",
|
||||
"minutes": "Minutes",
|
||||
"kilometers": "Kilometers",
|
||||
"miles": "Miles"
|
||||
},
|
||||
"short": {
|
||||
"litre": "Lt",
|
||||
"gallon": "Gal",
|
||||
"kilowatthour": "KwH",
|
||||
"kilogram": "Kg",
|
||||
"usgallon": "US Gal",
|
||||
"minutes": "Mins",
|
||||
"kilometers": "Km",
|
||||
"miles": "Mi"
|
||||
}
|
||||
},
|
||||
"avgfillupqty": "Avg Fillup Qty",
|
||||
"avgfillupexpense": "Avg Fillup Expense",
|
||||
@@ -117,7 +117,9 @@
|
||||
"price": "Price",
|
||||
"total": "Total",
|
||||
"fulltank": "Tank Full",
|
||||
"partialfillup": "Partial Fillup",
|
||||
"getafulltank": "Did you get a full tank?",
|
||||
"tankpartialfull": "Which do you track?",
|
||||
"by": "By",
|
||||
"expenses": "Expenses",
|
||||
"expensetype": "Expense Type",
|
||||
@@ -130,6 +132,8 @@
|
||||
"importdatadesc": "Choose from the following options to import data into Hammond",
|
||||
"import": "Import",
|
||||
"importcsv": "If you have been using {name} to store your vehicle data, export the CSV file from {name} and click here to import.",
|
||||
"importgeneric": "Generic Fillups Import",
|
||||
"importgenericdesc": "Fillups CSV import.",
|
||||
"choosecsv": "Choose CSV",
|
||||
"choosephoto": "Choose Photo",
|
||||
"importsuccessfull": "Data Imported Successfully",
|
||||
@@ -137,13 +141,15 @@
|
||||
"importfrom": "Import from {0}",
|
||||
"stepstoimport": "Steps to import data from {name}",
|
||||
"choosecsvimport": "Choose the {name} CSV and press the import button.",
|
||||
"choosedatafile": "Choose the CSV file and then press the import button.",
|
||||
"dontimportagain": "Make sure that you do not import the file again because that will create repeat entries.",
|
||||
"checkpointsimportcsv": "Once you have checked all these points, just import the CSV below.",
|
||||
"importhintunits": "Similiarly, make sure that the <u>Fuel Unit</u> and <u>Fuel Type</u> are correctly set in the Vehicle.",
|
||||
"importhintcurrdist": "Make sure that the <u>Currency</u> and <u>Distance Unit</u> are set correctly in Hammond. Import will not autodetect Currency from the CSV but use the one set for the user.",
|
||||
"importhintcurrdist": "Make sure that the <u>Currency</u> and <u>Distance Unit</u> are set correctly in Hammond. Import will not autodetect Currency from the file but use the one set for the user.",
|
||||
"importhintnickname": "Make sure that the Vehicle nickname in Hammond is exactly the same as the name on Fuelly CSV or the import will not work.",
|
||||
"importhintvehiclecreated": "Make sure that you have already created the vehicles in Hammond platform.",
|
||||
"importhintcreatecsv": "Export your data from {name} in the CSV format. Steps to do that can be found",
|
||||
"importgenerichintdata": "Data must be in CSV format.",
|
||||
"here": "here",
|
||||
"unprocessedquickentries": "You have one quick entry to be processed. | You have {0} quick entries pending to be processed.",
|
||||
"show": "Show",
|
||||
@@ -178,6 +184,7 @@
|
||||
"fillingstation": "Filling Station Name",
|
||||
"comments": "Comments",
|
||||
"missfillupbefore": "Did you miss the fillup entry before this one?",
|
||||
"missedfillup": "Missed Fillup",
|
||||
"fillupdate": "Fillup Date",
|
||||
"fillupsavedsuccessfully": "Fillup Saved Successfully",
|
||||
"expensesavedsuccessfully": "Expense Saved Successfully",
|
||||
@@ -195,25 +202,25 @@
|
||||
"testconn": "Test Connection",
|
||||
"migrate": "Migrate",
|
||||
"init": {
|
||||
"migrateclarkson": "Migrate from Clarkson",
|
||||
"migrateclarksondesc": "If you have an existing Clarkson deployment and you want to migrate your data from that, press the following button.",
|
||||
"freshinstall": "Fresh Install",
|
||||
"freshinstalldesc": "If you want a fresh install of Hammond, press the following button.",
|
||||
"clarkson": {
|
||||
"desc": "<p>You need to make sure that this deployment of Hammond can access the MySQL database used by Clarkson.</p><p>If that is not directly possible, you can make a copy of that database somewhere accessible from this instance.</p><p>Once that is done, enter the connection string to the MySQL instance in the following format.</p><p>All the users imported from Clarkson will have their username as their email in Clarkson database and pasword set to<span class='' style='font-weight:bold'>hammond</span></p><code>user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local</code><br/><br/>",
|
||||
"success": "We have successfully migrated the data from Clarkson. You will be redirected to the login screen shortly where you can login using your existing email and password : hammond"
|
||||
},
|
||||
"fresh": {
|
||||
"setupadminuser": "Setup Admin Users",
|
||||
"yourpassword": "Your Password",
|
||||
"youremail": "Your Email",
|
||||
"yourname": "Your Name",
|
||||
"success": "You have been registered successfully. You will be redirected to the login screen shortly where you can login and start using the system."
|
||||
}
|
||||
"migrateclarkson": "Migrate from Clarkson",
|
||||
"migrateclarksondesc": "If you have an existing Clarkson deployment and you want to migrate your data from that, press the following button.",
|
||||
"freshinstall": "Fresh Install",
|
||||
"freshinstalldesc": "If you want a fresh install of Hammond, press the following button.",
|
||||
"clarkson": {
|
||||
"desc": "<p>You need to make sure that this deployment of Hammond can access the MySQL database used by Clarkson.</p><p>If that is not directly possible, you can make a copy of that database somewhere accessible from this instance.</p><p>Once that is done, enter the connection string to the MySQL instance in the following format.</p><p>All the users imported from Clarkson will have their username as their email in Clarkson database and pasword set to<span class='' style='font-weight:bold'>hammond</span></p><code>user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local</code><br/><br/>",
|
||||
"success": "We have successfully migrated the data from Clarkson. You will be redirected to the login screen shortly where you can login using your existing email and password : hammond"
|
||||
},
|
||||
"fresh": {
|
||||
"setupadminuser": "Setup Admin Users",
|
||||
"yourpassword": "Your Password",
|
||||
"youremail": "Your Email",
|
||||
"yourname": "Your Name",
|
||||
"success": "You have been registered successfully. You will be redirected to the login screen shortly where you can login and start using the system."
|
||||
}
|
||||
},
|
||||
"roles": {
|
||||
"ADMIN": "ADMIN",
|
||||
"USER": "USER"
|
||||
"ADMIN": "ADMIN",
|
||||
"USER": "USER"
|
||||
},
|
||||
"profile": "Profile",
|
||||
"processedon": "Processed on",
|
||||
@@ -221,4 +228,4 @@
|
||||
"disable": "Disable",
|
||||
"confirm": "Go Ahead",
|
||||
"labelforfile": "Label for this file"
|
||||
}
|
||||
}
|
||||
231
ui/src/locales/fr.json
Normal file
231
ui/src/locales/fr.json
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"quickentry": "Pas d'entrée rapide | Entrée rapide | Entrées rapides",
|
||||
"statistics": "Statistiques",
|
||||
"thisweek": "Cette semaine",
|
||||
"thismonth": "Ce mois",
|
||||
"pastxdays": "Dernier jour | Derniers {count} jours",
|
||||
"pastxmonths": "Dernier mois | Derniers {count} mois",
|
||||
"thisyear": "Cette année",
|
||||
"alltime": "Tout le temps",
|
||||
"noattachments": "Pas de piece jointe",
|
||||
"attachments": "Pièces jointes",
|
||||
"choosefile": "Choose File",
|
||||
"addattachment": "Ajouter une pièce jointe",
|
||||
"sharedwith": "Partager avec",
|
||||
"share": "Partager",
|
||||
"you": "Vous",
|
||||
"addfillup": "Ajouter un plein",
|
||||
"createfillup": "Créer un plein",
|
||||
"deletefillup": "Supprimer ce plein",
|
||||
"addexpense": "Ajouter une dépense",
|
||||
"createexpense": "Créer une dépense",
|
||||
"deleteexpense": "Supprimer cette dépense",
|
||||
"nofillups": "Pas de plein",
|
||||
"transfervehicle": "Transferer le Véhicule",
|
||||
"settingssaved": "Paramètres sauvegardés avec succès",
|
||||
"yoursettings": "Vos paramètres",
|
||||
"settings": "Paramètres",
|
||||
"changepassword": "Changer votre mot de passe",
|
||||
"oldpassword": "Ancien mot de passe",
|
||||
"newpassword": "Nouveau mot de passe",
|
||||
"repeatnewpassword": "Répéter votre nouveau mot de passe",
|
||||
"passworddontmatch": "Les mots de passe ne correspondent pas",
|
||||
"save": "Sauvegarder",
|
||||
"supportthedeveloper": "Supporter le développeur",
|
||||
"buyhimabeer": "Acheter lui un café!",
|
||||
"featurerequest": "Demande de fonctionnalité",
|
||||
"foundabug": "Trouvé un bug",
|
||||
"currentversion": "Version actuelle",
|
||||
"moreinfo": "Plus d'informations",
|
||||
"currency": "Monnaie",
|
||||
"distanceunit": "Unité de distance",
|
||||
"dateformat": "Format de data",
|
||||
"createnow": "Créer Maintenant",
|
||||
"yourvehicles": "Vos Véhicules",
|
||||
"menu": {
|
||||
"quickentries": "Entrée rapide",
|
||||
"logout": "Se déconnecter",
|
||||
"import": "Importer",
|
||||
"home": "Accueil",
|
||||
"settings": "Paramètres",
|
||||
"admin": "Admin",
|
||||
"sitesettings": "Paramètres du site",
|
||||
"users": "Utilisateurs",
|
||||
"login": "Connexion"
|
||||
},
|
||||
"enterusername": "Entrez votre nom d'utilisateur",
|
||||
"enterpassword": "Entrez votre mot de passe",
|
||||
"email": "Email",
|
||||
"password": "Mot de passe",
|
||||
"login": "connexion",
|
||||
"totalexpenses": "Dépenses totales",
|
||||
"fillupcost": "Coût des pleins",
|
||||
"otherexpenses": "Autres dépenses",
|
||||
"addvehicle": "Ajouter un Véhicule",
|
||||
"editvehicle": "Editer un Véhicule",
|
||||
"deletevehicle": "Supprimer un Véhicule",
|
||||
"sharevehicle": "Partager un Véhicule",
|
||||
"makeowner": "Changer le propriétaire",
|
||||
"lastfillup": "Dernier plein",
|
||||
"quickentrydesc": "Prendre une photo de la facture ou de l'écran de la pompe à essence pour créer une entrée plus tard.",
|
||||
"quickentrycreatedsuccessfully": "Entrée rapide créée avec succès",
|
||||
"uploadfile": "Téléverser un fichier",
|
||||
"uploadphoto": "Téléverser une photo",
|
||||
"details": "Détails",
|
||||
"odometer": "Odomètre",
|
||||
"language": "Langue",
|
||||
"date": "Date",
|
||||
"pastfillups": "Derniers pleins",
|
||||
"fuelsubtype": "Sous-type de combustible",
|
||||
"fueltype": "Type de combustible",
|
||||
"quantity": "Quantité",
|
||||
"gasstation": "Station service",
|
||||
"fuel": {
|
||||
"petrol": "Pétrol",
|
||||
"diesel": "Diesel",
|
||||
"cng": "CNG",
|
||||
"lpg": "LPG",
|
||||
"electric": "Electrique",
|
||||
"ethanol": "Éthanol"
|
||||
},
|
||||
"unit": {
|
||||
"long": {
|
||||
"litre": "Litre",
|
||||
"gallon": "Gallon",
|
||||
"kilowatthour": "Kilowatt Heure",
|
||||
"kilogram": "Kilogram",
|
||||
"usgallon": "US Gallon",
|
||||
"minutes": "Minutes",
|
||||
"kilometers": "Kilometres",
|
||||
"miles": "Miles"
|
||||
},
|
||||
"short": {
|
||||
"litre": "Lt",
|
||||
"gallon": "Gal",
|
||||
"kilowatthour": "KwH",
|
||||
"kilogram": "Kg",
|
||||
"usgallon": "US Gal",
|
||||
"minutes": "Mins",
|
||||
"kilometers": "Km",
|
||||
"miles": "Mi"
|
||||
}
|
||||
},
|
||||
"avgfillupqty": "Qté de plein moyen",
|
||||
"avgfillupexpense": "Prix du plein moyen",
|
||||
"avgfuelcost": "Prix de l'essence moyen",
|
||||
"per": "{0} par {1}",
|
||||
"price": "Prix",
|
||||
"total": "Total",
|
||||
"fulltank": "Reservoir complet",
|
||||
"partialfillup": "Plein partiel",
|
||||
"getafulltank": "Est-ce que vous avez rempli tout votre reservoir?",
|
||||
"tankpartialfull": "Le quel traquez-vous?",
|
||||
"by": "Par",
|
||||
"expenses": "Dépenses",
|
||||
"expensetype": "Type de dépense",
|
||||
"noexpenses": "Pas de dépense",
|
||||
"download": "Télécharger",
|
||||
"title": "Titre",
|
||||
"name": "Nom",
|
||||
"delete": "Supprimer",
|
||||
"importdata": "Importer des données dans Hammond",
|
||||
"importdatadesc": "Choisissez une option pour importer des données dans Hammond",
|
||||
"import": "Importer",
|
||||
"importcsv": "Si vous utilisiez {name} pour stocker les données de vos véhicules, exportez les données en format CSV depuis {name} et cliquez ici pour importer.",
|
||||
"importgeneric": "Importation de plein générique",
|
||||
"importgenericdesc": "Importation de plein avec un SVC.",
|
||||
"choosecsv": "Choisir un CSV",
|
||||
"choosephoto": "Choisir une Photo",
|
||||
"importsuccessfull": "Données importée avec succès",
|
||||
"importerror": "Il y a eu un problème lors de l'importation. Veuillez regarder le message d'erreur",
|
||||
"importfrom": "Importer depuis {0}",
|
||||
"stepstoimport": "Étapes pour importer des données depuis {name}",
|
||||
"choosecsvimport": "Choisissez le fichier CSV de {name} et appuyez sur le bouton pour importer.",
|
||||
"choosedatafile": "Choisissez le fichier CSV et appuyez sur le bouton pour importer.",
|
||||
"dontimportagain": "Faites attention à ne pas importer le fichier à nouveau car cela va créer des entrées dupliquées.",
|
||||
"checkpointsimportcsv": "Dès que vous avez vérifié tous ces points, importez le CSV ci-dessous.",
|
||||
"importhintunits": "De la même manière, make sure that the <u>Fuel Unit</u> and <u>Fuel Type</u> are correctly set in the Vehicle.",
|
||||
"importhintcurrdist": "Soyez sûre que la <u>Monnaie</u> et l'<u>Unité de distance</u> sont mises correctement dans Hammond. L'importation ne detectera pas automatiquement la Monnaie du fichier mais utilisera les valeurs de l'utilisateur.",
|
||||
"importhintnickname": "Soyez sûre que le nom du véhicule dans Hammon est exactement le même que le nom dans Fuelly, sinon, l'importation ne fonctionnera pas.",
|
||||
"importhintvehiclecreated": "Soyez sûre d'avoir déjà créé le véhicule dans la plate-forme Hammond.",
|
||||
"importhintcreatecsv": "Exportez vos données depuis {name} en format CSV. Les étapes pour faire ceci peuvent être trouvées",
|
||||
"importgenerichintdata": "Les données doivent être au format CSV.",
|
||||
"here": "ici",
|
||||
"unprocessedquickentries": "Vous avez 1 entrée rapide en attente d'être traîtée. | Vous avez {0} entrée rapide en attente d'être traîtée.",
|
||||
"show": "montrer",
|
||||
"loginerror": "Il y a eu une erreur lors de la connexion a votre compte: {msg}",
|
||||
"showunprocessed": "Montrer seulement les non-traîtées",
|
||||
"unprocessed": "non-traîtée",
|
||||
"sitesettingdesc": "Mettre à jour les paramètres du site. Ces valeurs seront utilisées par défaut pour les nouveaux utilisateurs.",
|
||||
"settingdesc": "Ces valeurs seront utilisées par défaut lorsque vous créez un nouveau plein ou une nouvelle dépense.",
|
||||
"areyousure": "Êtes-vous sûre de vouloir faire ceci?",
|
||||
"adduser": "Ajouter un utilisateur",
|
||||
"usercreatedsuccessfully": "Utilisateur créé avec succès",
|
||||
"userdisabledsuccessfully": "Utilisateur désactivé avec succès",
|
||||
"userenabledsuccessfully": "Utilisateur activé avec succès",
|
||||
"role": "Rôle",
|
||||
"created": "Créé",
|
||||
"createnewuser": "Créer un nouvel utilisateur",
|
||||
"cancel": "Annuler",
|
||||
"novehicles": "Il semble que vous n'avez pas encore créé de véhicule dans le système pour le moment. Commencez par créer une entrée pour un des véhicule que vous voulez traquer.",
|
||||
"processed": "Marquer en tant que traîté",
|
||||
"notfound": "Non Trouvé",
|
||||
"timeout": "La page a expiré lors du chargement. Êtes-vous sûre d'être toujours connecté à Internet?",
|
||||
"clicktoselect": "Cliquer pour sélectionner...",
|
||||
"expenseby": "Dépense par",
|
||||
"selectvehicle": "Selectionner un véhicule",
|
||||
"expensedate": "Date de la dépense",
|
||||
"totalamountpaid": "Montant payé total",
|
||||
"fillmoredetails": "Entrer plus de détails",
|
||||
"markquickentryprocessed": "Marquer l'entrée rapide séléctionnée en tant que traîtée",
|
||||
"referquickentry": "Faire référence à une entrée rapide",
|
||||
"deletequickentry": "Ceci va supprimer l'entrée rapide. Cette action ne peut pas être annulée. Êtes-vous sûre?",
|
||||
"fuelunit": "Unité de combustible",
|
||||
"fillingstation": "Nom de la station service",
|
||||
"comments": "Commentaires",
|
||||
"missfillupbefore": "Est-ce que vous avez manqué un plein avant celui-ci?",
|
||||
"missedfillup": "Plein manqué",
|
||||
"fillupdate": "Date du plein",
|
||||
"fillupsavedsuccessfully": "Plein sauvegardé avec succès",
|
||||
"expensesavedsuccessfully": "Dépense sauvegardé avec succès",
|
||||
"vehiclesavedsuccessfully": "Véhicule sauvegardé avec succès",
|
||||
"settingssavedsuccessfully": "Paramètres sauvegardés avec succès",
|
||||
"back": "Retour",
|
||||
"nickname": "Surnom",
|
||||
"registration": "Immatriculation",
|
||||
"createvehicle": "Créer un Véhicule",
|
||||
"make": "Marque",
|
||||
"model": "Modèle",
|
||||
"yearmanufacture": "Année de production",
|
||||
"enginesize": "Taille du moteur (en chevaux)",
|
||||
"mysqlconnstr": "Chaîne de caractère pour la connexion MySQL",
|
||||
"testconn": "Tester la Connexion",
|
||||
"migrate": "Migrer",
|
||||
"init": {
|
||||
"migrateclarkson": "Migrer depuis Clarkson",
|
||||
"migrateclarksondesc": "Si vous avez un déploiement Clarkson existant et que vous souhaitez migrer vos données à partir de celui-ci, appuyez sur le bouton suivant.",
|
||||
"freshinstall": "Nouvelle Installation",
|
||||
"freshinstalldesc": "Si vous voulez une nouvelle installation de Hammond, appuyez sur le bouton suivant.",
|
||||
"clarkson": {
|
||||
"desc": "<p>Vous devez vous assurer que ce déploiement de Hammond peut accéder à la base de données MySQL utilisée par Clarkson.</p><p>Si ce n'est pas directement possible, vous pouvez faire une copie de cette base de données autre part qui est accessible à partir de cette instance.</p><p>Une fois cela fait, entrez la chaîne de connexion à l'instance MySQL au format suivant.</p><p>Tous les utilisateurs importés de Clarkson auront leur nom d'utilisateur comme e-mail dans la base de données Clarkson et le mot de passe défini sur <span class='' style='font-weight:bold'>hammond</span></p><code>user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local</code><br/><br/>",
|
||||
"success": "Nous avons migré avec succès les données depuis Clarkson. Vous serez bientôt redirigé vers l'écran de connexion où vous pourrez vous connecter en utilisant votre adresse e-mail et votre mot de passe existants : hammond"
|
||||
},
|
||||
"fresh": {
|
||||
"setupadminuser": "Configurer le compte administrateur",
|
||||
"yourpassword": "Votre Mot de passe",
|
||||
"youremail": "Votre Email",
|
||||
"yourname": "Votre Nom",
|
||||
"success": "Vous avez été inscrit avec succès. Vous allez être redirigé vers la page de connexion très bientôt, vous pourrez vous connecter et commencer à utiliser le système."
|
||||
}
|
||||
},
|
||||
"roles": {
|
||||
"ADMIN": "ADMIN",
|
||||
"USER": "USER"
|
||||
},
|
||||
"profile": "Profile",
|
||||
"processedon": "Traîté le",
|
||||
"enable": "Activer",
|
||||
"disable": "Désactiver",
|
||||
"confirm": "Continuer",
|
||||
"labelforfile": "Label pour ce fichier"
|
||||
}
|
||||
231
ui/src/locales/hu.json
Normal file
231
ui/src/locales/hu.json
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"quickentry": "Nincs gyors bejegyzés | Gyors bejegyzés | Gyors bejegyzések",
|
||||
"statistics": "Statisztikák",
|
||||
"thisweek": "Ez a hét",
|
||||
"thismonth": "Ez a hónap",
|
||||
"pastxdays": "Elmúlt 1 nap | Elmúlt {count} nap",
|
||||
"pastxmonths": "Elmúlt 1 hónap | Past {count} hónap",
|
||||
"thisyear": "Ez az év",
|
||||
"alltime": "Összes",
|
||||
"noattachments": "Nincs csatolmány eddig",
|
||||
"attachments": "Csatolmányok",
|
||||
"choosefile": "Válassz fájlt",
|
||||
"addattachment": "Csatolmány hozzáadása",
|
||||
"sharedwith": "Megosztva vele",
|
||||
"share": "Megosztás",
|
||||
"you": "Te",
|
||||
"addfillup": "Tankolás hozzáadása",
|
||||
"createfillup": "Tankolás létrehozása",
|
||||
"deletefillup": "Tankolás törlése",
|
||||
"addexpense": "Kiadás hozzáadása",
|
||||
"createexpense": "Kiadás létrehozása",
|
||||
"deleteexpense": "Kiads törlése",
|
||||
"nofillups": "Nincs tankolás eddig",
|
||||
"transfervehicle": "Jármű átruházása",
|
||||
"settingssaved": "Beállítások sikeresen mentve",
|
||||
"yoursettings": "Beállításaid",
|
||||
"settings": "Beállítások",
|
||||
"changepassword": "Jelszó megváltoztatása",
|
||||
"oldpassword": "Régi jelszó",
|
||||
"newpassword": "Új jelszó",
|
||||
"repeatnewpassword": "Jelszó mégegyszer",
|
||||
"passworddontmatch": "Jelszavak nem egyeznek",
|
||||
"save": "Mentés",
|
||||
"supportthedeveloper": "Támogsad a fejlesztőt",
|
||||
"buyhimabeer": "Vegyél neki egy sört!",
|
||||
"featurerequest": "Funkció kérése",
|
||||
"foundabug": "Hibát találtam",
|
||||
"currentversion": "Aktuális verzió",
|
||||
"moreinfo": "Több információ",
|
||||
"currency": "Pénznem",
|
||||
"distanceunit": "Távolság mértékegysége",
|
||||
"dateformat": "Dátum formátuma",
|
||||
"createnow": "Létrehozás most",
|
||||
"yourvehicles": "Járműveid",
|
||||
"menu": {
|
||||
"quickentries": "Gyors bejegyzések",
|
||||
"logout": "Kijelentkezés",
|
||||
"import": "Betöltés",
|
||||
"home": "Kezdőlap",
|
||||
"settings": "Beállítások",
|
||||
"admin": "Adminisztrátor",
|
||||
"sitesettings": "Oldal beállításai",
|
||||
"users": "Felhasználók",
|
||||
"login": "Bejelentkezés"
|
||||
},
|
||||
"enterusername": "Írd be a felhasználó neved",
|
||||
"enterpassword": "Írd be a jelszavad",
|
||||
"email": "Email",
|
||||
"password": "Jelszó",
|
||||
"login": "bejelentkezés",
|
||||
"totalexpenses": "Összeskiadás",
|
||||
"fillupcost": "Tankolás költsége",
|
||||
"otherexpenses": "Egyéb kiadás",
|
||||
"addvehicle": "Jármű hozzáadása",
|
||||
"editvehicle": "Jármű szerkesztése",
|
||||
"deletevehicle": "Jármű törlése",
|
||||
"sharevehicle": "Jármű megosztása",
|
||||
"makeowner": "Tulajdonosnak jelölés",
|
||||
"lastfillup": "Utolsó tankolás",
|
||||
"quickentrydesc": "Csinálj képet a blokkról/számláról vagy a tankoló mérőóráról hogy fel tudd vinni később az adatokat.",
|
||||
"quickentrycreatedsuccessfully": "Gyors bejegyzés sikeresen létrehozva",
|
||||
"uploadfile": "Fájl feltöltése",
|
||||
"uploadphoto": "Fotó feltöltése",
|
||||
"details": "Részletek",
|
||||
"odometer": "Kilóméter óra",
|
||||
"language": "Nyelv",
|
||||
"date": "Dátum",
|
||||
"pastfillups": "Előző tankolások",
|
||||
"fuelsubtype": "Üzemanyag altípus",
|
||||
"fueltype": "Üzemanyag típus",
|
||||
"quantity": "Mennyiség",
|
||||
"gasstation": "Benzinkút",
|
||||
"fuel": {
|
||||
"petrol": "Benzin",
|
||||
"diesel": "Dízel",
|
||||
"cng": "CNG",
|
||||
"lpg": "LPG",
|
||||
"electric": "Elektromos",
|
||||
"ethanol": "Etanol"
|
||||
},
|
||||
"unit": {
|
||||
"long": {
|
||||
"litre": "Liter",
|
||||
"gallon": "Gallon",
|
||||
"kilowatthour": "Kilowattóra",
|
||||
"kilogram": "Kilogram",
|
||||
"usgallon": "US Gallon",
|
||||
"minutes": "Perc",
|
||||
"kilometers": "Kilóméter",
|
||||
"miles": "Mérföld"
|
||||
},
|
||||
"short": {
|
||||
"litre": "L",
|
||||
"gallon": "Gal",
|
||||
"kilowatthour": "KwH",
|
||||
"kilogram": "Kg",
|
||||
"usgallon": "US Gal",
|
||||
"minutes": "P",
|
||||
"kilometers": "Km",
|
||||
"miles": "Mérf"
|
||||
}
|
||||
},
|
||||
"avgfillupqty": "Átl. tankolási menny.",
|
||||
"avgfillupexpense": "Átl. tankolási kiadás",
|
||||
"avgfuelcost": "Átl. üzemanyag ár",
|
||||
"per": "{0} per {1}",
|
||||
"price": "Ár",
|
||||
"total": "Összesen",
|
||||
"fulltank": "Tele tank",
|
||||
"partialfillup": "Részleges tankolás",
|
||||
"getafulltank": "Teletankoltál?",
|
||||
"tankpartialfull": "Which do you track?",
|
||||
"by": "által",
|
||||
"expenses": "Kiadások",
|
||||
"expensetype": "Kiadás típusa",
|
||||
"noexpenses": "Nincs kiadás eddig",
|
||||
"download": "Letöltés",
|
||||
"title": "Címe",
|
||||
"name": "Neve",
|
||||
"delete": "Törlés",
|
||||
"importdata": "Adata betöltésa Hammondba",
|
||||
"importdatadesc": "Válassz az alábbi lehetőségek közül, hogy betöltsd az adatokat",
|
||||
"import": "Betöltés",
|
||||
"importcsv": "Ha már használtad {name}-t hogy tárold a jármű adatait, exportáld CSV-be {name}-ból/ből majd kattints it a Betöltésre.",
|
||||
"importgeneric": "Általános tanoklások betöltése",
|
||||
"importgenericdesc": "Tankolás CSV betöltés.",
|
||||
"choosecsv": "CSV választása",
|
||||
"choosephoto": "Fotó választása",
|
||||
"importsuccessfull": "Adat sikeresen betöltve",
|
||||
"importerror": "Betöltés közben hiba lépett fel. Kérem ellenőrizze a hibaüzenetet.",
|
||||
"importfrom": "Betöltés innen: {0}",
|
||||
"stepstoimport": "Lépések az adat betöltéséhez {name}-ból/ből",
|
||||
"choosecsvimport": "Válassza a/az {name} CSV-t és nyomja meg a betöltés gombot.",
|
||||
"choosedatafile": "Válassza a CSV fájlt majd nyomja meg az importálás gombot.",
|
||||
"dontimportagain": "Legyen biztos benne, hogy nem importálja újra ugyan azt a fájlt. Dublikált bejegyzéseket eredményez.",
|
||||
"checkpointsimportcsv": "Amikor végzett az összes ponttal, töltse be a CSV-t lejjebb.",
|
||||
"importhintunits": "Hasonlóan, legyen biztos benne, hogy az <u>Üzemanyag egysége</u> és az <u>Üzemanyag Típúsa</u> helyesek a Jármű beállításaiban.",
|
||||
"importhintcurrdist": "Ellenőrizze, hogy a <u>Pénznem</u> és a <u>Távolság mértékegysége</u> be lettek állítva a Hammond-ban. A betöltés automatikusan nem ismeri fel a bejegyzések Pénznemét, helyette a felhaszáló alapértlemzett beállítása lesz alkalmazva.",
|
||||
"importhintnickname": "Ellenőrizze, hogy a Jármű neve Hammond-ban megegyezik a Fuelly CSV-ben használttal vagy a betöltés nem fog működni.",
|
||||
"importhintvehiclecreated": "Ellenőrizze, hogy a Járművek már léteznek a Hammond rendszerében.",
|
||||
"importhintcreatecsv": "Mentse adatát {name}-ból/ből CSV formátumba. Steps to do that can be found",
|
||||
"importgenerichintdata": "Az adatnak CSV formátumban kell lennie.",
|
||||
"here": "itt",
|
||||
"unprocessedquickentries": "Egy gyors bejegyzés feldolgozva. | {0} gyorsbejegyzés vár feldolgozásra.",
|
||||
"show": "Mutasd",
|
||||
"loginerror": "Hiba történt a bejelentkezés során. {msg}",
|
||||
"showunprocessed": "Csak nem feldolgozottak",
|
||||
"unprocessed": "feldolgozatlan",
|
||||
"sitesettingdesc": "Oldal beállításainak módosítása. Ezek lesznek használva új felhazsnálók létrehozásakor.",
|
||||
"settingdesc": "Ezek lesznak alkalmazva alapértelmezett értékként, tankolásnál vagy kiadásnál.",
|
||||
"areyousure": "Biztos hogy ezt akarja?",
|
||||
"adduser": "Felhasználó hozzáadása",
|
||||
"usercreatedsuccessfully": "Felhasználó sikeresen létrehozva",
|
||||
"userdisabledsuccessfully": "Felhasználó sikeresen letiltva",
|
||||
"userenabledsuccessfully": "Felhasználó sikeresen engedélyezve",
|
||||
"role": "Szerepkör",
|
||||
"created": "Létrehozva",
|
||||
"createnewuser": "Új felhasználó létrehozása",
|
||||
"cancel": "Mégsem",
|
||||
"novehicles": "Eddig nem hozott létre járművet a rendszerében. Hozzon létre egyet amelynek adatait követni szeretné.",
|
||||
"processed": "Megjelölés feldolgozottnak",
|
||||
"notfound": "Nem talált",
|
||||
"timeout": "A lap túl sokáig nem töltött be. Biztos benne, hogy még mindig van \ninternet elérése?",
|
||||
"clicktoselect": "Válasszon...",
|
||||
"expenseby": "Kiadások ez szerint",
|
||||
"selectvehicle": "Válassz járművet",
|
||||
"expensedate": "Kiadás dátuma",
|
||||
"totalamountpaid": "Összes kifizetés",
|
||||
"fillmoredetails": "Több részlet kitöltése",
|
||||
"markquickentryprocessed": "Kiválasztott gyorsbejegyzések megjelölése feldolgozottként",
|
||||
"referquickentry": "Gzorsbejegzy;s referencia",
|
||||
"deletequickentry": "Ez kitörli ezt a gyorsbejegyzést. Ez a lépés visszafordíthatatlan. Biztos benne?",
|
||||
"fuelunit": "Üzemenyag egység",
|
||||
"fillingstation": "Benzinkút neve",
|
||||
"comments": "Komment",
|
||||
"missfillupbefore": "Nem töltötte ki az előző tankolást?",
|
||||
"missedfillup": "Kihagyott tankolás",
|
||||
"fillupdate": "Tankolás dátuma",
|
||||
"fillupsavedsuccessfully": "Tankolás sikeresen mentve",
|
||||
"expensesavedsuccessfully": "Kiadás sikeresen mentve",
|
||||
"vehiclesavedsuccessfully": "Jármű sikeresen mentve",
|
||||
"settingssavedsuccessfully": "Beállítások sikeresen mentve",
|
||||
"back": "Vissza",
|
||||
"nickname": "Becenév",
|
||||
"registration": "Rendszám",
|
||||
"createvehicle": "Jármű létrehozása",
|
||||
"make": "Gyártó",
|
||||
"model": "Model",
|
||||
"yearmanufacture": "Gyártás éve",
|
||||
"enginesize": "Motorméret (cm3)",
|
||||
"mysqlconnstr": "Mysql Connection String",
|
||||
"testconn": "Kapcsolat tesztelése",
|
||||
"migrate": "Migrálás",
|
||||
"init": {
|
||||
"migrateclarkson": "Migrálás Clarkson-ból",
|
||||
"migrateclarksondesc": "Ha van egy meglévő Clarkson telepítése, és szeretné adatait átmozgatni onnan, nyomja meg a következő gombot.",
|
||||
"freshinstall": "Tiszta telepítés",
|
||||
"freshinstalldesc": "Ha szeretné a Hammond tiszta telepítését, nyomja meg a következő gombot.",
|
||||
"clarkson": {
|
||||
"desc": "<p>Biztosítania kell, hogy ez a Hammond telepítés el tudja érni a Clarkson által készített MySQL adatbázist.</p><p>Ha ez nem megoldható, készíthet egy másolatot az adatbázisról, és elhelyzheti olyan helyre amely elérhető innen.</p><p>Amikor ezzel kész van, Állítsa me a connection String-et a MySQL-hez a következő formátumban.</p><p>Az összes Clarkson-ból migrált felhasználónak az e-mail címük lesz a felhasználó nevük, és a jelszavuk <span class='' style='font-weight:bold'>hammond</span> lesz</p><code>user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local</code><br/><br/>",
|
||||
"success": "Sikeresen migráltuk az adatot Clarkson-ból. Hamarosan át lesz irányítva a bejelentkezési oldalra, ahol használhatja a meglévő fiókját, és jelszavát: hammond"
|
||||
},
|
||||
"fresh": {
|
||||
"setupadminuser": "Adminisztrátor felhasználó beállítása",
|
||||
"yourpassword": "Ön jelszava",
|
||||
"youremail": "Ön e-mailcíme",
|
||||
"yourname": "Ön neve",
|
||||
"success": "Ön sikeresen regisztrált. Át lesz irányítva a bejelentkezési képernyőre, ahol be tud jelentkezni és elkezdheti használni a rendszert."
|
||||
}
|
||||
},
|
||||
"roles": {
|
||||
"ADMIN": "ADMIN",
|
||||
"USER": "FELHASZNÁLÓ"
|
||||
},
|
||||
"profile": "Profil",
|
||||
"processedon": "Felfdolgozva ekkor",
|
||||
"enable": "Engedélyezve",
|
||||
"disable": "Letiltva",
|
||||
"confirm": "Megerősítés",
|
||||
"labelforfile": "Címke ehheza fájlhoz"
|
||||
}
|
||||
231
ui/src/locales/sl.json
Normal file
231
ui/src/locales/sl.json
Normal file
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"quickentry": "Ni hitrih vnosov | Hiter vnos | Hitri vnosi",
|
||||
"statistics": "Statistika",
|
||||
"thisweek": "Ta teden",
|
||||
"thismonth": "Ta mesec",
|
||||
"pastxdays": "Zadnji dan | Zadnjih {count} dni",
|
||||
"pastxmonths": "Zadnji mesec | Zadnji {count} mesecev",
|
||||
"thisyear": "To leto",
|
||||
"alltime": "Celoten čas",
|
||||
"noattachments": "Zaenkrat še ni priponk",
|
||||
"attachments": "Priloge",
|
||||
"choosefile": "Izberi datoteko",
|
||||
"addattachment": "Dodaj prilogo",
|
||||
"sharedwith": "V skupni rabi z",
|
||||
"share": "Deli",
|
||||
"you": "Ti",
|
||||
"addfillup": "Dodaj polnjenje",
|
||||
"createfillup": "Ustvarite polnjenje",
|
||||
"deletefillup": "Izbriši to polnjenje",
|
||||
"addexpense": "Dodaj strošek",
|
||||
"createexpense": "Ustvari strošek",
|
||||
"deleteexpense": "Izbriši ta strošek",
|
||||
"nofillups": "Zaenkrat še brez polnjenja",
|
||||
"transfervehicle": "Prevozno sredstvo",
|
||||
"settingssaved": "Nastavitve so uspešno shranjene",
|
||||
"yoursettings": "Vaše nastavitve",
|
||||
"settings": "Nastavitve",
|
||||
"changepassword": "Spremeni geslo",
|
||||
"oldpassword": "Staro geslo",
|
||||
"newpassword": "Novo geslo",
|
||||
"repeatnewpassword": "Ponovite novo geslo",
|
||||
"passworddontmatch": "Vrednosti gesel se ne ujemajo",
|
||||
"save": "Shrani",
|
||||
"supportthedeveloper": "Podprite razvijalca",
|
||||
"buyhimabeer": "Kupi mu pivo!",
|
||||
"featurerequest": "Nova funkcionalnost",
|
||||
"foundabug": "Našel sem hrošča",
|
||||
"currentversion": "Trenutna verzija",
|
||||
"moreinfo": "Več informacij",
|
||||
"currency": "Valuta",
|
||||
"distanceunit": "Enota razdalje",
|
||||
"dateformat": "Format datuma",
|
||||
"createnow": "Ustvari zdaj",
|
||||
"yourvehicles": "Vaša vozila",
|
||||
"menu": {
|
||||
"quickentries": "Hitri vnosi",
|
||||
"logout": "Odjava",
|
||||
"import": "Uvoz",
|
||||
"home": "Domov",
|
||||
"settings": "Nastavitve",
|
||||
"admin": "Skrbnik",
|
||||
"sitesettings": "Nastavitve spletnega mesta",
|
||||
"users": "Uporabniki",
|
||||
"login": "Vpiši se"
|
||||
},
|
||||
"enterusername": "Vnesite svoje uporabniško ime",
|
||||
"enterpassword": "Vnesite vaše geslo",
|
||||
"email": "E-naslov",
|
||||
"password": "Geslo",
|
||||
"login": "Vpiši se",
|
||||
"totalexpenses": "Skupni stroški",
|
||||
"fillupcost": "Stroški polnjenja",
|
||||
"otherexpenses": "Drugi stroški",
|
||||
"addvehicle": "Dodaj vozilo",
|
||||
"editvehicle": "Uredi vozilo",
|
||||
"deletevehicle": "Izbriši vozilo",
|
||||
"sharevehicle": "Deli vozilo",
|
||||
"makeowner": "Postani lastnik",
|
||||
"lastfillup": "Zadnje polnjenje",
|
||||
"quickentrydesc": "Posnemite sliko računa ali zaslona črpalke za gorivo, da ju lahko vnesete pozneje.",
|
||||
"quickentrycreatedsuccessfully": "Hitri vnos je bil uspešno ustvarjen",
|
||||
"uploadfile": "Naloži datoteko",
|
||||
"uploadphoto": "Naloži fotografijo",
|
||||
"details": "Podrobnosti",
|
||||
"odometer": "Odometer",
|
||||
"language": "Jezik",
|
||||
"date": "Datum",
|
||||
"pastfillups": "Prejšnja polnjenja",
|
||||
"fuelsubtype": "Podvrsta goriva",
|
||||
"fueltype": "Vrsta goriva",
|
||||
"quantity": "Količina",
|
||||
"gasstation": "Bencinska črpalka",
|
||||
"fuel": {
|
||||
"petrol": "Bencin",
|
||||
"diesel": "Dizelsko gorivo",
|
||||
"cng": "CNG",
|
||||
"lpg": "LPG",
|
||||
"electric": "Elektrika",
|
||||
"ethanol": "Etanol"
|
||||
},
|
||||
"unit": {
|
||||
"long": {
|
||||
"litre": "Liter",
|
||||
"gallon": "Galon",
|
||||
"kilowatthour": "Kilovatna ura",
|
||||
"kilogram": "Kilogram",
|
||||
"usgallon": "Ameriška galona",
|
||||
"minutes": "Minute",
|
||||
"kilometers": "Kilometri",
|
||||
"miles": "Milje"
|
||||
},
|
||||
"short": {
|
||||
"litre": "Lit",
|
||||
"gallon": "Gal",
|
||||
"kilowatthour": "KwH",
|
||||
"kilogram": "Kg",
|
||||
"usgallon": "US Gal",
|
||||
"minutes": "Min",
|
||||
"kilometers": "Km",
|
||||
"miles": "Mi"
|
||||
}
|
||||
},
|
||||
"avgfillupqty": "Povprečna količina polnjenja",
|
||||
"avgfillupexpense": "Povprečni stroški polnjenja",
|
||||
"avgfuelcost": "Povprečni strošek goriva",
|
||||
"per": "{0} na {1}",
|
||||
"price": "Cena",
|
||||
"total": "Skupaj",
|
||||
"fulltank": "Rezervoar poln",
|
||||
"partialfillup": "Delno polnjenje",
|
||||
"getafulltank": "Ste dobili poln rezervoar?",
|
||||
"tankpartialfull": "Kateremu sledite?",
|
||||
"by": "Od",
|
||||
"expenses": "Stroški",
|
||||
"expensetype": "Vrsta stroška",
|
||||
"noexpenses": "Zaenkrat ni bilo stroškov",
|
||||
"download": "Prenesi",
|
||||
"title": "Naslov",
|
||||
"name": "Ime",
|
||||
"delete": "Izbriši",
|
||||
"importdata": "Uvozite podatke v Hammond",
|
||||
"importdatadesc": "Za uvoz podatkov v Hammond izberite med naslednjimi možnostmi",
|
||||
"import": "Uvozi",
|
||||
"importcsv": "Če ste za shranjevanje podatkov o vozilu uporabljali {name}, izvozite datoteko CSV iz {name} in kliknite tukaj za uvoz.",
|
||||
"importgeneric": "Generični uvoz polnjenja",
|
||||
"importgenericdesc": "CSV uvoz poljenja.",
|
||||
"choosecsv": "Izberite CSV",
|
||||
"choosephoto": "Izberite fotografijo",
|
||||
"importsuccessfull": "Podatki so bili uspešno uvoženi",
|
||||
"importerror": "Pri uvozu datoteke je prišlo do težave. ",
|
||||
"importfrom": "Uvoz iz {0}",
|
||||
"stepstoimport": "Koraki za uvoz podatkov iz {name}",
|
||||
"choosecsvimport": "Izberite {name} CSV in pritisnite gumb za uvoz.",
|
||||
"choosedatafile": "Izberite datoteko CSV in pritisnite gumb za uvoz.",
|
||||
"dontimportagain": "Prepričajte se, da datoteke ne uvozite znova, ker boste s tem ustvarili ponavljajoče se vnose.",
|
||||
"checkpointsimportcsv": "Ko preverite vse te točke, preprosto uvozite spodnji CSV.",
|
||||
"importhintunits": "Podobno se prepričajte, da sta <u>Enota za gorivo</u> in <u>Vrsta goriva</u> pravilno nameščeni pod Vozilo.",
|
||||
"importhintcurrdist": "Prepričajte se, da sta <u>Valuta</u> in <u>Enota razdalje</u> pri Hammondu uporabniku pravilno nastavljeni.",
|
||||
"importhintnickname": "Prepričajte se, da je vzdevek vozila v Hammondu popolnoma enak imenu v CSV datoteki polnjenj, sicer uvoz ne bo deloval.",
|
||||
"importhintvehiclecreated": "Prepričajte se, da ste že ustvarili vozila na platformi Hammond.",
|
||||
"importhintcreatecsv": "Izvozite svoje podatke iz {name} v formatu CSV. ",
|
||||
"importgenerichintdata": "Podatki morajo biti v formatu CSV.",
|
||||
"here": "tukaj",
|
||||
"unprocessedquickentries": "Za obdelavo imate en hiter vnos. | Za obdelavo imate {0} hitrih vnosov.",
|
||||
"show": "Prikaži",
|
||||
"loginerror": "Pri prijavi v vaš račun je prišlo do napake. ",
|
||||
"showunprocessed": "Pokaži samo neobdelano",
|
||||
"unprocessed": "neobdelano",
|
||||
"sitesettingdesc": "Posodobite nastavitve na ravni aplikacije. Te bodo uporabljene kot privzete vrednosti za nove uporabnike.",
|
||||
"settingdesc": "Te bodo uporabljene kot privzete vrednosti vsakič, ko ustvarite novo polnjenje ali strošek.",
|
||||
"areyousure": "Ste prepričani, da želite to narediti?",
|
||||
"adduser": "Dodaj uporabnika",
|
||||
"usercreatedsuccessfully": "Uporabnik je bil uspešno ustvarjen",
|
||||
"userdisabledsuccessfully": "Uporabnik uspešno onemogočen",
|
||||
"userenabledsuccessfully": "Uporabnik je uspešno omogočen",
|
||||
"role": "Vloga",
|
||||
"created": "Ustvarjeno",
|
||||
"createnewuser": "Ustvari novega uporabnika",
|
||||
"cancel": "Prekliči",
|
||||
"novehicles": "Videti je, da še niste ustvarili vozila v sistemu. ",
|
||||
"processed": "Označi obdelano",
|
||||
"notfound": "Ni najdeno",
|
||||
"timeout": "Med nalaganjem strani je potekla časovna omejitev. ",
|
||||
"clicktoselect": "Kliknite za izbiro ...",
|
||||
"expenseby": "Stroški po",
|
||||
"selectvehicle": "Izberite vozilo",
|
||||
"expensedate": "Datum izdatka",
|
||||
"totalamountpaid": "Skupni plačani znesek",
|
||||
"fillmoredetails": "Izpolnite več podrobnosti",
|
||||
"markquickentryprocessed": "Označi izbrani hitri vnos kot obdelan",
|
||||
"referquickentry": "Oglejte si hiter vnos",
|
||||
"deletequickentry": "S tem boste izbrisali ta hitri vnos. ",
|
||||
"fuelunit": "Enota za gorivo",
|
||||
"fillingstation": "Ime bencinske postaje",
|
||||
"comments": "Komentarji",
|
||||
"missfillupbefore": "Ste pred tem zamudili vnos zapolnitve?",
|
||||
"missedfillup": "Zamujeno polnjenje",
|
||||
"fillupdate": "Datum polnjenja",
|
||||
"fillupsavedsuccessfully": "Polnjenje je bil uspešno shranjeno",
|
||||
"expensesavedsuccessfully": "Stroški so uspešno shranjeni",
|
||||
"vehiclesavedsuccessfully": "Vozilo je uspešno shranjeno",
|
||||
"settingssavedsuccessfully": "Nastavitve so uspešno shranjene",
|
||||
"back": "Nazaj",
|
||||
"nickname": "Vzdevek",
|
||||
"registration": "Registracija",
|
||||
"createvehicle": "Ustvarite vozilo",
|
||||
"make": "Znamka / Podjetje",
|
||||
"model": "Model",
|
||||
"yearmanufacture": "Leto izdelave",
|
||||
"enginesize": "Prostornina motorja (v cc)",
|
||||
"mysqlconnstr": "Niz povezave Mysql",
|
||||
"testconn": "Testna povezava",
|
||||
"migrate": "Preseli",
|
||||
"init": {
|
||||
"migrateclarkson": "Selitev iz Clarksona",
|
||||
"migrateclarksondesc": "Če imate obstoječo Clarkson namestitev in želite iz nje preseliti svoje podatke, pritisnite naslednji gumb.",
|
||||
"freshinstall": "Sveža namestitev",
|
||||
"freshinstalldesc": "Če želite novo namestitev Hammonda, pritisnite naslednji gumb.",
|
||||
"clarkson": {
|
||||
"desc": "<p>Zagotoviti morate, da lahko ta uvedba Hammonda dostopa do baze podatkov MySQL, ki jo uporablja Clarkson.</p><p>Če to ni neposredno mogoče, lahko naredite kopijo te zbirke podatkov nekje, kjer je dostopna iz tega primerka.</p><p>Ko je to storjeno, vnesite povezovalni niz v primerek MySQL v naslednji obliki.</p><p>Vsi uporabniki, uvoženi iz Clarksona, bodo imeli svoje uporabniško ime kot e-pošto v bazi podatkov Clarkson in geslo nastavljeno na<span class='' style='font-weight:bold'>hammond</span></p><code>uporabnik:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4</code><br/><br/>",
|
||||
"success": "Uspešno smo prenesli podatke iz Clarksona. "
|
||||
},
|
||||
"fresh": {
|
||||
"setupadminuser": "Nastavitev skrbniških uporabnikov",
|
||||
"yourpassword": "Vaše geslo",
|
||||
"youremail": "Vaš e-poštni naslov",
|
||||
"yourname": "Vaše ime",
|
||||
"success": "Uspešno ste se registrirali. "
|
||||
}
|
||||
},
|
||||
"roles": {
|
||||
"ADMIN": "SKRBNIK",
|
||||
"USER": "UPORABNIK"
|
||||
},
|
||||
"profile": "Profil",
|
||||
"processedon": "Obdelano dne",
|
||||
"enable": "Omogoči",
|
||||
"disable": "Onemogoči",
|
||||
"confirm": "Kar daj",
|
||||
"labelforfile": "Oznaka za to datoteko"
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
faCheck,
|
||||
faTimes,
|
||||
faArrowUp,
|
||||
faArrowRotateLeft,
|
||||
faAngleLeft,
|
||||
faAngleRight,
|
||||
faCalendar,
|
||||
@@ -34,11 +35,11 @@ import '@components/_globals'
|
||||
import 'buefy/dist/buefy.css'
|
||||
import 'nprogress/nprogress.css'
|
||||
|
||||
Vue.component('vue-fontawesome', FontAwesomeIcon)
|
||||
library.add(
|
||||
faCheck,
|
||||
faTimes,
|
||||
faArrowUp,
|
||||
faArrowRotateLeft,
|
||||
faAngleLeft,
|
||||
faAngleRight,
|
||||
faCalendar,
|
||||
@@ -54,7 +55,8 @@ library.add(
|
||||
faShare,
|
||||
faUserFriends,
|
||||
faTimesCircle
|
||||
)
|
||||
);
|
||||
Vue.component('VueFontawesome', FontAwesomeIcon)
|
||||
|
||||
Vue.use(Buefy, {
|
||||
defaultIconComponent: 'vue-fontawesome',
|
||||
|
||||
@@ -410,6 +410,24 @@ export default [
|
||||
},
|
||||
props: (route) => ({ user: store.state.auth.currentUser || {} }),
|
||||
},
|
||||
{
|
||||
path: '/import/drivvo',
|
||||
name: 'import-drivvo',
|
||||
component: () => lazyLoadView(import('@views/import-drivvo.vue')),
|
||||
meta: {
|
||||
authRequired: true,
|
||||
},
|
||||
props: (route) => ({ user: store.state.auth.currentUser || {} }),
|
||||
},
|
||||
{
|
||||
path: '/import/generic',
|
||||
name: 'import-generic',
|
||||
component: () => lazyLoadView(import('@views/import-generic.vue')),
|
||||
meta: {
|
||||
authRequired: true,
|
||||
},
|
||||
props: (route) => ({ user: store.state.auth.currentUser || {} }),
|
||||
},
|
||||
{
|
||||
path: '/logout',
|
||||
name: 'logout',
|
||||
|
||||
@@ -162,41 +162,41 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
<form @submit.prevent="createExpense">
|
||||
<b-field :label="this.$t('selectvehicle')">
|
||||
<b-select v-model="selectedVehicle" :placeholder="this.$t('vehicle')" required expanded :disabled="expense.id">
|
||||
<b-field :label="$t('selectvehicle')">
|
||||
<b-select v-model="selectedVehicle" :placeholder="$t('vehicle')" required expanded :disabled="expense.id">
|
||||
<option v-for="option in myVehicles" :key="option.id" :value="option">
|
||||
{{ option.nickname }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('expenseby')">
|
||||
<b-select v-model="expenseModel.userId" :placeholder="this.$t('user')" required expanded :disabled="expense.id">
|
||||
<b-field :label="$t('expenseby')">
|
||||
<b-select v-model="expenseModel.userId" :placeholder="$t('user')" required expanded :disabled="expense.id">
|
||||
<option v-for="option in users" :key="option.userId" :value="option.userId">
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('expensedate')">
|
||||
<b-field :label="$t('expensedate')">
|
||||
<b-datepicker
|
||||
v-model="expenseModel.date"
|
||||
:date-formatter="formatDate"
|
||||
:placeholder="this.$t('clicktoselect')"
|
||||
:placeholder="$t('clicktoselect')"
|
||||
icon="calendar"
|
||||
:max-date="new Date()"
|
||||
>
|
||||
</b-datepicker>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('expensetype') + `*`">
|
||||
<b-field :label="$t('expensetype') + `*`">
|
||||
<b-input v-model="expenseModel.expenseType" expanded required></b-input>
|
||||
</b-field>
|
||||
|
||||
<b-field :label="this.$t('totalamountpaid')">
|
||||
<b-field :label="$t('totalamountpaid')">
|
||||
<p class="control">
|
||||
<span class="button is-static">{{ me.currency }}</span>
|
||||
</p>
|
||||
<b-input v-model.number="expenseModel.amount" type="number" min="0" expanded step=".001" required></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('odometer')">
|
||||
<b-field :label="$t('odometer')">
|
||||
<p class="control">
|
||||
<span class="button is-static">{{ $t('unit.short.' + me.distanceUnitDetail.key) }}</span>
|
||||
</p>
|
||||
@@ -207,7 +207,7 @@ export default {
|
||||
<b-switch v-model="showMore">{{ $t('fillmoredetails') }}</b-switch>
|
||||
</b-field>
|
||||
<fieldset v-if="showMore">
|
||||
<b-field :label="this.$t('details')">
|
||||
<b-field :label="$t('details')">
|
||||
<b-input v-model="expenseModel.comments" type="textarea" expanded></b-input>
|
||||
</b-field>
|
||||
</fieldset>
|
||||
@@ -216,7 +216,7 @@ export default {
|
||||
</b-field>
|
||||
<br />
|
||||
<b-field>
|
||||
<b-button tag="input" native-type="submit" :value="this.$t('save')" :disabled="tryingToCreate" type="is-primary" label="Create Expense" expanded> </b-button>
|
||||
<b-button tag="button" native-type="submit" :value="$t('save')" :disabled="tryingToCreate" type="is-primary" label="Create Expense" expanded/>
|
||||
</b-field>
|
||||
</form>
|
||||
</Layout>
|
||||
|
||||
@@ -76,6 +76,9 @@ export default {
|
||||
this.fetchVehicleFuelSubTypes()
|
||||
if (!this.fillup.id) {
|
||||
this.fillupModel = this.getEmptyFillup()
|
||||
if (this.vehicle.fillups.length > 0) {
|
||||
this.fillupModel.odoReading = this.vehicle.fillups[0].odoReading
|
||||
}
|
||||
this.fillupModel.userId = this.me.id
|
||||
}
|
||||
},
|
||||
@@ -193,21 +196,21 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
<form class="" @submit.prevent="createFillup">
|
||||
<b-field :label="this.$t('selectvehicle')">
|
||||
<b-select v-model="selectedVehicle" :placeholder="this.$t('vehicle')" required expanded :disabled="fillup.id">
|
||||
<b-field :label="$t('selectvehicle')">
|
||||
<b-select v-model="selectedVehicle" :placeholder="$t('vehicle')" required expanded :disabled="fillup.id">
|
||||
<option v-for="option in myVehicles" :key="option.id" :value="option">
|
||||
{{ option.nickname }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('expenseby')">
|
||||
<b-select v-model="fillupModel.userId" :placeholder="this.$t('user')" required expanded :disabled="fillup.id">
|
||||
<b-field :label="$t('expenseby')">
|
||||
<b-select v-model="fillupModel.userId" :placeholder="$t('user')" required expanded :disabled="fillup.id">
|
||||
<option v-for="option in users" :key="option.userId" :value="option.userId">
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('fillupdate')">
|
||||
<b-field :label="$t('fillupdate')">
|
||||
<b-datepicker
|
||||
v-model="fillupModel.date"
|
||||
:date-formatter="formatDate"
|
||||
@@ -218,7 +221,7 @@ export default {
|
||||
>
|
||||
</b-datepicker>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('fuelsubtype')">
|
||||
<b-field :label="$t('fuelsubtype')">
|
||||
<b-autocomplete
|
||||
v-model="fillupModel.fuelSubType"
|
||||
:data="filteredFuelSubtypes"
|
||||
@@ -229,27 +232,27 @@ export default {
|
||||
>
|
||||
</b-autocomplete>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('quantity') + `*`" addons>
|
||||
<b-field :label="$t('quantity') + `*`" addons>
|
||||
<b-input v-model.number="fillupModel.fuelQuantity" type="number" step=".001" min="0" expanded required></b-input>
|
||||
<b-select v-model="fillupModel.fuelUnit" :placeholder="this.$t('fuelunit')" required>
|
||||
<b-select v-model="fillupModel.fuelUnit" :placeholder="$t('fuelunit')" required>
|
||||
<option v-for="(option, key) in fuelUnitMasters" :key="key" :value="key">
|
||||
{{ $t('unit.long.' + option.key) }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('per', { '0': this.$t('price'), '1': $t('unit.short.' + vehicle.fuelUnitDetail.key) })"
|
||||
<b-field :label="$t('per', { '0': $t('price'), '1': $t('unit.short.' + vehicle.fuelUnitDetail.key) })"
|
||||
><p class="control">
|
||||
<span class="button is-static">{{ me.currency }}</span>
|
||||
</p>
|
||||
<b-input v-model.number="fillupModel.perUnitPrice" type="number" min="0" step=".001" expanded required></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('totalamountpaid')">
|
||||
<b-field :label="$t('totalamountpaid')">
|
||||
<p class="control">
|
||||
<span class="button is-static">{{ me.currency }}</span>
|
||||
</p>
|
||||
<b-input v-model.number="fillupModel.totalAmount" type="number" min="0" step=".001" expanded required></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('odometer')">
|
||||
<b-field :label="$t('odometer')">
|
||||
<p class="control">
|
||||
<span class="button is-static">{{ $t('unit.short.' + me.distanceUnitDetail.key) }}</span>
|
||||
</p>
|
||||
@@ -265,10 +268,10 @@ export default {
|
||||
<b-switch v-model="showMore">{{ $t('fillmoredetails') }}</b-switch>
|
||||
</b-field>
|
||||
<fieldset v-if="showMore">
|
||||
<b-field :label="this.$t('fillingstation')">
|
||||
<b-field :label="$t('fillingstation')">
|
||||
<b-input v-model="fillupModel.fillingStation" type="text" expanded></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('comments')">
|
||||
<b-field :label="$t('comments')">
|
||||
<b-input v-model="fillupModel.comments" type="textarea" expanded></b-input>
|
||||
</b-field>
|
||||
</fieldset>
|
||||
@@ -277,7 +280,15 @@ export default {
|
||||
</b-field>
|
||||
<br />
|
||||
<b-field>
|
||||
<b-button tag="input" native-type="submit" :disabled="tryingToCreate" type="is-primary" :value="this.$t('save')" :label="this.$t('createfillup')" expanded> </b-button>
|
||||
<b-button
|
||||
tag="button"
|
||||
native-type="submit"
|
||||
:disabled="tryingToCreate"
|
||||
type="is-primary"
|
||||
:value="$t('save')"
|
||||
:label="$t('createfillup')"
|
||||
expanded
|
||||
/>
|
||||
<p v-if="authError">
|
||||
There was an error logging in to your account.
|
||||
</p>
|
||||
|
||||
@@ -134,47 +134,55 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
<form @submit.prevent="createVehicle">
|
||||
<b-field :label="this.$t('nickname') + `*`">
|
||||
<b-field :label="$t('nickname') + `*`">
|
||||
<b-input v-model="vehicleModel.nickname" type="text" expanded required></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('registration') + `*`">
|
||||
<b-field :label="$t('registration') + `*`">
|
||||
<b-input v-model="vehicleModel.registration" type="text" expanded required></b-input>
|
||||
</b-field>
|
||||
<b-field label="VIN">
|
||||
<b-field label="VIN">
|
||||
<b-input v-model="vehicleModel.vin" type="text" expanded></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('fueltype') + `*`">
|
||||
<b-select v-model.number="vehicleModel.fuelType" :placeholder="this.$t('fueltype')" required expanded>
|
||||
<b-field :label="$t('fueltype') + `*`">
|
||||
<b-select v-model.number="vehicleModel.fuelType" :placeholder="$t('fueltype')" required expanded>
|
||||
<option v-for="(option, key) in fuelTypeMasters" :key="key" :value="key">
|
||||
{{ $t('fuel.' + option.key) }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
|
||||
<b-field :label="this.$t('fuelunit') + `*`">
|
||||
<b-select v-model.number="vehicleModel.fuelUnit" :placeholder="this.$t('fuelunit')" required expanded>
|
||||
<b-field :label="$t('fuelunit') + `*`">
|
||||
<b-select v-model.number="vehicleModel.fuelUnit" :placeholder="$t('fuelunit')" required expanded>
|
||||
<option v-for="(option, key) in fuelUnitMasters" :key="key" :value="key">
|
||||
{{ $t('unit.long.' + option.key) }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
|
||||
<b-field :label="this.$t('make') + `*`">
|
||||
<b-field :label="$t('make') + `*`">
|
||||
<b-input v-model="vehicleModel.make" type="text" required expanded></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('model') + `*`">
|
||||
<b-field :label="$t('model') + `*`">
|
||||
<b-input v-model="vehicleModel.model" type="text" required expanded></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('yearmanufacture') + `*`">
|
||||
<b-field :label="$t('yearmanufacture') + `*`">
|
||||
<b-input v-model.number="vehicleModel.yearOfManufacture" type="number" expanded number></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('yearmanufacture')">
|
||||
<b-field :label="$t('enginesize')">
|
||||
<b-input v-model.number="vehicleModel.engineSize" type="number" expanded number></b-input>
|
||||
</b-field>
|
||||
|
||||
<br />
|
||||
<b-field>
|
||||
<b-button tag="input" native-type="submit" :disabled="tryingToCreate" type="is-primary" :value="this.$t('save')" :label="this.$t('createvehicle')" expanded>
|
||||
<b-button
|
||||
tag="button"
|
||||
native-type="submit"
|
||||
:disabled="tryingToCreate"
|
||||
type="is-primary"
|
||||
:value="$t('save')"
|
||||
:label="$t('createvehicle')"
|
||||
expanded
|
||||
>
|
||||
<BaseIcon v-if="tryingToCreate" name="sync" spin />
|
||||
</b-button>
|
||||
<p v-if="authError">
|
||||
|
||||
172
ui/src/router/views/import-drivvo.vue
Normal file
172
ui/src/router/views/import-drivvo.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<script>
|
||||
import Layout from '@layouts/main.vue'
|
||||
import { mapState } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
page: {
|
||||
title: 'Import Drivvo',
|
||||
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: [],
|
||||
importLocation: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('utils', ['isMobile']),
|
||||
...mapState('vehicles', ['vehicles']),
|
||||
uploadButtonLabel() {
|
||||
if (this.isMobile) {
|
||||
if (this.file == null) {
|
||||
return 'Choose Photo'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
} else {
|
||||
if (this.file == null) {
|
||||
return 'Choose CSV'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.myVehicles = this.vehicles
|
||||
},
|
||||
methods: {
|
||||
importDrivvo() {
|
||||
console.log('Import from drivvo')
|
||||
if (this.file == null) {
|
||||
return
|
||||
}
|
||||
this.tryingToCreate = true
|
||||
this.errorMessage = ''
|
||||
const formData = new FormData()
|
||||
formData.append('vehicleID', this.selectedVehicle)
|
||||
formData.append('importLocation', this.importLocation)
|
||||
formData.append('file', this.file, this.file.name)
|
||||
axios
|
||||
.post(`/api/import/drivvo`, formData)
|
||||
.then((data) => {
|
||||
this.$buefy.toast.open({
|
||||
message: 'Data Imported Successfully',
|
||||
type: 'is-success',
|
||||
duration: 3000,
|
||||
})
|
||||
this.file = null
|
||||
setTimeout(() => this.$router.push({ name: 'home' }), 1000)
|
||||
})
|
||||
.catch((ex) => {
|
||||
this.$buefy.toast.open({
|
||||
duration: 5000,
|
||||
message: 'There was some issue with importing the file. Please check the error message',
|
||||
position: 'is-bottom',
|
||||
type: 'is-danger',
|
||||
})
|
||||
if (ex.response && ex.response.data.errors) {
|
||||
this.errors = ex.response.data.errors
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.tryingToCreate = false
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Layout>
|
||||
<div class="columns box">
|
||||
<div class="column">
|
||||
<h1 class="title">Import from Drivvo</h1>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="subtitle"> Steps to import data from Drivvo</p>
|
||||
<ol>
|
||||
<li>Export your data from Drivvo in the CSV format.</li>
|
||||
<li>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</li>
|
||||
<li
|
||||
>Make sure that the <u>Currency</u> and <u>Distance Unit</u> are set correctly in Hammond. Drivvo does not include this information in
|
||||
their export, instead Hammond will use the values set for the user.</li
|
||||
>
|
||||
<li>Similiarly, make sure that the <u>Fuel Unit</u> and <u>Fuel Type</u> are correctly set in the Vehicle.</li>
|
||||
<li>Once you have checked all these points, select the vehicle and import the CSV below.</li>
|
||||
<li><b>Make sure that you do not import the file again as that will create repeat entries.</b></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
><b>PS:</b> If you have <em>'income'</em> and <em>'trips'</em> in your export, they will not be imported to Hammond. The fields
|
||||
<em>'Second fuel'</em> and <em>'Third fuel'</em> are are are also ignored as the use case for these is not understood by us. If you have a use
|
||||
case for this, please open a issue on
|
||||
<a href="https://github.com/akhilrex/hammond/issues">issue tracker</a>
|
||||
</p>
|
||||
<div class="section box">
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-full"> <p class="subtitle">Choose the vehicle, then select the Drivvo CSV and press the import button.</p></div>
|
||||
<div class="column is-full is-flex is-align-content-center">
|
||||
<form @submit.prevent="importDrivvo">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<b-field label="Vehicle" label-position="on-border">
|
||||
<b-select v-model="selectedVehicle" placeholder="Select Vehicle" required>
|
||||
<option v-for="vehicle in myVehicles" :key="vehicle.id" :value="vehicle.id">{{ vehicle.nickname }}</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
</div>
|
||||
<div class="column">
|
||||
<b-field>
|
||||
<b-tooltip label="Whether to import the location for fillups and services or not." multilined>
|
||||
<b-checkbox v-model="importLocation">Import Location?</b-checkbox>
|
||||
</b-tooltip>
|
||||
</b-field>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<b-field class="file is-primary" :class="{ 'has-name': !!file }">
|
||||
<b-upload v-model="file" class="file-label" accept=".csv" required>
|
||||
<span class="file-cta">
|
||||
<b-icon class="file-icon" icon="upload"></b-icon>
|
||||
<span class="file-label">{{ uploadButtonLabel }}</span>
|
||||
</span>
|
||||
<span v-if="file" class="file-name" :class="isMobile ? 'file-name-mobile' : 'file-name-desktop'">
|
||||
{{ file.name }}
|
||||
</span>
|
||||
</b-upload>
|
||||
</b-field>
|
||||
</div>
|
||||
<div class="column">
|
||||
<b-button tag="button" native-type="submit" :disabled="tryingToCreate" type="is-primary" class="control">
|
||||
Import
|
||||
</b-button>
|
||||
</div></div
|
||||
>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<b-message v-if="errors.length" type="is-danger">
|
||||
<ul>
|
||||
<li v-for="error in errors" :key="error">{{ error }}</li>
|
||||
</ul>
|
||||
</b-message>
|
||||
</Layout>
|
||||
</template>
|
||||
@@ -9,6 +9,19 @@ export default {
|
||||
meta: [{ name: 'description', content: 'The Import Fuelly page.' }],
|
||||
},
|
||||
components: { Layout },
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
file: null,
|
||||
tryingToCreate: false,
|
||||
errors: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('utils', ['isMobile']),
|
||||
uploadButtonLabel() {
|
||||
@@ -27,19 +40,6 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
file: null,
|
||||
tryingToCreate: false,
|
||||
errors: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
importFuelly() {
|
||||
if (this.file == null) {
|
||||
@@ -58,6 +58,7 @@ export default {
|
||||
duration: 3000,
|
||||
})
|
||||
this.file = null
|
||||
setTimeout(() => this.$router.push({ name: 'home' }), 1000)
|
||||
})
|
||||
.catch((ex) => {
|
||||
this.$buefy.toast.open({
|
||||
@@ -108,7 +109,7 @@ export default {
|
||||
<div class="columns"
|
||||
><div class="column">
|
||||
<b-field class="file is-primary" :class="{ 'has-name': !!file }">
|
||||
<b-upload v-model="file" class="file-label" accept=".csv">
|
||||
<b-upload v-model="file" class="file-label" accept=".csv" required>
|
||||
<span class="file-cta">
|
||||
<b-icon class="file-icon" icon="upload"></b-icon>
|
||||
<span class="file-label">{{ uploadButtonLabel }}</span>
|
||||
@@ -120,7 +121,7 @@ export default {
|
||||
</b-field>
|
||||
</div>
|
||||
<div class="column">
|
||||
<b-button tag="input" native-type="submit" :disabled="tryingToCreate" type="is-primary" :value="this.$t('uploadfile')" class="control">
|
||||
<b-button tag="button" native-type="submit" :disabled="tryingToCreate" type="is-primary" class="control">
|
||||
{{ $t('import') }}
|
||||
</b-button>
|
||||
</div></div
|
||||
|
||||
7
ui/src/router/views/import-generic.unit.js
Normal file
7
ui/src/router/views/import-generic.unit.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import ImportGeneric from './import-generic'
|
||||
|
||||
describe('@views/import-generic', () => {
|
||||
it('is a valid view', () => {
|
||||
expect(ImportGeneric).toBeAViewComponent()
|
||||
})
|
||||
})
|
||||
411
ui/src/router/views/import-generic.vue
Normal file
411
ui/src/router/views/import-generic.vue
Normal file
@@ -0,0 +1,411 @@
|
||||
<script>
|
||||
import Layout from '@layouts/main.vue'
|
||||
import { mapState } from 'vuex'
|
||||
import axios from 'axios'
|
||||
import Papa from 'papaparse'
|
||||
|
||||
export default {
|
||||
page: {
|
||||
title: 'Generic Import',
|
||||
meta: [{ name: 'description', content: 'The Generic Import page.' }],
|
||||
},
|
||||
components: { Layout },
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
file: null,
|
||||
tryingToCreate: false,
|
||||
errors: [],
|
||||
papaConfig: { dynamicTyping: true, skipEmptyLines: true, complete: this.assignResults },
|
||||
fileData: null,
|
||||
fileHeadings: null,
|
||||
myVehicles: [],
|
||||
selectedVehicle: null,
|
||||
invertFullTank: null,
|
||||
filledValueString: '',
|
||||
notFilledValueString: '',
|
||||
isFullTankString: false,
|
||||
fileHeadingMap: {
|
||||
fuelQuantity: null,
|
||||
perUnitPrice: null,
|
||||
totalAmount: null,
|
||||
odoReading: null,
|
||||
isTankFull: null,
|
||||
hasMissedFillup: null,
|
||||
comments: [], // [int]
|
||||
fillingStation: null,
|
||||
date: null,
|
||||
fuelSubType: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('utils', ['isMobile']),
|
||||
...mapState('vehicles', ['vehicles']),
|
||||
uploadButtonLabel() {
|
||||
if (this.isMobile) {
|
||||
if (this.file == null) {
|
||||
return this.$t('choosephoto')
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
} else {
|
||||
if (this.file == null) {
|
||||
return this.$t('choosefile')
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.myVehicles = this.vehicles
|
||||
},
|
||||
methods: {
|
||||
assignResults(results, file) {
|
||||
this.fileData = results.data
|
||||
this.fileHeadings = results.data[0]
|
||||
},
|
||||
parseCSV() {
|
||||
if (this.file == null) {
|
||||
return
|
||||
}
|
||||
this.errorMessage = ''
|
||||
Papa.parse(this.file, this.papaConfig)
|
||||
},
|
||||
getUsedHeadings() {
|
||||
return Object.keys(this.fileHeadingMap).filter((k) => this.fileHeadingMap[k] != null) // filter non-null properties
|
||||
},
|
||||
getTimezone() {
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
},
|
||||
csvToJson() {
|
||||
const data = []
|
||||
const headings = this.getUsedHeadings().reduce((a, k) => ({ ...a, [k]: this.fileHeadingMap[k] }), {}) // create new object from filter
|
||||
const comments = (row) => {
|
||||
return this.fileHeadingMap.comments.reduce((a, fi) => {
|
||||
// TODO: sanitize to prevent XSS
|
||||
return `${a}${this.fileHeadings[fi]}: ${row[fi]}\n`
|
||||
}, '')
|
||||
}
|
||||
const calculateTotal = (row) => {
|
||||
return this.fileHeadingMap.totalAmount === -1
|
||||
? row[this.fileHeadingMap.fuelQuantity] * row[this.fileHeadingMap.perUnitPrice]
|
||||
: row[this.fileHeadingMap.totalAmount]
|
||||
}
|
||||
|
||||
const setFullTank = (row) => {
|
||||
if (row[this.fileHeadingMap.isTankFull].toLowerCase() === this.filledValueString.toLowerCase()) {
|
||||
return true
|
||||
} else if (row[this.fileHeadingMap.isTankFull].toLowerCase() === this.notFilledValueString.toLowerCase()) {
|
||||
return false
|
||||
} else {
|
||||
// TODO: need to handle errors better
|
||||
throw Error
|
||||
}
|
||||
}
|
||||
|
||||
for (let r = 1; r < this.fileData.length; r++) {
|
||||
const row = this.fileData[r]
|
||||
const item = {}
|
||||
Object.keys(headings).forEach((k) => {
|
||||
if (k === 'comments') {
|
||||
item[k] = comments(row)
|
||||
} else if (k === 'totalAmount') {
|
||||
item[k] = calculateTotal(row)
|
||||
} else if (k === 'isTankFull') {
|
||||
if (this.isFullTankString) {
|
||||
item[k] = setFullTank(row)
|
||||
} else {
|
||||
if (this.invertFullTank) {
|
||||
item[k] = Boolean(!row[headings[k]])
|
||||
} else {
|
||||
item[k] = Boolean(row[headings[k]])
|
||||
}
|
||||
}
|
||||
} else if (k === 'hasMissedFillup') {
|
||||
// TODO: need to account for this field being a string
|
||||
item[k] = Boolean(row[headings[k]])
|
||||
} else if (k === 'date') {
|
||||
item[k] = new Date(row[headings[k]]).toISOString()
|
||||
} else {
|
||||
item[k] = row[headings[k]]
|
||||
}
|
||||
})
|
||||
data.push(item)
|
||||
}
|
||||
return data
|
||||
},
|
||||
importData() {
|
||||
if (this.errors.length === 0) {
|
||||
try {
|
||||
const content = {
|
||||
data: this.csvToJson(),
|
||||
vehicleId: this.selectedVehicle.id,
|
||||
timezone: this.getTimezone(),
|
||||
}
|
||||
axios
|
||||
.post('/api/import/generic', content)
|
||||
.then((data) => {
|
||||
this.$buefy.toast.open({
|
||||
message: this.$t('importsuccessfull'),
|
||||
type: 'is-success',
|
||||
duration: 3000,
|
||||
})
|
||||
setTimeout(() => this.$router.push({ name: 'home' }), 1000)
|
||||
})
|
||||
.catch((ex) => {
|
||||
this.$buefy.toast.open({
|
||||
duration: 5000,
|
||||
message: this.$t('importerror'),
|
||||
position: 'is-bottom',
|
||||
type: 'is-danger',
|
||||
})
|
||||
console.log(ex)
|
||||
if (ex.response && ex.response.data.error) {
|
||||
this.errors.push(ex.response.data.error)
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
// TODO: handle error
|
||||
this.errors.push(e)
|
||||
}
|
||||
} else {
|
||||
this.errors.push('fix errors')
|
||||
}
|
||||
},
|
||||
checkFieldString() {
|
||||
const tankFull = this.fileData[1][this.fileHeadingMap.isTankFull]
|
||||
if (typeof tankFull !== 'boolean' && typeof tankFull === 'string') {
|
||||
this.isFullTankString = true
|
||||
}
|
||||
},
|
||||
clearHeadingProperty(property) {
|
||||
if (property === 'comments') {
|
||||
this.fileHeadingMap[property] = []
|
||||
} else {
|
||||
this.fileHeadingMap[property] = null
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Layout>
|
||||
<div class="columns box">
|
||||
<div class="column">
|
||||
<h1 class="title">{{ $t('importgeneric') }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div v-if="fileData === null" class="columns">
|
||||
<div class="column">
|
||||
<p class="subtitle"> {{ $t('stepstoimport', { name: 'CSV' }) }}</p>
|
||||
<ol>
|
||||
<!-- <li>{{ $t('importhintcreatecsv', { 'name': 'Fuelly' }) }} <a href="http://docs.fuelly.com/acar-import-export-center" target="_nofollow">{{ $t('here') }}</a>.</li> -->
|
||||
<li>{{ $t('importgenerichintdata') }}</li>
|
||||
<li>{{ $t('importhintvehiclecreated') }}</li>
|
||||
<li v-html="$t('importhintcurrdist')"></li>
|
||||
<li v-html="$t('importhintunits')"></li>
|
||||
<li>
|
||||
<b>{{ $t('dontimportagain') }}</b>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="fileData === null" class="section box">
|
||||
<div class="columns">
|
||||
<div class="column is-two-thirds">
|
||||
<p class="subtitle">{{ $t('choosedatafile') }}</p>
|
||||
</div>
|
||||
<div class="column is-one-third is-flex is-align-content-center">
|
||||
<form @submit.prevent="parseCSV">
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<b-field class="file is-primary" :class="{ 'has-name': !!file }">
|
||||
<b-upload v-model="file" class="file-label" accept=".csv" required>
|
||||
<span class="file-cta">
|
||||
<b-icon class="file-icon" icon="upload"></b-icon>
|
||||
<span class="file-label">{{ uploadButtonLabel }}</span>
|
||||
</span>
|
||||
<span v-if="file" class="file-name" :class="isMobile ? 'file-name-mobile' : 'file-name-desktop'">
|
||||
{{ file.name }}
|
||||
</span>
|
||||
</b-upload>
|
||||
</b-field>
|
||||
</div>
|
||||
<div class="column">
|
||||
<b-button tag="button" native-type="submit" type="is-primary" class="control">
|
||||
{{ $t('import') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="columns">
|
||||
<div class="column">
|
||||
<p class="subtitle">Map Fields</p>
|
||||
<form class="" @submit.prevent="importData">
|
||||
<b-field :label="$t('selectvehicle')">
|
||||
<b-select v-model="selectedVehicle" :placeholder="$t('vehicle')" required expanded>
|
||||
<option v-for="option in myVehicles" :key="option.id" :value="option">
|
||||
{{ option.nickname }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<span v-if="selectedVehicle !== null">
|
||||
<b-field :label="$t('fillupdate')">
|
||||
<b-select v-model="fileHeadingMap.date" required expanded>
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field>
|
||||
<template v-slot:label>
|
||||
{{ $t('fuelsubtype') }}
|
||||
<b-tooltip type="is-dark" label="Clear selection">
|
||||
<b-button
|
||||
type="is-ghost"
|
||||
size="is-small"
|
||||
icon-pack="fas"
|
||||
icon-right="arrow-rotate-left"
|
||||
@click="clearHeadingProperty('fuelSubType')"
|
||||
></b-button>
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="fileHeadingMap.fuelSubType" expanded>
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="$t('quantity')">
|
||||
<b-select v-model="fileHeadingMap.fuelQuantity" expanded required>
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="$t('per', { '0': $t('price'), '1': $t('unit.short.' + selectedVehicle.fuelUnitDetail.key) })">
|
||||
<b-select v-model.number="fileHeadingMap.perUnitPrice" type="number" min="0" step=".001" expanded required>
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="$t('totalamountpaid')">
|
||||
<b-select v-model.number="fileHeadingMap.totalAmount" expanded required>
|
||||
<option value="-1">Calculated</option>
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="$t('odometer')">
|
||||
<b-select v-model.number="fileHeadingMap.odoReading" expanded required>
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="$t('tankpartialfull')">
|
||||
<b-radio-button v-model="invertFullTank" native-value="false">{{ $t('fulltank') }}</b-radio-button>
|
||||
<b-radio-button v-model="invertFullTank" native-value="true">{{ $t('partialfillup') }}</b-radio-button>
|
||||
</b-field>
|
||||
<b-field>
|
||||
<b-select v-model="fileHeadingMap.isTankFull" required @input="checkFieldString">
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<span v-if="isFullTankString === true" required>
|
||||
<b-field label="Value when tank is filled">
|
||||
<b-input v-model="filledValueString"></b-input>
|
||||
</b-field>
|
||||
<b-field label="Value when tank was not completely filled">
|
||||
<b-input v-model="notFilledValueString"></b-input>
|
||||
</b-field>
|
||||
</span>
|
||||
<b-field>
|
||||
<template v-slot:label>
|
||||
{{ $t('missedfillup') }}
|
||||
<b-tooltip type="is-dark" label="Clear selection">
|
||||
<b-button
|
||||
type="is-ghost"
|
||||
size="is-small"
|
||||
icon-pack="fas"
|
||||
icon-right="arrow-rotate-left"
|
||||
@click="clearHeadingProperty('hasMissedFillup')"
|
||||
></b-button>
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="fileHeadingMap.hasMissedFillup">
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field>
|
||||
<template v-slot:label>
|
||||
{{ $t('fillingstation') }}
|
||||
<b-tooltip type="is-dark" label="Clear selection">
|
||||
<b-button
|
||||
type="is-ghost"
|
||||
size="is-small"
|
||||
icon-pack="fas"
|
||||
icon-right="arrow-rotate-left"
|
||||
@click="clearHeadingProperty('fillingStation')"
|
||||
></b-button>
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="fileHeadingMap.fillingStation">
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field>
|
||||
<template v-slot:label>
|
||||
{{ $t('comments') }}
|
||||
<b-tooltip type="is-dark" label="Clear selection">
|
||||
<b-button
|
||||
type="is-ghost"
|
||||
size="is-small"
|
||||
icon-pack="fas"
|
||||
icon-right="arrow-rotate-left"
|
||||
@click="clearHeadingProperty('comments')"
|
||||
></b-button>
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="fileHeadingMap.comments" type="textarea" multiple expanded>
|
||||
<option v-for="(option, index) in fileHeadings" :key="index" :value="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<br />
|
||||
<b-field>
|
||||
<b-button tag="button" native-type="submit" type="is-primary" :value="$t('save')" :label="$t('import')" expanded />
|
||||
<p v-if="authError"> There was an error logging in to your account. </p>
|
||||
</b-field>
|
||||
</span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<b-message v-if="errors.length" type="is-danger">
|
||||
<ul>
|
||||
<li v-for="error in errors" :key="error">{{ error }}</li>
|
||||
</ul>
|
||||
</b-message>
|
||||
</Layout>
|
||||
</template>
|
||||
@@ -18,19 +18,41 @@ export default {
|
||||
|
||||
<template>
|
||||
<Layout>
|
||||
<div class="columns box"
|
||||
><div class="column">
|
||||
<div class="columns box">
|
||||
<div class="column">
|
||||
<h1 class="title">{{ $t('importdata') }}</h1>
|
||||
<p class="subtitle">{{ $t('importdatadesc') }}</p>
|
||||
</div></div
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="columns">
|
||||
<div class="box column is-one-third" to="/import-fuelly">
|
||||
<h1 class="title">Fuelly</h1>
|
||||
<p>{{ $t('importcsv', { 'name': 'Fuelly' }) }}</p>
|
||||
<br />
|
||||
<b-button type="is-primary" tag="router-link" to="/import/fuelly">{{ $t('import') }}</b-button>
|
||||
<div class="column is-one-third">
|
||||
<div class="box">
|
||||
<h1 class="title">Fuelly</h1>
|
||||
<p>If you have been using Fuelly to store your vehicle data, export the CSV file from Fuelly and click here to
|
||||
import.</p>
|
||||
<br />
|
||||
<b-button type="is-primary" tag="router-link" to="/import/fuelly">{{ $t('import') }}</b-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-one-third" to="/import-fuelly">
|
||||
<div class="box">
|
||||
<h1 class="title">Drivvo</h1>
|
||||
<p>{{ $t('importcsv', { 'name': 'Fuelly' }) }}</p>
|
||||
<br />
|
||||
<b-button type="is-primary" tag="router-link" to="/import/drivvo">{{ $t('import') }}</b-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="column is-one-third" to="/import-generic">
|
||||
<div class="box">
|
||||
<h1 class="title">{{ $t('importgeneric') }}</h1>
|
||||
<p>{{ $t('importgenericdesc') }}</p>
|
||||
<br />
|
||||
<b-button type="is-primary" tag="router-link" to="/import/generic">{{ $t('import') }}</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
@@ -187,7 +187,7 @@ export default {
|
||||
{{ connectionError }}
|
||||
</b-notification>
|
||||
|
||||
<b-field addons :label="this.$t('mysqlconnstr')">
|
||||
<b-field addons :label="$t('mysqlconnstr')">
|
||||
<b-input v-model="url" required></b-input>
|
||||
</b-field>
|
||||
|
||||
@@ -200,20 +200,20 @@ export default {
|
||||
<div v-if="migrationMode === 'fresh'" class="box content">
|
||||
<h1 class="title">{{ $t('init.fresh.setupadminuser') }}</h1>
|
||||
<form @submit.prevent="register">
|
||||
<b-field :label="this.$t('init.fresh.yourname')">
|
||||
<b-field :label="$t('init.fresh.yourname')">
|
||||
<b-input v-model="registerModel.name" required></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('init.fresh.youremail')">
|
||||
<b-field :label="$t('init.fresh.youremail')">
|
||||
<b-input v-model="registerModel.email" type="email" required></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('init.fresh.yourpassword')">
|
||||
<b-field :label="$t('init.fresh.yourpassword')">
|
||||
<b-input v-model="registerModel.password" type="password" required minlength="8" password-reveal></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('currency')">
|
||||
<b-field :label="$t('currency')">
|
||||
<b-autocomplete
|
||||
v-model="registerModel.currency"
|
||||
:custom-formatter="formatCurrency"
|
||||
:placeholder="this.$t('currency')"
|
||||
:placeholder="$t('currency')"
|
||||
:data="filteredCurrencyMasters"
|
||||
:keep-first="true"
|
||||
:open-on-focus="true"
|
||||
@@ -221,8 +221,8 @@ export default {
|
||||
@select="(option) => (selected = option)"
|
||||
></b-autocomplete>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('distanceunit')">
|
||||
<b-select v-model.number="registerModel.distanceUnit" :placeholder="this.$t('distanceunit')" required expanded>
|
||||
<b-field :label="$t('distanceunit')">
|
||||
<b-select v-model.number="registerModel.distanceUnit" :placeholder="$t('distanceunit')" required expanded>
|
||||
<option v-for="(option, key) in distanceUnitMasters" :key="key" :value="key">
|
||||
{{ `${$t('unit.long.' + option.key)} (${$t('unit.short.' + option.key)})` }}
|
||||
</option>
|
||||
@@ -230,7 +230,7 @@ export default {
|
||||
</b-field>
|
||||
<br />
|
||||
<div class="buttons">
|
||||
<b-button type="is-primary" native-type="submit" tag="input" :value="this.$t('save')"></b-button>
|
||||
<b-button type="is-primary" native-type="submit" tag="button" :value="$t('save')">{{ $t('save') }}</b-button>
|
||||
|
||||
<b-button type="is-danger is-light" @click="resetMigrationMode">{{ $t('cancel') }}</b-button>
|
||||
</div>
|
||||
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
<b-field :label="$t('password')">
|
||||
<b-input v-model="password" tag="b-input" name="password" type="password" :placeholder="placeholders.password" />
|
||||
</b-field>
|
||||
<b-button tag="input" native-type="submit" :value="$t('login')" :disabled="tryingToLogIn" type="is-primary">
|
||||
<b-button tag="button" native-type="submit" :disabled="tryingToLogIn" type="is-primary">
|
||||
<BaseIcon v-if="tryingToLogIn" name="sync" spin />
|
||||
<span v-else>
|
||||
{{ $t('login') }}
|
||||
|
||||
@@ -167,7 +167,7 @@ export default {
|
||||
</b-field>
|
||||
<br />
|
||||
<b-field>
|
||||
<b-button tag="input" native-type="submit" :disabled="tryingToSave" type="is-primary" :value="$t('save')" expanded> </b-button>
|
||||
<b-button tag="button" native-type="submit" :disabled="tryingToSave" type="is-primary" expanded> {{ $t('save') }} </b-button>
|
||||
</b-field>
|
||||
</form>
|
||||
</div>
|
||||
@@ -185,7 +185,8 @@ export default {
|
||||
</b-field>
|
||||
<p v-if="!passwordValid" class="help is-danger">{{ $t('passworddontmatch') }}</p>
|
||||
<b-field>
|
||||
<b-button tag="input" native-type="submit" :disabled="!passwordValid" type="is-primary" :value="$t('changepassword')" expanded>
|
||||
<b-button tag="button" native-type="submit" :disabled="!passwordValid" type="is-primary" expanded>
|
||||
{{ $t('changepassword') }}
|
||||
</b-button>
|
||||
</b-field>
|
||||
</form>
|
||||
|
||||
@@ -72,15 +72,15 @@ export default {
|
||||
</div>
|
||||
<br />
|
||||
<form class="" @submit.prevent="saveSettings">
|
||||
<b-field :label="this.$t('currency')">
|
||||
<b-select v-model="settingsModel.currency" :placeholder="this.$t('currency')" required expanded>
|
||||
<b-field :label="$t('currency')">
|
||||
<b-select v-model="settingsModel.currency" :placeholder="$t('currency')" required expanded>
|
||||
<option v-for="option in currencyMasters" :key="option.code" :value="option.code">
|
||||
{{ `${option.namePlural} (${option.code})` }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('distanceunit')">
|
||||
<b-select v-model.number="settingsModel.distanceUnit" :placeholder="this.$t('distanceunit')" required expanded>
|
||||
<b-field :label="$t('distanceunit')">
|
||||
<b-select v-model.number="settingsModel.distanceUnit" :placeholder="$t('distanceunit')" required expanded>
|
||||
<option v-for="(option, key) in distanceUnitMasters" :key="key" :value="key">
|
||||
{{ `${$t('unit.long.' + option.key)} (${$t('unit.short.' + option.key)})` }}
|
||||
</option>
|
||||
@@ -88,7 +88,7 @@ export default {
|
||||
</b-field>
|
||||
<br />
|
||||
<b-field>
|
||||
<b-button tag="input" native-type="submit" :disabled="tryingToSave" type="is-primary" :value="this.$t('save')" expanded> </b-button>
|
||||
<b-button tag="button" native-type="submit" :disabled="tryingToSave" type="is-primary" expanded> {{ $t('save') }}</b-button>
|
||||
</b-field>
|
||||
</form>
|
||||
</Layout>
|
||||
|
||||
@@ -138,13 +138,13 @@ export default {
|
||||
<div v-if="showUserForm" class="box content">
|
||||
<h1 class="title">{{ $t('createnewuser') }}</h1>
|
||||
<form @submit.prevent="register">
|
||||
<b-field :label="this.$t('name')">
|
||||
<b-field :label="$t('name')">
|
||||
<b-input v-model="registerModel.name" required></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('email')">
|
||||
<b-field :label="$t('email')">
|
||||
<b-input v-model="registerModel.email" type="email" required></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('password')">
|
||||
<b-field :label="$t('password')">
|
||||
<b-input
|
||||
v-model="registerModel.password"
|
||||
type="password"
|
||||
@@ -153,24 +153,24 @@ export default {
|
||||
password-reveal
|
||||
></b-input>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('role')">
|
||||
<b-select v-model.number="registerModel.role" :placeholder="this.$t('placeholder')" required expanded>
|
||||
<b-field :label="$t('role')">
|
||||
<b-select v-model.number="registerModel.role" :placeholder="$t('role')" required expanded>
|
||||
<option v-for="(option, key) in roleMasters" :key="key" :value="key">
|
||||
{{ `test` }}
|
||||
{{ `${option.key}` }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('currency')">
|
||||
<b-select v-model="registerModel.currency" :placeholder="this.$t('currency')" required expanded>
|
||||
<b-field :label="$t('currency')">
|
||||
<b-select v-model="registerModel.currency" :placeholder="$t('currency')" required expanded>
|
||||
<option v-for="option in currencyMasters" :key="option.code" :value="option.code">
|
||||
{{ `${option.namePlural} (${option.code})` }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="this.$t('distanceunit')">
|
||||
<b-field :label="$t('distanceunit')">
|
||||
<b-select
|
||||
v-model.number="registerModel.distanceUnit"
|
||||
:placeholder="this.$t('distanceunit')"
|
||||
:placeholder="$t('distanceunit')"
|
||||
required
|
||||
expanded
|
||||
>
|
||||
@@ -181,28 +181,28 @@ export default {
|
||||
</b-field>
|
||||
<br />
|
||||
<div class="buttons">
|
||||
<b-button type="is-primary" native-type="submit" tag="input" :value="this.$t('save')"></b-button>
|
||||
<b-button type="is-primary" native-type="submit" tag="button">{{ $t('save') }}</b-button>
|
||||
|
||||
<b-button type="is-danger is-light" @click="resetUserForm">{{ $t('cancel') }}</b-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<b-table :data="users" hoverable mobile-cards detail-key="id" paginated per-page="10" :row-class="(row, index) => row.isDisabled && 'is-disabled'">
|
||||
<b-table-column v-slot="props" field="name" :label="this.$t('name')">
|
||||
<b-table-column v-slot="props" field="name" :label="$t('name')">
|
||||
{{ `${props.row.name}` }} <template v-if="props.row.id === user.id">({{ $t('you') }})</template>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="email" :label="this.$t('email')">
|
||||
<b-table-column v-slot="props" field="email" :label="$t('email')">
|
||||
{{ `${props.row.email}` }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="role" :label="this.$t('role')">
|
||||
<b-table-column v-slot="props" field="role" :label="$t('role')">
|
||||
{{ `${$t('roles.' + props.row.roleDetail.key)}` }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="createdAt" :label="this.$t('created')" sortable date>
|
||||
<b-table-column v-slot="props" field="createdAt" :label="$t('created')" sortable date>
|
||||
{{ formatDate(props.row.createdAt) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props">
|
||||
<b-button type="is-success" v-if="props.row.isDisabled && props.row.roleDetail.key === 'USER'" @click="changeDisabledStatus(props.row.id, false)">{{ $t('enable') }}</b-button>
|
||||
<b-button type="is-danger" v-if="!props.row.isDisabled && props.row.roleDetail.key === 'USER'" @click="changeDisabledStatus(props.row.id, true)">{{ $t('disable') }}</b-button>
|
||||
<b-button v-if="props.row.isDisabled && props.row.roleDetail.key === 'USER'" type="is-success" @click="changeDisabledStatus(props.row.id, false)">{{ $t('enable') }}</b-button>
|
||||
<b-button v-if="!props.row.isDisabled && props.row.roleDetail.key === 'USER'" type="is-danger" @click="changeDisabledStatus(props.row.id, true)">{{ $t('disable') }}</b-button>
|
||||
</b-table-column>
|
||||
</b-table>
|
||||
</div>
|
||||
|
||||
@@ -48,6 +48,12 @@ export default {
|
||||
{ label: this.$t('alltime'), value: 'all_time' },
|
||||
],
|
||||
dateRangeOption: 'past_30_days',
|
||||
mileageOptions: [
|
||||
{ label: 'L/100km', value: 'litre_100km' },
|
||||
{ label: 'km/L', value: 'km_litre' },
|
||||
{ label: 'mpg', value: 'mpg' },
|
||||
],
|
||||
mileageOption: 'litre_100km',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -86,7 +92,10 @@ export default {
|
||||
},
|
||||
{
|
||||
label: this.$t('avgfuelcost'),
|
||||
value: this.$t('per', {'0': this.formatCurrency(x.avgFuelPrice, x.currency), '1': this.$t('unit.short.' + this.vehicle.fuelUnitDetail.key)}),
|
||||
value: this.$t('per', {
|
||||
0: this.formatCurrency(x.avgFuelPrice, x.currency),
|
||||
1: this.$t('unit.short.' + this.vehicle.fuelUnitDetail.key),
|
||||
}),
|
||||
},
|
||||
]
|
||||
})
|
||||
@@ -303,15 +312,15 @@ export default {
|
||||
<div class="column is-one-half" :class="isMobile ? 'has-text-centered' : ''">
|
||||
<p class="title">{{ vehicle.nickname }} - {{ vehicle.registration }}</p>
|
||||
<p class="subtitle">
|
||||
{{ [vehicle.make, vehicle.model, this.$t('fuel.' + vehicle.fuelTypeDetail.key)].join(' | ') }}
|
||||
{{ [vehicle.make, vehicle.model, $t('fuel.' + vehicle.fuelTypeDetail.key)].join(' | ') }}
|
||||
|
||||
<template v-if="users.length > 1">
|
||||
| {{ $t("sharedwith") }} :
|
||||
| {{ $t('sharedwith') }} :
|
||||
{{
|
||||
users
|
||||
.map((x) => {
|
||||
if (x.userId === me.id) {
|
||||
return this.$t('you')
|
||||
return $t('you')
|
||||
} else {
|
||||
return x.name
|
||||
}
|
||||
@@ -322,8 +331,8 @@ export default {
|
||||
</p>
|
||||
</div>
|
||||
<div :class="(!isMobile ? 'has-text-right ' : '') + 'column is-one-half buttons'">
|
||||
<b-button type="is-primary" tag="router-link" :to="`/vehicles/${vehicle.id}/fillup`">{{ this.$t('addfillup') }}</b-button>
|
||||
<b-button type="is-primary" tag="router-link" :to="`/vehicles/${vehicle.id}/expense`">{{ this.$t('addexpense') }}</b-button>
|
||||
<b-button type="is-primary" tag="router-link" :to="`/vehicles/${vehicle.id}/fillup`">{{ $t('addfillup') }}</b-button>
|
||||
<b-button type="is-primary" tag="router-link" :to="`/vehicles/${vehicle.id}/expense`">{{ $t('addexpense') }}</b-button>
|
||||
<b-button
|
||||
v-if="vehicle.isOwner"
|
||||
tag="router-link"
|
||||
@@ -333,9 +342,8 @@ export default {
|
||||
props: { vehicle: vehicle },
|
||||
params: { id: vehicle.id },
|
||||
}"
|
||||
>
|
||||
<b-icon pack="fas" icon="edit" type="is-info"> </b-icon
|
||||
></b-button>
|
||||
><b-icon pack="fas" icon="edit" type="is-info"> </b-icon>
|
||||
</b-button>
|
||||
<b-button v-if="vehicle.isOwner" :title="$t('sharevehicle')" @click="showShareVehicleModal">
|
||||
<b-icon pack="fas" icon="user-friends" type="is-info"> </b-icon
|
||||
></b-button>
|
||||
@@ -356,42 +364,42 @@ export default {
|
||||
<h1 class="title is-4">{{ $t('pastfillups') }}</h1>
|
||||
|
||||
<b-table :data="fillups" hoverable mobile-cards :detailed="isMobile" detail-key="id" paginated per-page="10">
|
||||
<b-table-column v-slot="props" field="date" :label="this.$t('date')" :td-attrs="columnTdAttrs" sortable date>
|
||||
<b-table-column v-slot="props" field="date" :label="$t('date')" :td-attrs="columnTdAttrs" sortable date>
|
||||
{{ formatDate(props.row.date) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="fuelSubType" :label="this.$t('fuelsubtype')" :td-attrs="columnTdAttrs">
|
||||
<b-table-column v-slot="props" field="fuelSubType" :label="$t('fuelsubtype')" :td-attrs="columnTdAttrs">
|
||||
{{ props.row.fuelSubType }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="fuelQuantity" :label="this.$t('quantity')" :td-attrs="hiddenMobile" numeric>
|
||||
<b-table-column v-slot="props" field="fuelQuantity" :label="$t('quantity')" :td-attrs="hiddenMobile" numeric>
|
||||
{{ `${props.row.fuelQuantity} ${$t('unit.short.' + props.row.fuelUnitDetail.key)}` }}
|
||||
</b-table-column>
|
||||
<b-table-column
|
||||
v-slot="props"
|
||||
field="perUnitPrice"
|
||||
:label="this.$t('per', { '0': this.$t('price'), '1': this.$t('unit.short.' + vehicle.fuelUnitDetail.key) })"
|
||||
:label="$t('per', { '0': $t('price'), '1': $t('unit.short.' + vehicle.fuelUnitDetail.key) })"
|
||||
:td-attrs="hiddenMobile"
|
||||
numeric
|
||||
sortable
|
||||
>
|
||||
{{ `${formatCurrency(props.row.perUnitPrice, props.row.currency)}` }}
|
||||
</b-table-column>
|
||||
<b-table-column v-if="isMobile" v-slot="props" field="totalAmount" :label="this.$t('total')" :td-attrs="hiddenDesktop" sortable numeric>
|
||||
<b-table-column v-if="isMobile" v-slot="props" field="totalAmount" :label="$t('total')" :td-attrs="hiddenDesktop" sortable numeric>
|
||||
{{ `${me.currency} ${props.row.totalAmount}` }} ({{ `${props.row.fuelQuantity} ${$t('unit.short.' + props.row.fuelUnitDetail.key)}` }} @
|
||||
{{ `${me.currency} ${props.row.perUnitPrice}` }})
|
||||
</b-table-column>
|
||||
<b-table-column v-if="!isMobile" v-slot="props" field="totalAmount" :label="this.$t('total')" :td-attrs="hiddenMobile" sortable numeric>
|
||||
<b-table-column v-if="!isMobile" v-slot="props" field="totalAmount" :label="$t('total')" :td-attrs="hiddenMobile" sortable numeric>
|
||||
{{ `${formatCurrency(props.row.totalAmount, props.row.currency)}` }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" width="20" field="isTankFull" :label="this.$t('fulltank')" :td-attrs="hiddenMobile">
|
||||
<b-table-column v-slot="props" width="20" field="isTankFull" :label="$t('fulltank')" :td-attrs="hiddenMobile">
|
||||
<b-icon pack="fas" :icon="props.row.isTankFull ? 'check' : 'times'" type="is-info"> </b-icon>
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="odoReading" :label="this.$t('odometer')" :td-attrs="hiddenMobile" numeric>
|
||||
<b-table-column v-slot="props" field="odoReading" :label="$t('odometer')" :td-attrs="hiddenMobile" numeric>
|
||||
{{ `${props.row.odoReading} ${$t('unit.short.' + me.distanceUnitDetail.key)}` }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="fillingStation" :label="this.$t('gasstation')" :td-attrs="hiddenMobile">
|
||||
<b-table-column v-slot="props" field="fillingStation" :label="$t('gasstation')" :td-attrs="hiddenMobile">
|
||||
{{ `${props.row.fillingStation}` }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="userId" :label="this.$t('by')" :td-attrs="hiddenMobile">
|
||||
<b-table-column v-slot="props" field="userId" :label="$t('by')" :td-attrs="hiddenMobile">
|
||||
{{ `${props.row.user.name}` }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props">
|
||||
@@ -406,7 +414,10 @@ export default {
|
||||
>
|
||||
<b-icon pack="fas" icon="edit" type="is-info"> </b-icon
|
||||
></b-button>
|
||||
<b-button type="is-ghost" :title="$t('deletefillup')" @click="deleteFillup(props.row.id)">
|
||||
<b-button
|
||||
type="is-ghost"
|
||||
:title="$t('deletefillup')"
|
||||
@click="deleteFillup(props.row.id)">
|
||||
<b-icon pack="fas" icon="trash" type="is-danger"> </b-icon
|
||||
></b-button>
|
||||
</b-table-column>
|
||||
@@ -421,22 +432,22 @@ export default {
|
||||
<h1 class="title is-4">{{ $t('expenses') }}</h1>
|
||||
|
||||
<b-table :data="expenses" hoverable mobile-cards paginated per-page="10">
|
||||
<b-table-column v-slot="props" field="date" :label="this.$t('date')" :td-attrs="columnTdAttrs" date>
|
||||
<b-table-column v-slot="props" field="date" :label="$t('date')" :td-attrs="columnTdAttrs" date>
|
||||
{{ formatDate(props.row.date) }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="expenseType" :label="this.$t('expensetype')">
|
||||
<b-table-column v-slot="props" field="expenseType" :label="$t('expensetype')">
|
||||
{{ `${props.row.expenseType}` }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column v-slot="props" field="amount" :label="this.$t('total')" :td-attrs="hiddenMobile" sortable numeric>
|
||||
<b-table-column v-slot="props" field="amount" :label="$t('total')" :td-attrs="hiddenMobile" sortable numeric>
|
||||
{{ `${formatCurrency(props.row.amount, props.row.currency)}` }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column v-slot="props" field="odoReading" :label="this.$t('odometer')" :td-attrs="columnTdAttrs" numeric>
|
||||
<b-table-column v-slot="props" field="odoReading" :label="$t('odometer')" :td-attrs="columnTdAttrs" numeric>
|
||||
{{ `${props.row.odoReading} ${$t('unit.short.' + me.distanceUnitDetail.key)}` }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column v-slot="props" field="userId" :label="this.$t('by')" :td-attrs="columnTdAttrs">
|
||||
<b-table-column v-slot="props" field="userId" :label="$t('by')" :td-attrs="columnTdAttrs">
|
||||
{{ `${props.row.user.name}` }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props">
|
||||
@@ -461,7 +472,9 @@ export default {
|
||||
<br />
|
||||
<div class="box">
|
||||
<div class="columns">
|
||||
<div class="column is-three-quarters"> <h1 class="title is-4">{{ $t('attachments') }}</h1></div>
|
||||
<div class="column is-three-quarters">
|
||||
<h1 class="title is-4">{{ $t('attachments') }}</h1></div
|
||||
>
|
||||
<div class="column buttons">
|
||||
<b-button type="is-primary" @click="showAttachmentForm = true">
|
||||
{{ $t('addattachment') }}
|
||||
@@ -486,18 +499,18 @@ export default {
|
||||
</b-upload>
|
||||
</b-field>
|
||||
<b-field>
|
||||
<b-input v-model="title" required :placeholder="this.$t('labelforfile')"></b-input>
|
||||
<b-input v-model="title" required :placeholder="$t('labelforfile')"></b-input>
|
||||
</b-field>
|
||||
|
||||
<b-field class="buttons">
|
||||
<b-button tag="input" native-type="submit" :disabled="tryingToUpload" type="is-primary" label="Upload File" value="Upload File">
|
||||
<b-button tag="button" native-type="submit" :disabled="tryingToUpload" type="is-primary" label="Upload File" value="Upload File">
|
||||
</b-button>
|
||||
<b-button
|
||||
tag="input"
|
||||
tag="button"
|
||||
native-type="submit"
|
||||
:disabled="tryingToUpload"
|
||||
type="is-danger"
|
||||
label="Upload File"
|
||||
label="Cancel"
|
||||
value="Cancel"
|
||||
@click="showAttachmentForm = false"
|
||||
>
|
||||
@@ -510,14 +523,14 @@ export default {
|
||||
</div>
|
||||
|
||||
<b-table :data="attachments" hoverable mobile-cards>
|
||||
<b-table-column v-slot="props" field="title" :label="this.$t('title')" :td-attrs="columnTdAttrs">
|
||||
<b-table-column v-slot="props" field="title" :label="$t('title')" :td-attrs="columnTdAttrs">
|
||||
{{ `${props.row.title}` }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column v-slot="props" field="originalName" :label="this.$t('name')" :td-attrs="columnTdAttrs">
|
||||
<b-table-column v-slot="props" field="originalName" :label="$t('name')" :td-attrs="columnTdAttrs">
|
||||
{{ `${props.row.originalName}` }}
|
||||
</b-table-column>
|
||||
<b-table-column v-slot="props" field="id" :label="this.$t('download')" :td-attrs="columnTdAttrs">
|
||||
<b-table-column v-slot="props" field="id" :label="$t('download')" :td-attrs="columnTdAttrs">
|
||||
<b-button tag="a" :href="`/api/attachments/${props.row.id}/file?access_token=${currentUser.token}`" :download="props.row.originalName">
|
||||
<b-icon type="is-primary" icon="download"></b-icon>
|
||||
</b-button>
|
||||
@@ -527,16 +540,29 @@ export default {
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="columns">
|
||||
<div class="column" :class="isMobile ? 'has-text-centered' : ''"> <h1 class="title">{{ $t('statistics') }}</h1></div>
|
||||
<div class="column">
|
||||
<b-select v-model="dateRangeOption" class="is-pulled-right is-medium">
|
||||
<option v-for="option in dateRangeOptions" :key="option.value" :value="option.value">
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</b-select></div
|
||||
<div class="column" :class="isMobile ? 'has-text-centered' : ''">
|
||||
<h1 class="title">{{ $t('statistics') }}</h1></div
|
||||
>
|
||||
<div class="column">
|
||||
<div class="columns is-pulled-right is-medium">
|
||||
<div class="column">
|
||||
<b-select v-model="mileageOption">
|
||||
<option v-for="option in mileageOptions" :key="option.value" :value="option.value">
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</b-select>
|
||||
</div>
|
||||
<div class="column">
|
||||
<b-select v-model="dateRangeOption">
|
||||
<option v-for="option in dateRangeOptions" :key="option.value" :value="option.value">
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</b-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<MileageChart :vehicle="vehicle" :since="getStartDate()" :user="me" :height="300" />
|
||||
<MileageChart :vehicle="vehicle" :since="getStartDate()" :user="me" :height="300" :mileage-option="mileageOption" />
|
||||
</div>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
14736
ui/yarn.lock
14736
ui/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user