Compare commits
5 Commits
0ff842b845
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| e84a700a8b | |||
| 6a70a4a6ae | |||
| bcc56d6dd2 | |||
| e3656203ed | |||
| 54de913c16 |
@@ -1,19 +1,33 @@
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
# Przekieruj /odoo (bez slash) na /odoo/ (z slash)
|
||||
# Przekierowanie bez / na /odoo/
|
||||
location = /odoo {
|
||||
return 301 /odoo/;
|
||||
}
|
||||
|
||||
# Serwowanie plików Vue pod /odoo/
|
||||
# Serwowanie Vue
|
||||
location /odoo/ {
|
||||
alias /usr/share/nginx/html/;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /odoo/index.html;
|
||||
}
|
||||
|
||||
# Proxy do backendu (niewidoczny z zewnątrz)
|
||||
# no cache index.html
|
||||
location = /odoo/index.html {
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
expires 0;
|
||||
}
|
||||
|
||||
# cache JS/CSS/OBRAZY na długo
|
||||
location ~* \.(?:js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
access_log off;
|
||||
expires 1y;
|
||||
alias /usr/share/nginx/html/;
|
||||
}
|
||||
|
||||
# Proxy do backendu
|
||||
location /odoo/api/ {
|
||||
proxy_pass http://backend:8000/;
|
||||
proxy_set_header Host $host;
|
||||
@@ -22,3 +36,4 @@ server {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
980
frontend/package-lock.json
generated
980
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,8 @@
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --fix",
|
||||
"format": "prettier --write src/"
|
||||
"format": "prettier --write src/",
|
||||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jamescoyle/vue-icon": "^0.1.2",
|
||||
@@ -30,8 +31,10 @@
|
||||
"eslint": "^9.31.0",
|
||||
"eslint-plugin-vue": "~10.3.0",
|
||||
"globals": "^16.3.0",
|
||||
"jsdom": "^27.0.1",
|
||||
"prettier": "3.6.2",
|
||||
"vite": "^7.0.6",
|
||||
"vite-plugin-vue-devtools": "^8.0.0"
|
||||
"vite-plugin-vue-devtools": "^8.0.0",
|
||||
"vitest": "^4.0.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useAuthStore } from '@/stores/authStore'
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: '/odoo/api', // Twój backend
|
||||
// baseURL: 'http://localhost:8000', // Twój backend
|
||||
})
|
||||
|
||||
// Request interceptor – dodawanie tokena
|
||||
|
||||
@@ -96,7 +96,13 @@ function isValidWorkDay(day) {
|
||||
}
|
||||
|
||||
function calculateWorkedTime(entryTimes, exitTimes) {
|
||||
if (!entryTimes || !exitTimes || !Array.isArray(entryTimes) || !Array.isArray(exitTimes) || entryTimes.length === 0) {
|
||||
if (
|
||||
!entryTimes ||
|
||||
!exitTimes ||
|
||||
!Array.isArray(entryTimes) ||
|
||||
!Array.isArray(exitTimes) ||
|
||||
entryTimes.length === 0
|
||||
) {
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -144,7 +150,7 @@ function floatHoursToHHMM(decimalHours) {
|
||||
|
||||
function calculateDay(day) {
|
||||
// Create a mutable copy of exit times to potentially add the current time.
|
||||
const exitTimes = [...day.exitTime]
|
||||
// const exitTimes = [...day.exitTime]
|
||||
|
||||
// If there's one more entry than exits, it means the user is currently clocked in.
|
||||
if (day.entryTime.length > 0 && day.entryTime.length === day.exitTime.length + 1) {
|
||||
@@ -153,7 +159,7 @@ function calculateDay(day) {
|
||||
const mm = String(now.getMinutes()).padStart(2, '0')
|
||||
const ss = String(now.getSeconds()).padStart(2, '0')
|
||||
// Add the current time as the "exit" for the last entry.
|
||||
exitTimes.push(`${hh}:${mm}:${ss}`)
|
||||
day.exitTime.push(`${hh}:${mm}:${ss}`)
|
||||
}
|
||||
|
||||
if (day.entryTime.length === 0) {
|
||||
@@ -162,7 +168,7 @@ function calculateDay(day) {
|
||||
// The -0.25 for a 15-minute break seems to be a business rule.
|
||||
// It should probably only be subtracted once per day, not per interval.
|
||||
// Let's subtract it from the total.
|
||||
let totalHours = calculateWorkedTime(day.entryTime, exitTimes)
|
||||
let totalHours = calculateWorkedTime(day.entryTime, day.exitTime)
|
||||
if (totalHours > 0) {
|
||||
totalHours -= 0.25
|
||||
}
|
||||
|
||||
117
frontend/src/utils/utils.spec.js
Normal file
117
frontend/src/utils/utils.spec.js
Normal file
@@ -0,0 +1,117 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
||||
import utils from './utils.js'
|
||||
|
||||
const { calculateDay } = utils
|
||||
|
||||
describe('calculateDay', () => {
|
||||
let day
|
||||
|
||||
beforeEach(() => {
|
||||
day = {
|
||||
entryTime: [],
|
||||
exitTime: [],
|
||||
isHolidayLeave: false,
|
||||
isSickLeave: false,
|
||||
dayOfWeek: 'Pn', // Monday
|
||||
isPublicHoliday: false,
|
||||
workedHours: 0,
|
||||
overtime: 0,
|
||||
}
|
||||
})
|
||||
|
||||
it('should calculate worked hours and overtime for a standard workday', () => {
|
||||
day.entryTime = ['08:00:00']
|
||||
day.exitTime = ['16:30:00'] // 8.5 hours of work
|
||||
const totalHours = calculateDay(day)
|
||||
|
||||
// 8.5 hours - 0.25 break = 8.25 workedHours
|
||||
// 8.25 workedHours - 8 standard hours = 0.25 overtime
|
||||
// totalHours should be workedHours, so 8.25
|
||||
expect(day.workedHours).toBe(8.25)
|
||||
expect(day.overtime).toBe(0.25)
|
||||
expect(totalHours).toBe(8.25)
|
||||
})
|
||||
|
||||
it('should handle multiple entries and exits', () => {
|
||||
day.entryTime = ['08:00:00', '13:00:00']
|
||||
day.exitTime = ['12:00:00', '16:30:00'] // 4h + 3.5h = 7.5h
|
||||
const totalHours = calculateDay(day)
|
||||
|
||||
// 7.5 hours - 0.25 break = 7.25 workedHours
|
||||
// 7.25 workedHours - 8 standard hours = -0.75 overtime
|
||||
expect(day.workedHours).toBe(7.25)
|
||||
expect(day.overtime).toBe(-0.75)
|
||||
expect(totalHours).toBe(7.25)
|
||||
})
|
||||
|
||||
it('should calculate hours correctly when currently clocked in', () => {
|
||||
// Mock Date for consistent results
|
||||
const now = new Date('2025-10-29T12:00:00')
|
||||
vi.setSystemTime(now)
|
||||
|
||||
day.entryTime = ['09:00:00']
|
||||
day.exitTime = [] // Clocked in
|
||||
const totalHours = calculateDay(day)
|
||||
|
||||
// 9:00 to 12:00 is 3 hours
|
||||
// 3 hours - 0.25 break = 2.75 workedHours
|
||||
expect(day.workedHours).toBe(2.75)
|
||||
expect(day.overtime).toBe(2.75 - 8) // -5.25
|
||||
expect(totalHours).toBe(2.75)
|
||||
expect(day.exitTime[0]).toBe('12:00:00')
|
||||
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('should return 0 for a day with no entries', () => {
|
||||
const totalHours = calculateDay(day)
|
||||
expect(day.workedHours).toBe(0)
|
||||
expect(day.overtime).toBe(-8)
|
||||
expect(totalHours).toBe(0)
|
||||
})
|
||||
|
||||
it('should handle holiday leave', () => {
|
||||
day.isHolidayLeave = true
|
||||
const totalHours = calculateDay(day)
|
||||
expect(day.workedHours).toBe(0)
|
||||
expect(day.overtime).toBe(0) // Overtime is just workedHours on non-work days
|
||||
expect(totalHours).toBe(8) // 0 worked + 8 holiday
|
||||
})
|
||||
|
||||
it('should handle sick leave', () => {
|
||||
day.isSickLeave = true
|
||||
const totalHours = calculateDay(day)
|
||||
expect(day.workedHours).toBe(0)
|
||||
expect(day.overtime).toBe(0)
|
||||
expect(totalHours).toBe(6.4) // 0 worked + 6.4 sick
|
||||
})
|
||||
|
||||
it('should handle sick leave and holiday leave', () => {
|
||||
day.isHolidayLeave = true
|
||||
day.isSickLeave = true
|
||||
const totalHours = calculateDay(day)
|
||||
expect(day.workedHours).toBe(0)
|
||||
expect(day.overtime).toBe(0)
|
||||
expect(totalHours).toBe(14.4) // 0 worked + 8 holiday + 6.4 sick
|
||||
})
|
||||
|
||||
it('should not subtract break time if worked hours are 0', () => {
|
||||
day.entryTime = []
|
||||
day.exitTime = []
|
||||
const totalHours = calculateDay(day)
|
||||
expect(day.workedHours).toBe(0)
|
||||
expect(totalHours).toBe(0)
|
||||
})
|
||||
|
||||
it('should calculate overtime as workedHours on a weekend', () => {
|
||||
day.dayOfWeek = 'So' // Sunday
|
||||
day.entryTime = ['10:00:00']
|
||||
day.exitTime = ['12:00:00'] // 2 hours of work
|
||||
const totalHours = calculateDay(day)
|
||||
|
||||
// 2 hours - 0.25 break = 1.75
|
||||
expect(day.workedHours).toBe(1.75)
|
||||
expect(day.overtime).toBe(1.75) // On non-work days, all worked time is overtime
|
||||
expect(totalHours).toBe(1.75)
|
||||
})
|
||||
})
|
||||
@@ -1,16 +1,20 @@
|
||||
/// <reference types="vitest" />
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import VueDevTools from 'vite-plugin-vue-devtools'
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ command }) => ({
|
||||
base: '/odoo/',
|
||||
plugins: [vue(), vueDevTools()],
|
||||
plugins: [vue(), ...(command === 'serve' ? [VueDevTools()] : [])],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
},
|
||||
},
|
||||
})
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
},
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user