refactor(expenses): major refactor of the CRUDs methods sing sessions data
This commit is contained in:
parent
60aac39daa
commit
062b9b4640
136
package-lock.json
generated
136
package-lock.json
generated
|
|
@ -17,7 +17,7 @@
|
|||
"@nestjs/platform-express": "^11.1.6",
|
||||
"@nestjs/schedule": "^6.0.0",
|
||||
"@nestjs/swagger": "^11.2.0",
|
||||
"@prisma/client": "^6.17.1",
|
||||
"@prisma/client": "^6.18.0",
|
||||
"bullmq": "^5.58.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.2",
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
"globals": "^16.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prisma": "^6.17.1",
|
||||
"prisma": "^6.18.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
|
|
@ -3268,13 +3268,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nestjs/common": {
|
||||
"version": "11.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.6.tgz",
|
||||
"integrity": "sha512-krKwLLcFmeuKDqngG2N/RuZHCs2ycsKcxWIDgcm7i1lf3sQ0iG03ci+DsP/r3FcT/eJDFsIHnKtNta2LIi7PzQ==",
|
||||
"version": "11.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.7.tgz",
|
||||
"integrity": "sha512-lwlObwGgIlpXSXYOTpfzdCepUyWomz6bv9qzGzzvpgspUxkj0Uz0fUJcvD44V8Ps7QhKW3lZBoYbXrH25UZrbA==",
|
||||
"dependencies": {
|
||||
"file-type": "21.0.0",
|
||||
"iterare": "1.2.1",
|
||||
"load-esm": "1.0.2",
|
||||
"load-esm": "1.0.3",
|
||||
"tslib": "2.8.1",
|
||||
"uid": "2.0.2"
|
||||
},
|
||||
|
|
@ -3312,15 +3312,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nestjs/core": {
|
||||
"version": "11.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.6.tgz",
|
||||
"integrity": "sha512-siWX7UDgErisW18VTeJA+x+/tpNZrJewjTBsRPF3JVxuWRuAB1kRoiJcxHgln8Lb5UY9NdvklITR84DUEXD0Cg==",
|
||||
"version": "11.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.7.tgz",
|
||||
"integrity": "sha512-TyXFOwjhHv/goSgJ8i20K78jwTM0iSpk9GBcC2h3mf4MxNy+znI8m7nWjfoACjTkb89cTwDQetfTHtSfGLLaiA==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@nuxt/opencollective": "0.4.1",
|
||||
"fast-safe-stringify": "2.1.1",
|
||||
"iterare": "1.2.1",
|
||||
"path-to-regexp": "8.2.0",
|
||||
"path-to-regexp": "8.3.0",
|
||||
"tslib": "2.8.1",
|
||||
"uid": "2.0.2"
|
||||
},
|
||||
|
|
@ -3392,14 +3392,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nestjs/platform-express": {
|
||||
"version": "11.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.6.tgz",
|
||||
"integrity": "sha512-HErwPmKnk+loTq8qzu1up+k7FC6Kqa8x6lJ4cDw77KnTxLzsCaPt+jBvOq6UfICmfqcqCCf3dKXg+aObQp+kIQ==",
|
||||
"version": "11.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.7.tgz",
|
||||
"integrity": "sha512-5T+GLdvTiGPKB4/P4PM9ftKUKNHJy8ThEFhZA3vQnXVL7Vf0rDr07TfVTySVu+XTh85m1lpFVuyFM6u6wLNsRA==",
|
||||
"dependencies": {
|
||||
"cors": "2.8.5",
|
||||
"express": "5.1.0",
|
||||
"multer": "2.0.2",
|
||||
"path-to-regexp": "8.2.0",
|
||||
"path-to-regexp": "8.3.0",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"funding": {
|
||||
|
|
@ -3547,19 +3547,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/swagger/node_modules/path-to-regexp": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
|
||||
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/testing": {
|
||||
"version": "11.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.6.tgz",
|
||||
"integrity": "sha512-srYzzDNxGvVCe1j0SpTS9/ix75PKt6Sn6iMaH1rpJ6nj2g8vwNrhK0CoJJXvpCYgrnI+2WES2pprYnq8rAMYHA==",
|
||||
"version": "11.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.7.tgz",
|
||||
"integrity": "sha512-QbtrgSlc3QVo6RHNxTTlyhaiobLLy8kvhOlgWHsoXRknybuRs7vZg4k5mo3ye6pITGeT3CrWIRpZjUsh5Wps5Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
|
|
@ -3667,9 +3658,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@prisma/client": {
|
||||
"version": "6.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.17.1.tgz",
|
||||
"integrity": "sha512-zL58jbLzYamjnNnmNA51IOZdbk5ci03KviXCuB0Tydc9btH2kDWsi1pQm2VecviRTM7jGia0OPPkgpGnT3nKvw==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.18.0.tgz",
|
||||
"integrity": "sha512-jnL2I9gDnPnw4A+4h5SuNn8Gc+1mL1Z79U/3I9eE2gbxJG1oSA+62ByPW4xkeDgwE0fqMzzpAZ7IHxYnLZ4iQA==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=18.18"
|
||||
|
|
@ -3688,60 +3679,60 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@prisma/config": {
|
||||
"version": "6.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.17.1.tgz",
|
||||
"integrity": "sha512-fs8wY6DsvOCzuiyWVckrVs1LOcbY4LZNz8ki4uUIQ28jCCzojTGqdLhN2Jl5lDnC1yI8/gNIKpsWDM8pLhOdwA==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.18.0.tgz",
|
||||
"integrity": "sha512-rgFzspCpwsE+q3OF/xkp0fI2SJ3PfNe9LLMmuSVbAZ4nN66WfBiKqJKo/hLz3ysxiPQZf8h1SMf2ilqPMeWATQ==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"c12": "3.1.0",
|
||||
"deepmerge-ts": "7.1.5",
|
||||
"effect": "3.16.12",
|
||||
"effect": "3.18.4",
|
||||
"empathic": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/debug": {
|
||||
"version": "6.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.17.1.tgz",
|
||||
"integrity": "sha512-Vf7Tt5Wh9XcndpbmeotuqOMLWPTjEKCsgojxXP2oxE1/xYe7PtnP76hsouG9vis6fctX+TxgmwxTuYi/+xc7dQ==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.18.0.tgz",
|
||||
"integrity": "sha512-PMVPMmxPj0ps1VY75DIrT430MoOyQx9hmm174k6cmLZpcI95rAPXOQ+pp8ANQkJtNyLVDxnxVJ0QLbrm/ViBcg==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@prisma/engines": {
|
||||
"version": "6.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.17.1.tgz",
|
||||
"integrity": "sha512-D95Ik3GYZkqZ8lSR4EyFOJ/tR33FcYRP8kK61o+WMsyD10UfJwd7+YielflHfKwiGodcqKqoraWw8ElAgMDbPw==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.18.0.tgz",
|
||||
"integrity": "sha512-i5RzjGF/ex6AFgqEe2o1IW8iIxJGYVQJVRau13kHPYEL1Ck8Zvwuzamqed/1iIljs5C7L+Opiz5TzSsUebkriA==",
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@prisma/debug": "6.17.1",
|
||||
"@prisma/engines-version": "6.17.1-1.272a37d34178c2894197e17273bf937f25acdeac",
|
||||
"@prisma/fetch-engine": "6.17.1",
|
||||
"@prisma/get-platform": "6.17.1"
|
||||
"@prisma/debug": "6.18.0",
|
||||
"@prisma/engines-version": "6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
|
||||
"@prisma/fetch-engine": "6.18.0",
|
||||
"@prisma/get-platform": "6.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/engines-version": {
|
||||
"version": "6.17.1-1.272a37d34178c2894197e17273bf937f25acdeac",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.17.1-1.272a37d34178c2894197e17273bf937f25acdeac.tgz",
|
||||
"integrity": "sha512-17140E3huOuD9lMdJ9+SF/juOf3WR3sTJMVyyenzqUPbuH+89nPhSWcrY+Mf7tmSs6HvaO+7S+HkELinn6bhdg==",
|
||||
"version": "6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f.tgz",
|
||||
"integrity": "sha512-T7Af4QsJQnSgWN1zBbX+Cha5t4qjHRxoeoWpK4JugJzG/ipmmDMY5S+O0N1ET6sCBNVkf6lz+Y+ZNO9+wFU8pQ==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@prisma/fetch-engine": {
|
||||
"version": "6.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.17.1.tgz",
|
||||
"integrity": "sha512-AYZiHOs184qkDMiTeshyJCtyL4yERkjfTkJiSJdYuSfc24m94lTNL5+GFinZ6vVz+ktX4NJzHKn1zIFzGTWrWg==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.18.0.tgz",
|
||||
"integrity": "sha512-TdaBvTtBwP3IoqVYoGIYpD4mWlk0pJpjTJjir/xLeNWlwog7Sl3bD2J0jJ8+5+q/6RBg+acb9drsv5W6lqae7A==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@prisma/debug": "6.17.1",
|
||||
"@prisma/engines-version": "6.17.1-1.272a37d34178c2894197e17273bf937f25acdeac",
|
||||
"@prisma/get-platform": "6.17.1"
|
||||
"@prisma/debug": "6.18.0",
|
||||
"@prisma/engines-version": "6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
|
||||
"@prisma/get-platform": "6.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/get-platform": {
|
||||
"version": "6.17.1",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.17.1.tgz",
|
||||
"integrity": "sha512-AKEn6fsfz0r482S5KRDFlIGEaq9wLNcgalD1adL+fPcFFblIKs1sD81kY/utrHdqKuVC6E1XSRpegDK3ZLL4Qg==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.18.0.tgz",
|
||||
"integrity": "sha512-uXNJCJGhxTCXo2B25Ta91Rk1/Nmlqg9p7G9GKh8TPhxvAyXCvMNQoogj4JLEUy+3ku8g59cpyQIKFhqY2xO2bg==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@prisma/debug": "6.17.1"
|
||||
"@prisma/debug": "6.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@scarf/scarf": {
|
||||
|
|
@ -6953,9 +6944,9 @@
|
|||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"node_modules/effect": {
|
||||
"version": "3.16.12",
|
||||
"resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz",
|
||||
"integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==",
|
||||
"version": "3.18.4",
|
||||
"resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz",
|
||||
"integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
|
|
@ -9542,9 +9533,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/load-esm": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/load-esm/-/load-esm-1.0.2.tgz",
|
||||
"integrity": "sha512-nVAvWk/jeyrWyXEAs84mpQCYccxRqgKY4OznLuJhJCa0XsPSfdOIr2zvBZEj3IHEHbX97jjscKRRV539bW0Gpw==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/load-esm/-/load-esm-1.0.3.tgz",
|
||||
"integrity": "sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
|
|
@ -10468,11 +10459,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
|
||||
"integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
|
||||
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
|
|
@ -10703,14 +10695,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/prisma": {
|
||||
"version": "6.17.1",
|
||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.17.1.tgz",
|
||||
"integrity": "sha512-ac6h0sM1Tg3zu8NInY+qhP/S9KhENVaw9n1BrGKQVFu05JT5yT5Qqqmb8tMRIE3ZXvVj4xcRA5yfrsy4X7Yy5g==",
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.18.0.tgz",
|
||||
"integrity": "sha512-bXWy3vTk8mnRmT+SLyZBQoC2vtV9Z8u7OHvEu+aULYxwiop/CPiFZ+F56KsNRNf35jw+8wcu8pmLsjxpBxAO9g==",
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@prisma/config": "6.17.1",
|
||||
"@prisma/engines": "6.17.1"
|
||||
"@prisma/config": "6.18.0",
|
||||
"@prisma/engines": "6.18.0"
|
||||
},
|
||||
"bin": {
|
||||
"prisma": "build/index.js"
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"@nestjs/platform-express": "^11.1.6",
|
||||
"@nestjs/schedule": "^6.0.0",
|
||||
"@nestjs/swagger": "^11.2.0",
|
||||
"@prisma/client": "^6.17.1",
|
||||
"@prisma/client": "^6.18.0",
|
||||
"bullmq": "^5.58.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.2",
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
"globals": "^16.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prisma": "^6.17.1",
|
||||
"prisma": "^6.18.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
|
|
|
|||
|
|
@ -24,10 +24,7 @@ model Users {
|
|||
role Roles @default(GUEST)
|
||||
|
||||
employee Employees? @relation("UserEmployee")
|
||||
customer Customers? @relation("UserCustomer")
|
||||
oauth_sessions OAuthSessions[] @relation("UserOAuthSessions")
|
||||
employees_archive EmployeesArchive[] @relation("UsersToEmployeesToArchive")
|
||||
customer_archive CustomersArchive[] @relation("UserToCustomersToArchive")
|
||||
preferences Preferences? @relation("UserPreferences")
|
||||
|
||||
@@map("users")
|
||||
|
|
@ -49,61 +46,13 @@ model Employees {
|
|||
|
||||
|
||||
crew Employees[] @relation("EmployeeSupervisor")
|
||||
archive EmployeesArchive[] @relation("EmployeeToArchive")
|
||||
timesheet Timesheets[] @relation("TimesheetEmployee")
|
||||
leave_request LeaveRequests[] @relation("LeaveRequestEmployee")
|
||||
supervisor_archive EmployeesArchive[] @relation("EmployeeSupervisorToArchive")
|
||||
schedule_presets SchedulePresets[] @relation("SchedulePreset")
|
||||
|
||||
@@map("employees")
|
||||
}
|
||||
|
||||
model EmployeesArchive {
|
||||
id Int @id @default(autoincrement())
|
||||
employee Employees @relation("EmployeeToArchive", fields: [employee_id], references: [id])
|
||||
employee_id Int
|
||||
user_id String @db.Uuid
|
||||
user Users @relation("UsersToEmployeesToArchive", fields: [user_id], references: [id])
|
||||
supervisor Employees? @relation("EmployeeSupervisorToArchive", fields: [supervisor_id], references: [id])
|
||||
supervisor_id Int?
|
||||
|
||||
archived_at DateTime @default(now())
|
||||
first_name String
|
||||
last_name String
|
||||
job_title String?
|
||||
is_supervisor Boolean
|
||||
external_payroll_id Int
|
||||
company_code Int
|
||||
first_work_day DateTime @db.Date
|
||||
last_work_day DateTime @db.Date
|
||||
|
||||
@@map("employees_archive")
|
||||
}
|
||||
|
||||
model Customers {
|
||||
id Int @id @default(autoincrement())
|
||||
user Users @relation("UserCustomer", fields: [user_id], references: [id])
|
||||
user_id String @unique @db.Uuid
|
||||
invoice_id Int? @unique
|
||||
|
||||
archive CustomersArchive[] @relation("CustomerToArchive")
|
||||
|
||||
@@map("customers")
|
||||
}
|
||||
|
||||
model CustomersArchive {
|
||||
id Int @id @default(autoincrement())
|
||||
customer Customers @relation("CustomerToArchive", fields: [customer_id], references: [id])
|
||||
customer_id Int
|
||||
user Users @relation("UserToCustomersToArchive", fields: [user_id], references: [id])
|
||||
user_id String @db.Uuid
|
||||
|
||||
archived_at DateTime @default(now())
|
||||
invoice_id Int? @unique
|
||||
|
||||
@@map("customers_archive")
|
||||
}
|
||||
|
||||
model LeaveRequests {
|
||||
id Int @id @default(autoincrement())
|
||||
employee Employees @relation("LeaveRequestEmployee", fields: [employee_id], references: [id])
|
||||
|
|
@ -216,13 +165,6 @@ model SchedulePresetShifts {
|
|||
@@map("schedule_preset_shifts")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
model Shifts {
|
||||
id Int @id @default(autoincrement())
|
||||
timesheet Timesheets @relation("ShiftTimesheet", fields: [timesheet_id], references: [id])
|
||||
|
|
@ -283,7 +225,7 @@ model Expenses {
|
|||
attachment Int?
|
||||
|
||||
date DateTime @db.Date
|
||||
amount Decimal @db.Money
|
||||
amount Decimal? @db.Decimal(12,2)
|
||||
mileage Decimal? @db.Decimal(12,2)
|
||||
comment String
|
||||
supervisor_comment String?
|
||||
|
|
@ -305,7 +247,7 @@ model ExpensesArchive {
|
|||
archived_at DateTime @default(now())
|
||||
bank_code_id Int
|
||||
date DateTime @db.Date
|
||||
amount Decimal? @db.Money
|
||||
amount Decimal? @db.Decimal(12,2)
|
||||
mileage Decimal? @db.Decimal(12,2)
|
||||
comment String?
|
||||
is_approved Boolean
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { Body, Controller, Param, ParseIntPipe, Post } from "@nestjs/common";
|
||||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from "@nestjs/common";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { ExpenseDto } from "../dtos/expense.dto";
|
||||
import { CreateResult, ExpenseUpsertService } from "../services/expense-upsert.service";
|
||||
import { CreateResult, ExpenseUpsertService, UpdateResult } from "../services/expense-upsert.service";
|
||||
import { updateExpenseDto } from "src/modules/expenses/dtos/update-expense.dto";
|
||||
|
||||
|
||||
@Controller('expense')
|
||||
|
|
@ -11,11 +12,21 @@ export class ExpenseController {
|
|||
private readonly upsert_service: ExpenseUpsertService,
|
||||
){}
|
||||
|
||||
@Post(':timesheet_id')
|
||||
create(
|
||||
@Param('timesheet_id', ParseIntPipe) timesheet_id: number,
|
||||
@Body() dto: ExpenseDto): Promise<CreateResult>{
|
||||
return this.upsert_service.createExpense(timesheet_id, dto);
|
||||
}
|
||||
|
||||
// @Post(':timesheet_id')
|
||||
// create(
|
||||
// @Param('timesheet_id', ParseIntPipe) timesheet_id: number,
|
||||
// @Body() dto: ExpenseDto): Promise<CreateResult>{
|
||||
// return this.upsert_service.createExpense(timesheet_id, dto);
|
||||
// }
|
||||
@Patch()
|
||||
update(
|
||||
@Body() body: { update :{ id: number; dto: updateExpenseDto }}): Promise<UpdateResult>{
|
||||
return this.upsert_service.updateExpense(body.update);
|
||||
}
|
||||
|
||||
@Delete(':expense_id')
|
||||
remove(@Param('expense_id') expense_id: number) {
|
||||
return this.upsert_service.deleteExpense(expense_id);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@ import { IsBoolean, IsInt, IsOptional, IsString, MaxLength } from "class-validat
|
|||
export class ExpenseDto {
|
||||
@IsInt() bank_code_id!: number;
|
||||
@IsInt() timesheet_id!: number;
|
||||
@IsString() @IsOptional() attachment?: string;
|
||||
@IsInt() @IsOptional() attachment?: number;
|
||||
|
||||
@IsString() date!: string;
|
||||
@IsString() date!: string;
|
||||
@IsInt() @IsOptional() amount?: number;
|
||||
@IsInt() @IsOptional() mileage?: number;
|
||||
@IsString() @MaxLength(280) comment!: string;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
export class GetExpenseDto {
|
||||
id: number;
|
||||
timesheet_id: number;
|
||||
bank_code_id: number;
|
||||
attachment?: string;
|
||||
attachment?: number;
|
||||
date: string;
|
||||
comment: string;
|
||||
mileage?: number;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,15 @@
|
|||
// import { ExpensesController } from "./controllers/expenses.controller";
|
||||
// import { Module } from "@nestjs/common";
|
||||
// import { ExpensesQueryService } from "./services/expenses-query.service";
|
||||
// import { BusinessLogicsModule } from "src/modules/business-logics/business-logics.module";
|
||||
// import { ExpensesCommandService } from "./services/expenses-command.service";
|
||||
// import { ExpensesArchivalService } from "./services/expenses-archival.service";
|
||||
// import { SharedModule } from "../shared/shared.module";
|
||||
import { ExpensesArchivalService } from "./services/expenses-archival.service";
|
||||
import { BusinessLogicsModule } from "src/modules/business-logics/business-logics.module";
|
||||
import { ExpenseUpsertService } from "src/modules/expenses/services/expense-upsert.service";
|
||||
import { ExpenseController } from "src/modules/expenses/controllers/expense.controller";
|
||||
import { SharedModule } from "../shared/shared.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
// @Module({
|
||||
// imports: [BusinessLogicsModule, SharedModule],
|
||||
// controllers: [ExpensesController],
|
||||
// providers: [
|
||||
// ExpensesQueryService,
|
||||
// ExpensesArchivalService,
|
||||
// ExpensesCommandService,
|
||||
// ],
|
||||
// exports: [
|
||||
// ExpensesQueryService,
|
||||
// ExpensesArchivalService,
|
||||
// ],
|
||||
// })
|
||||
@Module({
|
||||
imports: [ BusinessLogicsModule, SharedModule ],
|
||||
controllers: [ ExpenseController ],
|
||||
providers: [ ExpenseUpsertService, ExpensesArchivalService ],
|
||||
exports: [ ExpensesArchivalService ],
|
||||
})
|
||||
|
||||
// export class ExpensesModule {}
|
||||
export class ExpensesModule {}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
export const toDateFromString = (ymd: string): Date => {
|
||||
return new Date(`${ymd}T00:00:00:000Z`);
|
||||
}
|
||||
export const toStringFromDate = (date: Date) =>
|
||||
date.toISOString().slice(0,10);
|
||||
|
|
@ -1,41 +1,171 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { GetExpenseDto } from "../dtos/get-expense.dto";
|
||||
import { toDateFromString, toStringFromDate } from "../helpers/expenses-date-time-helpers";
|
||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { updateExpenseDto } from "../dtos/update-expense.dto";
|
||||
import { GetExpenseDto } from "../dtos/get-expense.dto";
|
||||
import { PrismaService } from "src/prisma/prisma.service";
|
||||
import { ExpenseDto } from "../dtos/expense.dto";
|
||||
import { toDateFromString } from "../helpers/expenses-date-time-helpers";
|
||||
|
||||
type Normalized = { date: Date; comment: string; supervisor_comment: string; };
|
||||
type Normalized = { date: Date; comment: string; supervisor_comment?: string; };
|
||||
|
||||
export type CreateResult = { ok: true; data: GetExpenseDto } | { ok: false; error: any };
|
||||
export type CreateResult = { ok: true; data: GetExpenseDto } | { ok: false; error: any };
|
||||
export type UpdatePayload = { id: number; dto: updateExpenseDto };
|
||||
export type UpdateResult = { ok: true; id: number; data: GetExpenseDto } | { ok: false; id: number; error: any };
|
||||
export type DeleteResult = { ok: true; id: number; } | { ok: false; id: number; error: any };
|
||||
|
||||
type NormedOk = { dto: GetExpenseDto; normed: Normalized };
|
||||
type NormedErr = { error: any };
|
||||
export type UpdateResult = { ok: true; id: number; data: GetExpenseDto } | { ok: false; id: number; error: any };
|
||||
export type DeleteResult = { ok: true; id: number; } | { ok: false; id: number; error: any };
|
||||
|
||||
@Injectable()
|
||||
export class ExpenseUpsertService {
|
||||
constructor(private readonly prisma: PrismaService){}
|
||||
constructor(private readonly prisma: PrismaService) { }
|
||||
|
||||
//_________________________________________________________________
|
||||
// CREATE
|
||||
//_________________________________________________________________
|
||||
//normalized frontend data to match DB
|
||||
async createExpense(timesheet_id: number, dto: ExpenseDto){
|
||||
const normed_expense = this.normalizeExpenseDto(dto)
|
||||
async createExpense(timesheet_id: number, dto: ExpenseDto): Promise<CreateResult> {
|
||||
try {
|
||||
//normalize strings and dates
|
||||
const normed_expense = this.normalizeExpenseDto(dto);
|
||||
|
||||
//parse numbers
|
||||
const parsed_amount = this.parseOptionalNumber(dto.amount, "amount");
|
||||
const parsed_mileage = this.parseOptionalNumber(dto.mileage, "mileage");
|
||||
const parsed_attachment = this.parseOptionalNumber(dto.attachment, "attachment");
|
||||
|
||||
//create a new expense
|
||||
const expense = await this.prisma.expenses.create({
|
||||
data: {
|
||||
timesheet_id,
|
||||
bank_code_id: dto.bank_code_id,
|
||||
attachment: parsed_attachment,
|
||||
date: normed_expense.date,
|
||||
amount: parsed_amount,
|
||||
mileage: parsed_mileage,
|
||||
comment: normed_expense.comment,
|
||||
supervisor_comment: normed_expense.supervisor_comment,
|
||||
is_approved: dto.is_approved,
|
||||
},
|
||||
//return the newly created expense with id
|
||||
select: {
|
||||
id: true,
|
||||
timesheet_id: true,
|
||||
bank_code_id: true,
|
||||
attachment: true,
|
||||
date: true,
|
||||
amount: true,
|
||||
mileage: true,
|
||||
comment: true,
|
||||
supervisor_comment: true,
|
||||
is_approved: true,
|
||||
},
|
||||
});
|
||||
|
||||
//build an object to return to the frontend to display
|
||||
const created: GetExpenseDto = {
|
||||
id: expense.id,
|
||||
timesheet_id: expense.timesheet_id,
|
||||
bank_code_id: expense.bank_code_id,
|
||||
attachment: expense.attachment ?? undefined,
|
||||
date: toStringFromDate(expense.date),
|
||||
amount: expense.amount?.toNumber(),
|
||||
mileage: expense.mileage?.toNumber(),
|
||||
comment: expense.comment,
|
||||
supervisor_comment: expense.supervisor_comment ?? undefined,
|
||||
is_approved: expense.is_approved,
|
||||
};
|
||||
return { ok: true, data: created }
|
||||
|
||||
} catch (error) {
|
||||
return { ok: false, error: error }
|
||||
}
|
||||
}
|
||||
|
||||
//_________________________________________________________________
|
||||
// UPDATE
|
||||
//_________________________________________________________________
|
||||
async updateExpense({id, dto}: UpdatePayload): Promise<UpdateResult> {
|
||||
try {
|
||||
//checks for modifications
|
||||
const data: Record<string, unknown> = {};
|
||||
if (dto.date !== undefined) data.date = toDateFromString(dto.date);
|
||||
if (dto.comment !== undefined) data.comment = this.truncate280(dto.comment);
|
||||
if (dto.attachment !== undefined) data.attachment = this.parseOptionalNumber(dto.attachment, "attachment");
|
||||
if (dto.amount !== undefined) data.amount = this.parseOptionalNumber(dto.amount, "amount");
|
||||
if (dto.mileage !== undefined) data.mileage = this.parseOptionalNumber(dto.mileage, "mileage");
|
||||
if (dto.bank_code_id !== undefined) data.bank_code_id = dto.bank_code_id;
|
||||
if (dto.supervisor_comment !== undefined) {
|
||||
data.supervisor_comment = dto.supervisor_comment?.trim()
|
||||
? this.truncate280(dto.supervisor_comment.trim())
|
||||
: null;
|
||||
}
|
||||
//return an error if no fields needs an update
|
||||
if(!Object.keys(data).length) {
|
||||
return { ok: false, id, error: new Error("Nothing to update")};
|
||||
}
|
||||
|
||||
const expense = await this.prisma.expenses.update({
|
||||
where: { id },
|
||||
data,
|
||||
select: {
|
||||
id: true,
|
||||
timesheet_id: true,
|
||||
bank_code_id: true,
|
||||
attachment: true,
|
||||
date: true,
|
||||
amount: true,
|
||||
mileage: true,
|
||||
comment: true,
|
||||
supervisor_comment: true,
|
||||
is_approved: true,
|
||||
},
|
||||
});
|
||||
|
||||
const updated: GetExpenseDto = {
|
||||
id: expense.id,
|
||||
timesheet_id: expense.timesheet_id,
|
||||
bank_code_id: expense.bank_code_id,
|
||||
attachment: expense.attachment ?? undefined,
|
||||
date: toStringFromDate(expense.date),
|
||||
amount: expense.amount?.toNumber(),
|
||||
mileage: expense.mileage?.toNumber(),
|
||||
comment: expense.comment,
|
||||
supervisor_comment: expense.supervisor_comment ?? undefined,
|
||||
is_approved: expense.is_approved,
|
||||
};
|
||||
return { ok: true, id: expense.id, data: updated };
|
||||
} catch (error) {
|
||||
return { ok: false, id: id, error: error}
|
||||
}
|
||||
}
|
||||
//_________________________________________________________________
|
||||
// DELETE
|
||||
//_________________________________________________________________
|
||||
async deleteExpense(expense_id: number): Promise<DeleteResult> {
|
||||
try {
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
const expense = await tx.expenses.findUnique({
|
||||
where: { id: expense_id },
|
||||
select: { id: true },
|
||||
});
|
||||
if(!expense) throw new NotFoundException(`Expense with id: ${expense_id} not found`);
|
||||
|
||||
await tx.expenses.delete({ where: { id: expense_id }});
|
||||
return { success: true };
|
||||
});
|
||||
return { ok: true, id: expense_id };
|
||||
} catch (error) {
|
||||
return { ok: false, id: expense_id, error };
|
||||
}
|
||||
}
|
||||
|
||||
//_________________________________________________________________
|
||||
// LOCAL HELPERS
|
||||
//_________________________________________________________________
|
||||
//makes sure that comments are the right length the date is of Date type
|
||||
private normalizeExpenseDto(dto: ExpenseDto): Normalized {
|
||||
const date = toDateFromString(dto.date);
|
||||
const date = toDateFromString(dto.date);
|
||||
const comment = this.truncate280(dto.comment);
|
||||
const supervisor_comment = this.truncate280(dto.supervisor_comment? dto.supervisor_comment : '');
|
||||
const supervisor_comment =
|
||||
dto.supervisor_comment && dto.supervisor_comment.trim()
|
||||
? this.truncate280(dto.supervisor_comment.trim())
|
||||
: undefined;
|
||||
return { date, comment, supervisor_comment };
|
||||
}
|
||||
|
||||
|
|
@ -43,4 +173,12 @@ export class ExpenseUpsertService {
|
|||
private truncate280 = (input: string): string => {
|
||||
return input.length > 280 ? input.slice(0, 280) : input;
|
||||
}
|
||||
|
||||
//makes sure that the type of data of numeric values is valid
|
||||
private parseOptionalNumber = (value: unknown, field: string) => {
|
||||
if (value == null) return undefined;
|
||||
const parsed = Number(value);
|
||||
if (Number.isNaN(parsed)) throw new Error(`Invalid value : ${value} for ${field}`);
|
||||
return parsed;
|
||||
};
|
||||
}
|
||||
|
|
@ -12,12 +12,12 @@ export class ShiftController {
|
|||
private readonly get_service: ShiftsGetService
|
||||
){}
|
||||
|
||||
@Get()
|
||||
async getShiftsByIds(
|
||||
@Query("shift_ids") shift_ids: string) {
|
||||
const parsed = shift_ids.split(/,\s*/).map(value => Number(value)).filter(Number.isFinite);
|
||||
return this.get_service.getShiftByShiftId(parsed);
|
||||
}
|
||||
// @Get()
|
||||
// async getShiftsByIds(
|
||||
// @Query("shift_ids") shift_ids: string) {
|
||||
// const parsed = shift_ids.split(/,\s*/).map(value => Number(value)).filter(Number.isFinite);
|
||||
// return this.get_service.getShiftByShiftId(parsed);
|
||||
// }
|
||||
|
||||
@Post(':timesheet_id')
|
||||
createBatch(
|
||||
|
|
|
|||
|
|
@ -336,17 +336,17 @@ export class ShiftsUpsertService {
|
|||
//finds shifts using shit_ids
|
||||
//recalc overtime shifts after delete
|
||||
//blocs deletion if approved
|
||||
async deleteShift(shift_id: number) {
|
||||
return await this.prisma.$transaction(async (tx) =>{
|
||||
async deleteShift(shift_id: number) {
|
||||
return await this.prisma.$transaction(async (tx) => {
|
||||
const shift = await tx.shifts.findUnique({
|
||||
where: { id: shift_id },
|
||||
where: { id: shift_id },
|
||||
select: { id: true, date: true, timesheet_id: true },
|
||||
});
|
||||
if(!shift) throw new NotFoundException(`Shift with id #${shift_id} not found`);
|
||||
if (!shift) throw new NotFoundException(`Shift with id #${shift_id} not found`);
|
||||
|
||||
await tx.shifts.delete({ where: { id: shift_id } });
|
||||
|
||||
const summary = await this.overtime.getWeekOvertimeSummary( shift.timesheet_id, shift.date, tx);
|
||||
const summary = await this.overtime.getWeekOvertimeSummary(shift.timesheet_id, shift.date, tx);
|
||||
return {
|
||||
success: true,
|
||||
overtime: summary
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user