Merge branch 'main' of git.targo.ca:Targo/targo_backend
This commit is contained in:
commit
fc6681a548
|
|
@ -71,142 +71,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/employees/employee-list": {
|
|
||||||
"get": {
|
|
||||||
"operationId": "EmployeesController_findListEmployees",
|
|
||||||
"parameters": [],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "List of employees with scoped info found",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/EmployeeListItemDto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "List of employees with scoped info not found"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"access-token": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"summary": "Find all employees with scoped info",
|
|
||||||
"tags": [
|
|
||||||
"Employees"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/employees/{email}": {
|
|
||||||
"patch": {
|
|
||||||
"operationId": "EmployeesController_updateOrArchiveOrRestore",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "email",
|
|
||||||
"required": true,
|
|
||||||
"in": "path",
|
|
||||||
"description": "Email of the employee",
|
|
||||||
"schema": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"requestBody": {
|
|
||||||
"required": true,
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/UpdateEmployeeDto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Employee updated or restored",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/CreateEmployeeDto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"202": {
|
|
||||||
"description": "Employee archived successfully",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/CreateEmployeeDto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Employee not found in active or archive"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"access-token": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"access-token": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"summary": "Update, archive or restore an employee",
|
|
||||||
"tags": [
|
|
||||||
"Employees"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/employees/profile/{email}": {
|
|
||||||
"get": {
|
|
||||||
"operationId": "EmployeesController_findOneProfile",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "email",
|
|
||||||
"required": true,
|
|
||||||
"in": "path",
|
|
||||||
"description": "Identifier of the employee",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Employee profile found",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/EmployeeProfileItemDto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Employee profile not found"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"access-token": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"summary": "Find employee profile",
|
|
||||||
"tags": [
|
|
||||||
"Employees"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/notifications/summary": {
|
"/notifications/summary": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "NotificationsController_summary",
|
"operationId": "NotificationsController_summary",
|
||||||
|
|
@ -649,6 +513,39 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/preferences/{email}": {
|
||||||
|
"patch": {
|
||||||
|
"operationId": "PreferencesController_updatePreferences",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "email",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/PreferencesDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Preferences"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/timesheets": {
|
"/timesheets": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "TimesheetController_getTimesheetByIds",
|
"operationId": "TimesheetController_getTimesheetByIds",
|
||||||
|
|
@ -688,41 +585,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/shift": {
|
|
||||||
"get": {
|
|
||||||
"operationId": "ShiftController_getShiftsByIds",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "shift_ids",
|
|
||||||
"required": true,
|
|
||||||
"in": "query",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Shift"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"patch": {
|
|
||||||
"operationId": "ShiftController_updateBatch",
|
|
||||||
"parameters": [],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Shift"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/shift/{timesheet_id}": {
|
"/shift/{timesheet_id}": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "ShiftController_createBatch",
|
"operationId": "ShiftController_createBatch",
|
||||||
|
|
@ -759,6 +621,20 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/shift": {
|
||||||
|
"patch": {
|
||||||
|
"operationId": "ShiftController_updateBatch",
|
||||||
|
"parameters": [],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Shift"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/shift/{shift_id}": {
|
"/shift/{shift_id}": {
|
||||||
"delete": {
|
"delete": {
|
||||||
"operationId": "ShiftController_remove",
|
"operationId": "ShiftController_remove",
|
||||||
|
|
@ -782,39 +658,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/preferences/{email}": {
|
|
||||||
"patch": {
|
|
||||||
"operationId": "PreferencesController_updatePreferences",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "email",
|
|
||||||
"required": true,
|
|
||||||
"in": "path",
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"requestBody": {
|
|
||||||
"required": true,
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/PreferencesDto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"Preferences"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/schedule-presets/{email}": {
|
"/schedule-presets/{email}": {
|
||||||
"put": {
|
"put": {
|
||||||
"operationId": "SchedulePresetsController_upsert",
|
"operationId": "SchedulePresetsController_upsert",
|
||||||
|
|
@ -915,6 +758,76 @@
|
||||||
"SchedulePresets"
|
"SchedulePresets"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/expense/{timesheet_id}": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "ExpenseController_create",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "timesheet_id",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ExpenseDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Expense"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/expense": {
|
||||||
|
"patch": {
|
||||||
|
"operationId": "ExpenseController_update",
|
||||||
|
"parameters": [],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Expense"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/expense/{expense_id}": {
|
||||||
|
"delete": {
|
||||||
|
"operationId": "ExpenseController_remove",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "expense_id",
|
||||||
|
"required": true,
|
||||||
|
"in": "path",
|
||||||
|
"schema": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Expense"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
|
|
@ -974,162 +887,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schemas": {
|
"schemas": {
|
||||||
"EmployeeListItemDto": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {}
|
|
||||||
},
|
|
||||||
"UpdateEmployeeDto": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 1,
|
|
||||||
"description": "Unique ID of an employee(primary-key, auto-incremented)"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "0e6e2e1f-b157-4c7c-ae3f-999b3e4f914d",
|
|
||||||
"description": "UUID of the user linked to that employee"
|
|
||||||
},
|
|
||||||
"first_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Frodo",
|
|
||||||
"description": "Employee`s first name"
|
|
||||||
},
|
|
||||||
"last_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Baggins",
|
|
||||||
"description": "Employee`s last name"
|
|
||||||
},
|
|
||||||
"email": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "i_cant_do_this_sam@targointernet.com",
|
|
||||||
"description": "Employee`s email"
|
|
||||||
},
|
|
||||||
"phone_number": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "82538437464",
|
|
||||||
"description": "Employee`s phone number"
|
|
||||||
},
|
|
||||||
"residence": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "1 Bagshot Row, Hobbiton, The Shire, Middle-earth",
|
|
||||||
"description": "Employee`s residence"
|
|
||||||
},
|
|
||||||
"external_payroll_id": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 7464,
|
|
||||||
"description": "external ID for the pay system"
|
|
||||||
},
|
|
||||||
"company_code": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 335567447,
|
|
||||||
"description": "Employee`s company code"
|
|
||||||
},
|
|
||||||
"job_title": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "technicient",
|
|
||||||
"description": "employee`s job title"
|
|
||||||
},
|
|
||||||
"first_work_day": {
|
|
||||||
"format": "date-time",
|
|
||||||
"type": "string",
|
|
||||||
"example": "23/09/3018",
|
|
||||||
"description": "New hire date or undefined"
|
|
||||||
},
|
|
||||||
"last_work_day": {
|
|
||||||
"format": "date-time",
|
|
||||||
"type": "string",
|
|
||||||
"example": "25/03/3019",
|
|
||||||
"description": "Termination date (null to restore)"
|
|
||||||
},
|
|
||||||
"supervisor_id": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "Supervisor ID"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"CreateEmployeeDto": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 1,
|
|
||||||
"description": "Unique ID of an employee(primary-key, auto-incremented)"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "0e6e2e1f-b157-4c7c-ae3f-999b3e4f914d",
|
|
||||||
"description": "UUID of the user linked to that employee"
|
|
||||||
},
|
|
||||||
"first_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Frodo",
|
|
||||||
"description": "Employee`s first name"
|
|
||||||
},
|
|
||||||
"last_name": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "Baggins",
|
|
||||||
"description": "Employee`s last name"
|
|
||||||
},
|
|
||||||
"email": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "i_cant_do_this_sam@targointernet.com",
|
|
||||||
"description": "Employee`s email"
|
|
||||||
},
|
|
||||||
"phone_number": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "82538437464",
|
|
||||||
"description": "Employee`s phone number"
|
|
||||||
},
|
|
||||||
"residence": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "1 Bagshot Row, Hobbiton, The Shire, Middle-earth",
|
|
||||||
"description": "Employee`s residence"
|
|
||||||
},
|
|
||||||
"external_payroll_id": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 7464,
|
|
||||||
"description": "external ID for the pay system"
|
|
||||||
},
|
|
||||||
"company_code": {
|
|
||||||
"type": "number",
|
|
||||||
"example": 335567447,
|
|
||||||
"description": "Employee`s company code"
|
|
||||||
},
|
|
||||||
"job_title": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "technicient",
|
|
||||||
"description": "employee`s job title"
|
|
||||||
},
|
|
||||||
"first_work_day": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "23/09/3018",
|
|
||||||
"description": "Employee`s first working day"
|
|
||||||
},
|
|
||||||
"last_work_day": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "25/03/3019",
|
|
||||||
"description": "Employee`s last working day"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"user_id",
|
|
||||||
"first_name",
|
|
||||||
"last_name",
|
|
||||||
"email",
|
|
||||||
"phone_number",
|
|
||||||
"external_payroll_id",
|
|
||||||
"company_code",
|
|
||||||
"job_title",
|
|
||||||
"first_work_day"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"EmployeeProfileItemDto": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {}
|
|
||||||
},
|
|
||||||
"CreateOauthSessionDto": {
|
"CreateOauthSessionDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1407,6 +1164,10 @@
|
||||||
"SchedulePresetsDto": {
|
"SchedulePresetsDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
|
},
|
||||||
|
"ExpenseDto": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
136
package-lock.json
generated
136
package-lock.json
generated
|
|
@ -17,7 +17,7 @@
|
||||||
"@nestjs/platform-express": "^11.1.6",
|
"@nestjs/platform-express": "^11.1.6",
|
||||||
"@nestjs/schedule": "^6.0.0",
|
"@nestjs/schedule": "^6.0.0",
|
||||||
"@nestjs/swagger": "^11.2.0",
|
"@nestjs/swagger": "^11.2.0",
|
||||||
"@prisma/client": "^6.17.1",
|
"@prisma/client": "^6.18.0",
|
||||||
"bullmq": "^5.58.0",
|
"bullmq": "^5.58.0",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.2",
|
"class-validator": "^0.14.2",
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"prisma": "^6.17.1",
|
"prisma": "^6.18.0",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"supertest": "^7.0.0",
|
"supertest": "^7.0.0",
|
||||||
"ts-jest": "^29.2.5",
|
"ts-jest": "^29.2.5",
|
||||||
|
|
@ -3268,13 +3268,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@nestjs/common": {
|
"node_modules/@nestjs/common": {
|
||||||
"version": "11.1.6",
|
"version": "11.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.7.tgz",
|
||||||
"integrity": "sha512-krKwLLcFmeuKDqngG2N/RuZHCs2ycsKcxWIDgcm7i1lf3sQ0iG03ci+DsP/r3FcT/eJDFsIHnKtNta2LIi7PzQ==",
|
"integrity": "sha512-lwlObwGgIlpXSXYOTpfzdCepUyWomz6bv9qzGzzvpgspUxkj0Uz0fUJcvD44V8Ps7QhKW3lZBoYbXrH25UZrbA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"file-type": "21.0.0",
|
"file-type": "21.0.0",
|
||||||
"iterare": "1.2.1",
|
"iterare": "1.2.1",
|
||||||
"load-esm": "1.0.2",
|
"load-esm": "1.0.3",
|
||||||
"tslib": "2.8.1",
|
"tslib": "2.8.1",
|
||||||
"uid": "2.0.2"
|
"uid": "2.0.2"
|
||||||
},
|
},
|
||||||
|
|
@ -3312,15 +3312,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@nestjs/core": {
|
"node_modules/@nestjs/core": {
|
||||||
"version": "11.1.6",
|
"version": "11.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.7.tgz",
|
||||||
"integrity": "sha512-siWX7UDgErisW18VTeJA+x+/tpNZrJewjTBsRPF3JVxuWRuAB1kRoiJcxHgln8Lb5UY9NdvklITR84DUEXD0Cg==",
|
"integrity": "sha512-TyXFOwjhHv/goSgJ8i20K78jwTM0iSpk9GBcC2h3mf4MxNy+znI8m7nWjfoACjTkb89cTwDQetfTHtSfGLLaiA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/opencollective": "0.4.1",
|
"@nuxt/opencollective": "0.4.1",
|
||||||
"fast-safe-stringify": "2.1.1",
|
"fast-safe-stringify": "2.1.1",
|
||||||
"iterare": "1.2.1",
|
"iterare": "1.2.1",
|
||||||
"path-to-regexp": "8.2.0",
|
"path-to-regexp": "8.3.0",
|
||||||
"tslib": "2.8.1",
|
"tslib": "2.8.1",
|
||||||
"uid": "2.0.2"
|
"uid": "2.0.2"
|
||||||
},
|
},
|
||||||
|
|
@ -3392,14 +3392,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@nestjs/platform-express": {
|
"node_modules/@nestjs/platform-express": {
|
||||||
"version": "11.1.6",
|
"version": "11.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.7.tgz",
|
||||||
"integrity": "sha512-HErwPmKnk+loTq8qzu1up+k7FC6Kqa8x6lJ4cDw77KnTxLzsCaPt+jBvOq6UfICmfqcqCCf3dKXg+aObQp+kIQ==",
|
"integrity": "sha512-5T+GLdvTiGPKB4/P4PM9ftKUKNHJy8ThEFhZA3vQnXVL7Vf0rDr07TfVTySVu+XTh85m1lpFVuyFM6u6wLNsRA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"express": "5.1.0",
|
"express": "5.1.0",
|
||||||
"multer": "2.0.2",
|
"multer": "2.0.2",
|
||||||
"path-to-regexp": "8.2.0",
|
"path-to-regexp": "8.3.0",
|
||||||
"tslib": "2.8.1"
|
"tslib": "2.8.1"
|
||||||
},
|
},
|
||||||
"funding": {
|
"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": {
|
"node_modules/@nestjs/testing": {
|
||||||
"version": "11.1.6",
|
"version": "11.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.7.tgz",
|
||||||
"integrity": "sha512-srYzzDNxGvVCe1j0SpTS9/ix75PKt6Sn6iMaH1rpJ6nj2g8vwNrhK0CoJJXvpCYgrnI+2WES2pprYnq8rAMYHA==",
|
"integrity": "sha512-QbtrgSlc3QVo6RHNxTTlyhaiobLLy8kvhOlgWHsoXRknybuRs7vZg4k5mo3ye6pITGeT3CrWIRpZjUsh5Wps5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "2.8.1"
|
"tslib": "2.8.1"
|
||||||
|
|
@ -3667,9 +3658,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/client": {
|
"node_modules/@prisma/client": {
|
||||||
"version": "6.17.1",
|
"version": "6.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.18.0.tgz",
|
||||||
"integrity": "sha512-zL58jbLzYamjnNnmNA51IOZdbk5ci03KviXCuB0Tydc9btH2kDWsi1pQm2VecviRTM7jGia0OPPkgpGnT3nKvw==",
|
"integrity": "sha512-jnL2I9gDnPnw4A+4h5SuNn8Gc+1mL1Z79U/3I9eE2gbxJG1oSA+62ByPW4xkeDgwE0fqMzzpAZ7IHxYnLZ4iQA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.18"
|
"node": ">=18.18"
|
||||||
|
|
@ -3688,60 +3679,60 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/config": {
|
"node_modules/@prisma/config": {
|
||||||
"version": "6.17.1",
|
"version": "6.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.18.0.tgz",
|
||||||
"integrity": "sha512-fs8wY6DsvOCzuiyWVckrVs1LOcbY4LZNz8ki4uUIQ28jCCzojTGqdLhN2Jl5lDnC1yI8/gNIKpsWDM8pLhOdwA==",
|
"integrity": "sha512-rgFzspCpwsE+q3OF/xkp0fI2SJ3PfNe9LLMmuSVbAZ4nN66WfBiKqJKo/hLz3ysxiPQZf8h1SMf2ilqPMeWATQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"c12": "3.1.0",
|
"c12": "3.1.0",
|
||||||
"deepmerge-ts": "7.1.5",
|
"deepmerge-ts": "7.1.5",
|
||||||
"effect": "3.16.12",
|
"effect": "3.18.4",
|
||||||
"empathic": "2.0.0"
|
"empathic": "2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/debug": {
|
"node_modules/@prisma/debug": {
|
||||||
"version": "6.17.1",
|
"version": "6.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.18.0.tgz",
|
||||||
"integrity": "sha512-Vf7Tt5Wh9XcndpbmeotuqOMLWPTjEKCsgojxXP2oxE1/xYe7PtnP76hsouG9vis6fctX+TxgmwxTuYi/+xc7dQ==",
|
"integrity": "sha512-PMVPMmxPj0ps1VY75DIrT430MoOyQx9hmm174k6cmLZpcI95rAPXOQ+pp8ANQkJtNyLVDxnxVJ0QLbrm/ViBcg==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines": {
|
"node_modules/@prisma/engines": {
|
||||||
"version": "6.17.1",
|
"version": "6.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.18.0.tgz",
|
||||||
"integrity": "sha512-D95Ik3GYZkqZ8lSR4EyFOJ/tR33FcYRP8kK61o+WMsyD10UfJwd7+YielflHfKwiGodcqKqoraWw8ElAgMDbPw==",
|
"integrity": "sha512-i5RzjGF/ex6AFgqEe2o1IW8iIxJGYVQJVRau13kHPYEL1Ck8Zvwuzamqed/1iIljs5C7L+Opiz5TzSsUebkriA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "6.17.1",
|
"@prisma/debug": "6.18.0",
|
||||||
"@prisma/engines-version": "6.17.1-1.272a37d34178c2894197e17273bf937f25acdeac",
|
"@prisma/engines-version": "6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
|
||||||
"@prisma/fetch-engine": "6.17.1",
|
"@prisma/fetch-engine": "6.18.0",
|
||||||
"@prisma/get-platform": "6.17.1"
|
"@prisma/get-platform": "6.18.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines-version": {
|
"node_modules/@prisma/engines-version": {
|
||||||
"version": "6.17.1-1.272a37d34178c2894197e17273bf937f25acdeac",
|
"version": "6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.17.1-1.272a37d34178c2894197e17273bf937f25acdeac.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f.tgz",
|
||||||
"integrity": "sha512-17140E3huOuD9lMdJ9+SF/juOf3WR3sTJMVyyenzqUPbuH+89nPhSWcrY+Mf7tmSs6HvaO+7S+HkELinn6bhdg==",
|
"integrity": "sha512-T7Af4QsJQnSgWN1zBbX+Cha5t4qjHRxoeoWpK4JugJzG/ipmmDMY5S+O0N1ET6sCBNVkf6lz+Y+ZNO9+wFU8pQ==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/fetch-engine": {
|
"node_modules/@prisma/fetch-engine": {
|
||||||
"version": "6.17.1",
|
"version": "6.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.18.0.tgz",
|
||||||
"integrity": "sha512-AYZiHOs184qkDMiTeshyJCtyL4yERkjfTkJiSJdYuSfc24m94lTNL5+GFinZ6vVz+ktX4NJzHKn1zIFzGTWrWg==",
|
"integrity": "sha512-TdaBvTtBwP3IoqVYoGIYpD4mWlk0pJpjTJjir/xLeNWlwog7Sl3bD2J0jJ8+5+q/6RBg+acb9drsv5W6lqae7A==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "6.17.1",
|
"@prisma/debug": "6.18.0",
|
||||||
"@prisma/engines-version": "6.17.1-1.272a37d34178c2894197e17273bf937f25acdeac",
|
"@prisma/engines-version": "6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
|
||||||
"@prisma/get-platform": "6.17.1"
|
"@prisma/get-platform": "6.18.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/get-platform": {
|
"node_modules/@prisma/get-platform": {
|
||||||
"version": "6.17.1",
|
"version": "6.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.18.0.tgz",
|
||||||
"integrity": "sha512-AKEn6fsfz0r482S5KRDFlIGEaq9wLNcgalD1adL+fPcFFblIKs1sD81kY/utrHdqKuVC6E1XSRpegDK3ZLL4Qg==",
|
"integrity": "sha512-uXNJCJGhxTCXo2B25Ta91Rk1/Nmlqg9p7G9GKh8TPhxvAyXCvMNQoogj4JLEUy+3ku8g59cpyQIKFhqY2xO2bg==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "6.17.1"
|
"@prisma/debug": "6.18.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@scarf/scarf": {
|
"node_modules/@scarf/scarf": {
|
||||||
|
|
@ -6953,9 +6944,9 @@
|
||||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||||
},
|
},
|
||||||
"node_modules/effect": {
|
"node_modules/effect": {
|
||||||
"version": "3.16.12",
|
"version": "3.18.4",
|
||||||
"resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz",
|
"resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz",
|
||||||
"integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==",
|
"integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standard-schema/spec": "^1.0.0",
|
"@standard-schema/spec": "^1.0.0",
|
||||||
|
|
@ -9542,9 +9533,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/load-esm": {
|
"node_modules/load-esm": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/load-esm/-/load-esm-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/load-esm/-/load-esm-1.0.3.tgz",
|
||||||
"integrity": "sha512-nVAvWk/jeyrWyXEAs84mpQCYccxRqgKY4OznLuJhJCa0XsPSfdOIr2zvBZEj3IHEHbX97jjscKRRV539bW0Gpw==",
|
"integrity": "sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
|
|
@ -10468,11 +10459,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-to-regexp": {
|
"node_modules/path-to-regexp": {
|
||||||
"version": "8.2.0",
|
"version": "8.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
|
||||||
"integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
|
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
|
||||||
"engines": {
|
"funding": {
|
||||||
"node": ">=16"
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-type": {
|
"node_modules/path-type": {
|
||||||
|
|
@ -10703,14 +10695,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prisma": {
|
"node_modules/prisma": {
|
||||||
"version": "6.17.1",
|
"version": "6.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.18.0.tgz",
|
||||||
"integrity": "sha512-ac6h0sM1Tg3zu8NInY+qhP/S9KhENVaw9n1BrGKQVFu05JT5yT5Qqqmb8tMRIE3ZXvVj4xcRA5yfrsy4X7Yy5g==",
|
"integrity": "sha512-bXWy3vTk8mnRmT+SLyZBQoC2vtV9Z8u7OHvEu+aULYxwiop/CPiFZ+F56KsNRNf35jw+8wcu8pmLsjxpBxAO9g==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/config": "6.17.1",
|
"@prisma/config": "6.18.0",
|
||||||
"@prisma/engines": "6.17.1"
|
"@prisma/engines": "6.18.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"prisma": "build/index.js"
|
"prisma": "build/index.js"
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
"@nestjs/platform-express": "^11.1.6",
|
"@nestjs/platform-express": "^11.1.6",
|
||||||
"@nestjs/schedule": "^6.0.0",
|
"@nestjs/schedule": "^6.0.0",
|
||||||
"@nestjs/swagger": "^11.2.0",
|
"@nestjs/swagger": "^11.2.0",
|
||||||
"@prisma/client": "^6.17.1",
|
"@prisma/client": "^6.18.0",
|
||||||
"bullmq": "^5.58.0",
|
"bullmq": "^5.58.0",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.2",
|
"class-validator": "^0.14.2",
|
||||||
|
|
@ -86,7 +86,7 @@
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"prisma": "^6.17.1",
|
"prisma": "^6.18.0",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"supertest": "^7.0.0",
|
"supertest": "^7.0.0",
|
||||||
"ts-jest": "^29.2.5",
|
"ts-jest": "^29.2.5",
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,28 @@
|
||||||
import { PrismaClient, Roles } from '@prisma/client';
|
// import { PrismaClient, Roles } from '@prisma/client';
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
// const prisma = new PrismaClient();
|
||||||
|
|
||||||
async function main() {
|
// async function main() {
|
||||||
const customerUsers = await prisma.users.findMany({
|
// const customerUsers = await prisma.users.findMany({
|
||||||
where: { role: Roles.CUSTOMER },
|
// where: { role: Roles.CUSTOMER },
|
||||||
orderBy: { email: 'asc' },
|
// orderBy: { email: 'asc' },
|
||||||
});
|
// });
|
||||||
|
|
||||||
let i = 0;
|
// let i = 0;
|
||||||
for (const u of customerUsers) {
|
// for (const u of customerUsers) {
|
||||||
await prisma.customers.upsert({
|
// await prisma.customers.upsert({
|
||||||
where: { user_id: u.id },
|
// where: { user_id: u.id },
|
||||||
update: {},
|
// update: {},
|
||||||
create: {
|
// create: {
|
||||||
user_id: u.id,
|
// user_id: u.id,
|
||||||
invoice_id: i % 2 === 0 ? 100000 + i : null, // 1 sur 2 a un invoice_id
|
// invoice_id: i % 2 === 0 ? 100000 + i : null, // 1 sur 2 a un invoice_id
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
i++;
|
// i++;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const total = await prisma.customers.count();
|
// const total = await prisma.customers.count();
|
||||||
console.log(`✓ Customers: ${total} rows`);
|
// console.log(`✓ Customers: ${total} rows`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
main().finally(() => prisma.$disconnect());
|
// main().finally(() => prisma.$disconnect());
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,45 @@
|
||||||
import { PrismaClient } from '@prisma/client';
|
// import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
// if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
||||||
console.log("⏭ Seed leave-requests ignoré (SKIP_LEAVE_REQUESTS=true)");
|
// console.log("⏭ Seed leave-requests ignoré (SKIP_LEAVE_REQUESTS=true)");
|
||||||
process.exit(0);
|
// process.exit(0);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
// const prisma = new PrismaClient();
|
||||||
|
|
||||||
function daysAgo(n: number) {
|
// function daysAgo(n: number) {
|
||||||
const d = new Date();
|
// const d = new Date();
|
||||||
d.setDate(d.getDate() - n);
|
// d.setDate(d.getDate() - n);
|
||||||
d.setHours(0,0,0,0);
|
// d.setHours(0,0,0,0);
|
||||||
return d;
|
// return d;
|
||||||
}
|
// }
|
||||||
|
|
||||||
async function main() {
|
// async function main() {
|
||||||
const employees = await prisma.employees.findMany({
|
// const employees = await prisma.employees.findMany({
|
||||||
include: { user: true },
|
// include: { user: true },
|
||||||
take: 10, // archive 10
|
// take: 10, // archive 10
|
||||||
});
|
// });
|
||||||
|
|
||||||
for (const e of employees) {
|
// for (const e of employees) {
|
||||||
await prisma.employeesArchive.create({
|
// await prisma.employeesArchive.create({
|
||||||
data: {
|
// data: {
|
||||||
employee_id: e.id,
|
// employee_id: e.id,
|
||||||
user_id: e.user_id,
|
// user_id: e.user_id,
|
||||||
first_name: e.user.first_name,
|
// first_name: e.user.first_name,
|
||||||
last_name: e.user.last_name,
|
// last_name: e.user.last_name,
|
||||||
external_payroll_id: e.external_payroll_id,
|
// external_payroll_id: e.external_payroll_id,
|
||||||
company_code: e.company_code,
|
// company_code: e.company_code,
|
||||||
first_work_day: e.first_work_day,
|
// first_work_day: e.first_work_day,
|
||||||
last_work_day: daysAgo(30),
|
// last_work_day: daysAgo(30),
|
||||||
supervisor_id: e.supervisor_id ?? null,
|
// supervisor_id: e.supervisor_id ?? null,
|
||||||
job_title: e.job_title,
|
// job_title: e.job_title,
|
||||||
is_supervisor: e.is_supervisor,
|
// is_supervisor: e.is_supervisor,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
const total = await prisma.employeesArchive.count();
|
// const total = await prisma.employeesArchive.count();
|
||||||
console.log(`✓ EmployeesArchive: ${total} rows (added 10)`);
|
// console.log(`✓ EmployeesArchive: ${total} rows (added 10)`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
main().finally(() => prisma.$disconnect());
|
// main().finally(() => prisma.$disconnect());
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
// prisma/mock-seeds-scripts/06-customers-archive.ts
|
// // prisma/mock-seeds-scripts/06-customers-archive.ts
|
||||||
import { PrismaClient } from '@prisma/client';
|
// import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
// if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
||||||
console.log("⏭ Seed leave-requests ignoré (SKIP_LEAVE_REQUESTS=true)");
|
// console.log("⏭ Seed leave-requests ignoré (SKIP_LEAVE_REQUESTS=true)");
|
||||||
process.exit(0);
|
// process.exit(0);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
// const prisma = new PrismaClient();
|
||||||
|
|
||||||
async function main() {
|
// async function main() {
|
||||||
const customers = await prisma.customers.findMany({
|
// const customers = await prisma.customers.findMany({
|
||||||
orderBy: { id: 'asc' },
|
// orderBy: { id: 'asc' },
|
||||||
take: 5,
|
// take: 5,
|
||||||
});
|
// });
|
||||||
|
|
||||||
for (const c of customers) {
|
// for (const c of customers) {
|
||||||
const invoiceId = 200000 + c.id; // déterministe, stable entre runs
|
// const invoiceId = 200000 + c.id; // déterministe, stable entre runs
|
||||||
|
|
||||||
await prisma.customersArchive.upsert({
|
// await prisma.customersArchive.upsert({
|
||||||
where: { invoice_id: invoiceId }, // invoice_id est unique
|
// where: { invoice_id: invoiceId }, // invoice_id est unique
|
||||||
update: {}, // idempotent
|
// update: {}, // idempotent
|
||||||
create: {
|
// create: {
|
||||||
customer_id: c.id,
|
// customer_id: c.id,
|
||||||
user_id: c.user_id,
|
// user_id: c.user_id,
|
||||||
invoice_id: invoiceId,
|
// invoice_id: invoiceId,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
const total = await prisma.customersArchive.count();
|
// const total = await prisma.customersArchive.count();
|
||||||
console.log(`✓ CustomersArchive upserted for ${customers.length} customers (total=${total})`);
|
// console.log(`✓ CustomersArchive upserted for ${customers.length} customers (total=${total})`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
main().finally(() => prisma.$disconnect());
|
// main().finally(() => prisma.$disconnect());
|
||||||
|
|
|
||||||
|
|
@ -1,87 +1,87 @@
|
||||||
import { PrismaClient, LeaveApprovalStatus, LeaveTypes } from '@prisma/client';
|
// import { PrismaClient, LeaveApprovalStatus, LeaveTypes } from '@prisma/client';
|
||||||
|
|
||||||
if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
// if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
||||||
console.log('?? Seed leave-requests ignoré (SKIP_LEAVE_REQUESTS=true)');
|
// console.log('?? Seed leave-requests ignor<6F> (SKIP_LEAVE_REQUESTS=true)');
|
||||||
process.exit(0);
|
// process.exit(0);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
// const prisma = new PrismaClient();
|
||||||
|
|
||||||
function daysAgo(n: number) {
|
// function daysAgo(n: number) {
|
||||||
const d = new Date();
|
// const d = new Date();
|
||||||
d.setUTCDate(d.getUTCDate() - n);
|
// d.setUTCDate(d.getUTCDate() - n);
|
||||||
d.setUTCHours(0, 0, 0, 0);
|
// d.setUTCHours(0, 0, 0, 0);
|
||||||
return d;
|
// return d;
|
||||||
}
|
// }
|
||||||
|
|
||||||
async function main() {
|
// async function main() {
|
||||||
const employees = await prisma.employees.findMany({ select: { id: true } });
|
// const employees = await prisma.employees.findMany({ select: { id: true } });
|
||||||
if (!employees.length) {
|
// if (!employees.length) {
|
||||||
throw new Error('Aucun employé trouvé. Exécute le seed employees avant celui-ci.');
|
// throw new Error('Aucun employ<6F> trouv<75>. Ex<45>cute le seed employees avant celui-ci.');
|
||||||
}
|
// }
|
||||||
|
|
||||||
const leaveCodes = await prisma.bankCodes.findMany({
|
// const leaveCodes = await prisma.bankCodes.findMany({
|
||||||
where: { type: { in: ['SICK', 'VACATION', 'HOLIDAY'] } },
|
// where: { type: { in: ['SICK', 'VACATION', 'HOLIDAY'] } },
|
||||||
select: { id: true, type: true },
|
// select: { id: true, type: true },
|
||||||
});
|
// });
|
||||||
if (!leaveCodes.length) {
|
// if (!leaveCodes.length) {
|
||||||
throw new Error("Aucun bank code trouvé avec type in ('SICK','VACATION','HOLIDAY'). Vérifie ta table bank_codes.");
|
// throw new Error("Aucun bank code trouv<75> avec type in ('SICK','VACATION','HOLIDAY'). V<>rifie ta table bank_codes.");
|
||||||
}
|
// }
|
||||||
|
|
||||||
const statuses = Object.values(LeaveApprovalStatus);
|
// const statuses = Object.values(LeaveApprovalStatus);
|
||||||
const created = [] as Array<{ id: number; employee_id: number; leave_type: LeaveTypes; date: Date; comment: string; approval_status: LeaveApprovalStatus; requested_hours: number; payable_hours: number | null }>;
|
// const created = [] as Array<{ id: number; employee_id: number; leave_type: LeaveTypes; date: Date; comment: string; approval_status: LeaveApprovalStatus; requested_hours: number; payable_hours: number | null }>;
|
||||||
|
|
||||||
const COUNT = 12;
|
// const COUNT = 12;
|
||||||
for (let i = 0; i < COUNT; i++) {
|
// for (let i = 0; i < COUNT; i++) {
|
||||||
const emp = employees[i % employees.length];
|
// const emp = employees[i % employees.length];
|
||||||
const leaveCode = leaveCodes[Math.floor(Math.random() * leaveCodes.length)];
|
// const leaveCode = leaveCodes[Math.floor(Math.random() * leaveCodes.length)];
|
||||||
|
|
||||||
const date = daysAgo(120 - i * 3);
|
// const date = daysAgo(120 - i * 3);
|
||||||
const status = statuses[(i + 2) % statuses.length];
|
// const status = statuses[(i + 2) % statuses.length];
|
||||||
const requestedHours = 4 + (i % 5); // 4 ? 8 h
|
// const requestedHours = 4 + (i % 5); // 4 ? 8 h
|
||||||
const payableHours = status === LeaveApprovalStatus.APPROVED ? Math.min(requestedHours, 8) : null;
|
// const payableHours = status === LeaveApprovalStatus.APPROVED ? Math.min(requestedHours, 8) : null;
|
||||||
|
|
||||||
const lr = await prisma.leaveRequests.create({
|
// const lr = await prisma.leaveRequests.create({
|
||||||
data: {
|
// data: {
|
||||||
employee_id: emp.id,
|
// employee_id: emp.id,
|
||||||
bank_code_id: leaveCode.id,
|
// bank_code_id: leaveCode.id,
|
||||||
leave_type: leaveCode.type as LeaveTypes,
|
// leave_type: leaveCode.type as LeaveTypes,
|
||||||
date,
|
// date,
|
||||||
comment: `Past leave #${i + 1} (${leaveCode.type})`,
|
// comment: `Past leave #${i + 1} (${leaveCode.type})`,
|
||||||
approval_status: status,
|
// approval_status: status,
|
||||||
requested_hours: requestedHours,
|
// requested_hours: requestedHours,
|
||||||
payable_hours: payableHours,
|
// payable_hours: payableHours,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
created.push({
|
// created.push({
|
||||||
id: lr.id,
|
// id: lr.id,
|
||||||
employee_id: lr.employee_id,
|
// employee_id: lr.employee_id,
|
||||||
leave_type: lr.leave_type,
|
// leave_type: lr.leave_type,
|
||||||
date: lr.date,
|
// date: lr.date,
|
||||||
comment: lr.comment,
|
// comment: lr.comment,
|
||||||
approval_status: lr.approval_status,
|
// approval_status: lr.approval_status,
|
||||||
requested_hours: requestedHours,
|
// requested_hours: requestedHours,
|
||||||
payable_hours: payableHours,
|
// payable_hours: payableHours,
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
for (const lr of created) {
|
// for (const lr of created) {
|
||||||
await prisma.leaveRequestsArchive.create({
|
// await prisma.leaveRequestsArchive.create({
|
||||||
data: {
|
// data: {
|
||||||
leave_request_id: lr.id,
|
// leave_request_id: lr.id,
|
||||||
employee_id: lr.employee_id,
|
// employee_id: lr.employee_id,
|
||||||
leave_type: lr.leave_type,
|
// leave_type: lr.leave_type,
|
||||||
date: lr.date,
|
// date: lr.date,
|
||||||
comment: lr.comment,
|
// comment: lr.comment,
|
||||||
approval_status: lr.approval_status,
|
// approval_status: lr.approval_status,
|
||||||
requested_hours: lr.requested_hours,
|
// requested_hours: lr.requested_hours,
|
||||||
payable_hours: lr.payable_hours,
|
// payable_hours: lr.payable_hours,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
console.log(`? LeaveRequestsArchive: ${created.length} rows`);
|
// console.log(`? LeaveRequestsArchive: ${created.length} rows`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
main().finally(() => prisma.$disconnect());
|
// main().finally(() => prisma.$disconnect());
|
||||||
|
|
@ -1,71 +1,71 @@
|
||||||
import { PrismaClient } from '@prisma/client';
|
// import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
// if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
||||||
console.log("⏭ Seed leave-requests ignoré (SKIP_LEAVE_REQUESTS=true)");
|
// console.log("⏭ Seed leave-requests ignoré (SKIP_LEAVE_REQUESTS=true)");
|
||||||
process.exit(0);
|
// process.exit(0);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
// const prisma = new PrismaClient();
|
||||||
|
|
||||||
function timeAt(h:number,m:number) {
|
// function timeAt(h:number,m:number) {
|
||||||
return new Date(Date.UTC(1970,0,1,h,m,0));
|
// return new Date(Date.UTC(1970,0,1,h,m,0));
|
||||||
}
|
// }
|
||||||
function daysAgo(n:number) {
|
// function daysAgo(n:number) {
|
||||||
const d = new Date();
|
// const d = new Date();
|
||||||
d.setUTCDate(d.getUTCDate() - n);
|
// d.setUTCDate(d.getUTCDate() - n);
|
||||||
d.setUTCHours(0,0,0,0);
|
// d.setUTCHours(0,0,0,0);
|
||||||
return d;
|
// return d;
|
||||||
}
|
// }
|
||||||
|
|
||||||
async function main() {
|
// async function main() {
|
||||||
const bankCodes = await prisma.bankCodes.findMany({ where: { categorie: 'SHIFT' }, select: { id: true } });
|
// const bankCodes = await prisma.bankCodes.findMany({ where: { categorie: 'SHIFT' }, select: { id: true } });
|
||||||
const employees = await prisma.employees.findMany({ select: { id: true } });
|
// const employees = await prisma.employees.findMany({ select: { id: true } });
|
||||||
|
|
||||||
for (const e of employees) {
|
// for (const e of employees) {
|
||||||
const tss = await prisma.timesheets.findMany({ where: { employee_id: e.id }, select: { id: true } });
|
// const tss = await prisma.timesheets.findMany({ where: { employee_id: e.id }, select: { id: true } });
|
||||||
if (!tss.length) continue;
|
// if (!tss.length) continue;
|
||||||
|
|
||||||
const createdShiftIds: number[] = [];
|
// const createdShiftIds: number[] = [];
|
||||||
for (let i = 0; i < 8; i++) {
|
// for (let i = 0; i < 8; i++) {
|
||||||
const ts = tss[i % tss.length];
|
// const ts = tss[i % tss.length];
|
||||||
const bc = bankCodes[i % bankCodes.length];
|
// const bc = bankCodes[i % bankCodes.length];
|
||||||
const date = daysAgo(200 + i); // bien dans le passé
|
// const date = daysAgo(200 + i); // bien dans le passé
|
||||||
const startH = 7 + (i % 4); // 7..10
|
// const startH = 7 + (i % 4); // 7..10
|
||||||
const endH = startH + 8; // 15..18
|
// const endH = startH + 8; // 15..18
|
||||||
|
|
||||||
const sh = await prisma.shifts.create({
|
// const sh = await prisma.shifts.create({
|
||||||
data: {
|
// data: {
|
||||||
timesheet_id: ts.id,
|
// timesheet_id: ts.id,
|
||||||
bank_code_id: bc.id,
|
// bank_code_id: bc.id,
|
||||||
comment: `Archived-era shift ${i + 1} for emp ${e.id}`,
|
// comment: `Archived-era shift ${i + 1} for emp ${e.id}`,
|
||||||
date,
|
// date,
|
||||||
start_time: timeAt(startH, 0),
|
// start_time: timeAt(startH, 0),
|
||||||
end_time: timeAt(endH, 0),
|
// end_time: timeAt(endH, 0),
|
||||||
is_approved: true,
|
// is_approved: true,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
createdShiftIds.push(sh.id);
|
// createdShiftIds.push(sh.id);
|
||||||
}
|
// }
|
||||||
|
|
||||||
for (const sid of createdShiftIds) {
|
// for (const sid of createdShiftIds) {
|
||||||
const s = await prisma.shifts.findUnique({ where: { id: sid } });
|
// const s = await prisma.shifts.findUnique({ where: { id: sid } });
|
||||||
if (!s) continue;
|
// if (!s) continue;
|
||||||
await prisma.shiftsArchive.create({
|
// await prisma.shiftsArchive.create({
|
||||||
data: {
|
// data: {
|
||||||
shift_id: s.id,
|
// shift_id: s.id,
|
||||||
timesheet_id: s.timesheet_id,
|
// timesheet_id: s.timesheet_id,
|
||||||
bank_code_id: s.bank_code_id,
|
// bank_code_id: s.bank_code_id,
|
||||||
comment: s.comment,
|
// comment: s.comment,
|
||||||
date: s.date,
|
// date: s.date,
|
||||||
start_time: s.start_time,
|
// start_time: s.start_time,
|
||||||
end_time: s.end_time,
|
// end_time: s.end_time,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
const total = await prisma.shiftsArchive.count();
|
// const total = await prisma.shiftsArchive.count();
|
||||||
console.log(`✓ ShiftsArchive: ${total} rows total`);
|
// console.log(`✓ ShiftsArchive: ${total} rows total`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
main().finally(() => prisma.$disconnect());
|
// main().finally(() => prisma.$disconnect());
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,65 @@
|
||||||
// 13-expenses-archive.ts
|
// // 13-expenses-archive.ts
|
||||||
import { PrismaClient, Expenses } from '@prisma/client';
|
// import { PrismaClient, Expenses } from '@prisma/client';
|
||||||
|
|
||||||
if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
// if (process.env.SKIP_LEAVE_REQUESTS === 'true') {
|
||||||
console.log("⏭ Seed leave-requests ignoré (SKIP_LEAVE_REQUESTS=true)");
|
// console.log("⏭ Seed leave-requests ignoré (SKIP_LEAVE_REQUESTS=true)");
|
||||||
process.exit(0);
|
// process.exit(0);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
// const prisma = new PrismaClient();
|
||||||
|
|
||||||
function daysAgo(n:number) {
|
// function daysAgo(n:number) {
|
||||||
const d = new Date();
|
// const d = new Date();
|
||||||
d.setUTCDate(d.getUTCDate() - n);
|
// d.setUTCDate(d.getUTCDate() - n);
|
||||||
d.setUTCHours(0,0,0,0);
|
// d.setUTCHours(0,0,0,0);
|
||||||
return d;
|
// return d;
|
||||||
}
|
// }
|
||||||
|
|
||||||
async function main() {
|
// async function main() {
|
||||||
const expenseCodes = await prisma.bankCodes.findMany({ where: { categorie: 'EXPENSE' }, select: { id: true } });
|
// const expenseCodes = await prisma.bankCodes.findMany({ where: { categorie: 'EXPENSE' }, select: { id: true } });
|
||||||
const timesheets = await prisma.timesheets.findMany({ select: { id: true } });
|
// const timesheets = await prisma.timesheets.findMany({ select: { id: true } });
|
||||||
|
|
||||||
// ✅ typer pour éviter never[]
|
// // ✅ typer pour éviter never[]
|
||||||
const created: Expenses[] = [];
|
// const created: Expenses[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < 4; i++) {
|
// for (let i = 0; i < 4; i++) {
|
||||||
const ts = timesheets[i % timesheets.length];
|
// const ts = timesheets[i % timesheets.length];
|
||||||
const bc = expenseCodes[i % expenseCodes.length];
|
// const bc = expenseCodes[i % expenseCodes.length];
|
||||||
|
|
||||||
const exp = await prisma.expenses.create({
|
// const exp = await prisma.expenses.create({
|
||||||
data: {
|
// data: {
|
||||||
timesheet_id: ts.id,
|
// timesheet_id: ts.id,
|
||||||
bank_code_id: bc.id,
|
// bank_code_id: bc.id,
|
||||||
date: daysAgo(60 + i),
|
// date: daysAgo(60 + i),
|
||||||
amount: (20 + i * 3.5).toFixed(2), // ok: Decimal accepte string
|
// amount: (20 + i * 3.5).toFixed(2), // ok: Decimal accepte string
|
||||||
attachment: null,
|
// attachment: null,
|
||||||
comment: `Old expense #${i + 1}`,
|
// comment: `Old expense #${i + 1}`,
|
||||||
is_approved: true,
|
// is_approved: true,
|
||||||
supervisor_comment: null,
|
// supervisor_comment: null,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
created.push(exp);
|
// created.push(exp);
|
||||||
}
|
// }
|
||||||
|
|
||||||
for (const e of created) {
|
// for (const e of created) {
|
||||||
await prisma.expensesArchive.create({
|
// await prisma.expensesArchive.create({
|
||||||
data: {
|
// data: {
|
||||||
expense_id: e.id,
|
// expense_id: e.id,
|
||||||
timesheet_id: e.timesheet_id,
|
// timesheet_id: e.timesheet_id,
|
||||||
bank_code_id: e.bank_code_id,
|
// bank_code_id: e.bank_code_id,
|
||||||
date: e.date,
|
// date: e.date,
|
||||||
amount: e.amount,
|
// amount: e.amount,
|
||||||
attachment: e.attachment,
|
// attachment: e.attachment,
|
||||||
comment: e.comment,
|
// comment: e.comment,
|
||||||
is_approved: e.is_approved,
|
// is_approved: e.is_approved,
|
||||||
supervisor_comment: e.supervisor_comment,
|
// supervisor_comment: e.supervisor_comment,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
const total = await prisma.expensesArchive.count();
|
// const total = await prisma.expensesArchive.count();
|
||||||
console.log(`✓ ExpensesArchive: ${total} total rows (added ${created.length})`);
|
// console.log(`✓ ExpensesArchive: ${total} total rows (added ${created.length})`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
main().finally(() => prisma.$disconnect());
|
// main().finally(() => prisma.$disconnect());
|
||||||
|
|
|
||||||
|
|
@ -14,99 +14,48 @@ datasource db {
|
||||||
url = env("DATABASE_URL_DEV")
|
url = env("DATABASE_URL_DEV")
|
||||||
}
|
}
|
||||||
|
|
||||||
model Users {
|
// model Users {
|
||||||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
// id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
||||||
first_name String
|
// first_name String
|
||||||
last_name String
|
// last_name String
|
||||||
email String @unique
|
// email String @unique
|
||||||
phone_number String @unique
|
// phone_number String @unique
|
||||||
residence String?
|
// residence String?
|
||||||
role Roles @default(GUEST)
|
// role Roles @default(GUEST)
|
||||||
|
|
||||||
employee Employees? @relation("UserEmployee")
|
// employee Employees? @relation("UserEmployee")
|
||||||
customer Customers? @relation("UserCustomer")
|
// oauth_sessions OAuthSessions[] @relation("UserOAuthSessions")
|
||||||
oauth_sessions OAuthSessions[] @relation("UserOAuthSessions")
|
// preferences Preferences? @relation("UserPreferences")
|
||||||
employees_archive EmployeesArchive[] @relation("UsersToEmployeesToArchive")
|
|
||||||
customer_archive CustomersArchive[] @relation("UserToCustomersToArchive")
|
|
||||||
preferences Preferences? @relation("UserPreferences")
|
|
||||||
|
|
||||||
@@map("users")
|
// @@map("users")
|
||||||
}
|
// }
|
||||||
|
|
||||||
model Employees {
|
// model Employees {
|
||||||
id Int @id @default(autoincrement())
|
// id Int @id @default(autoincrement())
|
||||||
user Users @relation("UserEmployee", fields: [user_id], references: [id])
|
// user Users @relation("UserEmployee", fields: [user_id], references: [id])
|
||||||
user_id String @unique @db.Uuid
|
// user_id String @unique @db.Uuid
|
||||||
supervisor Employees? @relation("EmployeeSupervisor", fields: [supervisor_id], references: [id])
|
// supervisor Employees? @relation("EmployeeSupervisor", fields: [supervisor_id], references: [id])
|
||||||
supervisor_id Int?
|
// supervisor_id Int?
|
||||||
|
|
||||||
external_payroll_id Int
|
// external_payroll_id Int
|
||||||
company_code Int
|
// company_code Int
|
||||||
first_work_day DateTime @db.Date
|
// first_work_day DateTime @db.Date
|
||||||
last_work_day DateTime? @db.Date
|
// last_work_day DateTime? @db.Date
|
||||||
job_title String?
|
// job_title String?
|
||||||
is_supervisor Boolean @default(false)
|
// is_supervisor Boolean @default(false)
|
||||||
|
|
||||||
|
|
||||||
crew Employees[] @relation("EmployeeSupervisor")
|
// crew Employees[] @relation("EmployeeSupervisor")
|
||||||
archive EmployeesArchive[] @relation("EmployeeToArchive")
|
// timesheet Timesheets[] @relation("TimesheetEmployee")
|
||||||
timesheet Timesheets[] @relation("TimesheetEmployee")
|
// leave_request LeaveRequests[] @relation("LeaveRequestEmployee")
|
||||||
leave_request LeaveRequests[] @relation("LeaveRequestEmployee")
|
// schedule_presets SchedulePresets[] @relation("SchedulePreset")
|
||||||
supervisor_archive EmployeesArchive[] @relation("EmployeeSupervisorToArchive")
|
|
||||||
schedule_presets SchedulePresets[] @relation("SchedulePreset")
|
|
||||||
|
|
||||||
@@map("employees")
|
// @@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 {
|
model LeaveRequests {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
employee Employees @relation("LeaveRequestEmployee", fields: [employee_id], references: [id])
|
// employee Employees @relation("LeaveRequestEmployee", fields: [employee_id], references: [id])
|
||||||
employee_id Int
|
employee_id Int
|
||||||
bank_code BankCodes @relation("LeaveRequestBankCodes", fields: [bank_code_id], references: [id])
|
bank_code BankCodes @relation("LeaveRequestBankCodes", fields: [bank_code_id], references: [id])
|
||||||
bank_code_id Int
|
bank_code_id Int
|
||||||
|
|
@ -158,7 +107,7 @@ view PayPeriods {
|
||||||
|
|
||||||
model Timesheets {
|
model Timesheets {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
employee Employees @relation("TimesheetEmployee", fields: [employee_id], references: [id])
|
// employee Employees @relation("TimesheetEmployee", fields: [employee_id], references: [id])
|
||||||
employee_id Int
|
employee_id Int
|
||||||
|
|
||||||
start_date DateTime @db.Date
|
start_date DateTime @db.Date
|
||||||
|
|
@ -186,7 +135,7 @@ model TimesheetsArchive {
|
||||||
|
|
||||||
model SchedulePresets {
|
model SchedulePresets {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
employee Employees @relation("SchedulePreset", fields: [employee_id], references: [id])
|
// employee Employees @relation("SchedulePreset", fields: [employee_id], references: [id])
|
||||||
employee_id Int
|
employee_id Int
|
||||||
|
|
||||||
name String
|
name String
|
||||||
|
|
@ -216,13 +165,6 @@ model SchedulePresetShifts {
|
||||||
@@map("schedule_preset_shifts")
|
@@map("schedule_preset_shifts")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
model Shifts {
|
model Shifts {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
timesheet Timesheets @relation("ShiftTimesheet", fields: [timesheet_id], references: [id])
|
timesheet Timesheets @relation("ShiftTimesheet", fields: [timesheet_id], references: [id])
|
||||||
|
|
@ -283,7 +225,7 @@ model Expenses {
|
||||||
attachment Int?
|
attachment Int?
|
||||||
|
|
||||||
date DateTime @db.Date
|
date DateTime @db.Date
|
||||||
amount Decimal @db.Money
|
amount Decimal? @db.Decimal(12,2)
|
||||||
mileage Decimal? @db.Decimal(12,2)
|
mileage Decimal? @db.Decimal(12,2)
|
||||||
comment String
|
comment String
|
||||||
supervisor_comment String?
|
supervisor_comment String?
|
||||||
|
|
@ -305,7 +247,7 @@ model ExpensesArchive {
|
||||||
archived_at DateTime @default(now())
|
archived_at DateTime @default(now())
|
||||||
bank_code_id Int
|
bank_code_id Int
|
||||||
date DateTime @db.Date
|
date DateTime @db.Date
|
||||||
amount Decimal? @db.Money
|
amount Decimal? @db.Decimal(12,2)
|
||||||
mileage Decimal? @db.Decimal(12,2)
|
mileage Decimal? @db.Decimal(12,2)
|
||||||
comment String?
|
comment String?
|
||||||
is_approved Boolean
|
is_approved Boolean
|
||||||
|
|
@ -316,7 +258,7 @@ model ExpensesArchive {
|
||||||
|
|
||||||
model OAuthSessions {
|
model OAuthSessions {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
user Users @relation("UserOAuthSessions", fields: [user_id], references: [id])
|
// user Users @relation("UserOAuthSessions", fields: [user_id], references: [id])
|
||||||
user_id String @db.Uuid
|
user_id String @db.Uuid
|
||||||
application String
|
application String
|
||||||
access_token String @unique
|
access_token String @unique
|
||||||
|
|
@ -385,7 +327,7 @@ model AttachmentVariants {
|
||||||
|
|
||||||
model Preferences {
|
model Preferences {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
user Users @relation("UserPreferences", fields: [user_id], references: [id])
|
// user Users @relation("UserPreferences", fields: [user_id], references: [id])
|
||||||
user_id String @unique @db.Uuid
|
user_id String @unique @db.Uuid
|
||||||
|
|
||||||
notifications Int @default(0)
|
notifications Int @default(0)
|
||||||
|
|
|
||||||
|
|
@ -2,58 +2,45 @@ import { BadRequestException, Module, ValidationPipe } from '@nestjs/common';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
// import { ArchivalModule } from './modules/archival/archival.module';
|
// import { ArchivalModule } from './modules/archival/archival.module';
|
||||||
import { AuthenticationModule } from './modules/authentication/auth.module';
|
import { AuthenticationModule } from './identity-and-account/authentication/auth.module';
|
||||||
import { BankCodesModule } from './modules/bank-codes/bank-codes.module';
|
// import { BankCodesModule } from './modules/bank-codes/bank-codes.module';
|
||||||
import { BusinessLogicsModule } from './modules/business-logics/business-logics.module';
|
|
||||||
// import { CsvExportModule } from './modules/exports/csv-exports.module';
|
// import { CsvExportModule } from './modules/exports/csv-exports.module';
|
||||||
import { CustomersModule } from './modules/customers/customers.module';
|
|
||||||
import { EmployeesModule } from './modules/employees/employees.module';
|
|
||||||
// import { ExpensesModule } from './modules/expenses/expenses.module';
|
|
||||||
import { HealthModule } from './health/health.module';
|
import { HealthModule } from './health/health.module';
|
||||||
import { HealthController } from './health/health.controller';
|
import { HealthController } from './health/health.controller';
|
||||||
// import { LeaveRequestsModule } from './modules/leave-requests/leave-requests.module';
|
|
||||||
import { NotificationsModule } from './modules/notifications/notifications.module';
|
import { NotificationsModule } from './modules/notifications/notifications.module';
|
||||||
import { OvertimeService } from './modules/business-logics/services/overtime.service';
|
import { PreferencesModule } from './identity-and-account/preferences/preferences.module';
|
||||||
import { PreferencesModule } from './modules/preferences/preferences.module';
|
|
||||||
import { PrismaModule } from './prisma/prisma.module';
|
import { PrismaModule } from './prisma/prisma.module';
|
||||||
import { ScheduleModule } from '@nestjs/schedule';
|
import { ScheduleModule } from '@nestjs/schedule';
|
||||||
import { ShiftsModule } from './modules/shifts/shifts.module';
|
import { UsersModule } from './identity-and-account/users-management/users.module';
|
||||||
import { TimesheetsModule } from './modules/timesheets/timesheets.module';
|
|
||||||
import { UsersModule } from './modules/users-management/users.module';
|
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { APP_FILTER, APP_PIPE } from '@nestjs/core';
|
import { APP_FILTER, APP_PIPE } from '@nestjs/core';
|
||||||
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
|
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
|
||||||
import { ValidationError } from 'class-validator';
|
import { ValidationError } from 'class-validator';
|
||||||
import { SchedulePresetsModule } from './modules/schedule-presets/schedule-presets.module';
|
import { PayperiodsModule } from './time-and-attendance/modules/pay-period/pay-periods.module';
|
||||||
import { PayperiodsModule } from './modules/pay-periods/pay-periods.module';
|
import { TimeAndAttendanceModule } from 'src/time-and-attendance/time-and-attendance.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
// ArchivalModule,
|
|
||||||
AuthenticationModule,
|
AuthenticationModule,
|
||||||
BankCodesModule,
|
// BankCodesModule,
|
||||||
BusinessLogicsModule,
|
|
||||||
ConfigModule.forRoot({isGlobal: true}),
|
ConfigModule.forRoot({isGlobal: true}),
|
||||||
// CsvExportModule,
|
// CsvExportModule,
|
||||||
CustomersModule,
|
// CustomersModule,
|
||||||
EmployeesModule,
|
// EmployeesModule,
|
||||||
// ExpensesModule,
|
|
||||||
HealthModule,
|
HealthModule,
|
||||||
// LeaveRequestsModule,
|
|
||||||
NotificationsModule,
|
NotificationsModule,
|
||||||
PayperiodsModule,
|
PayperiodsModule,
|
||||||
PreferencesModule,
|
PreferencesModule,
|
||||||
PrismaModule,
|
PrismaModule,
|
||||||
ScheduleModule.forRoot(), //cronjobs
|
ScheduleModule.forRoot(), //cronjobs
|
||||||
SchedulePresetsModule,
|
// ShiftsModule,
|
||||||
ShiftsModule,
|
TimeAndAttendanceModule,
|
||||||
TimesheetsModule,
|
// TimesheetsModule,
|
||||||
UsersModule,
|
UsersModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController, HealthController],
|
controllers: [AppController, HealthController],
|
||||||
providers: [
|
providers: [
|
||||||
AppService,
|
AppService,
|
||||||
OvertimeService,
|
|
||||||
{
|
{
|
||||||
provide: APP_FILTER,
|
provide: APP_FILTER,
|
||||||
useClass: HttpExceptionFilter
|
useClass: HttpExceptionFilter
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { UsersService } from 'src/modules/users-management/services/users.service';
|
import { UsersService } from 'src/identity-and-account/users-management/services/users.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthentikAuthService {
|
export class AuthentikAuthService {
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
// import { Body,Controller,Get,NotFoundException,Param,Patch } from '@nestjs/common';
|
||||||
|
// import { EmployeesService } from '../services/employees.service';
|
||||||
|
// import { CreateEmployeeDto } from '../dtos/create-employee.dto';
|
||||||
|
// import { UpdateEmployeeDto } from '../dtos/update-employee.dto';
|
||||||
|
// import { RolesAllowed } from '../../../common/decorators/roles.decorators';
|
||||||
|
// import { ApiBearerAuth, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
|
// import { EmployeeListItemDto } from '../dtos/list-employee.dto';
|
||||||
|
// import { EmployeesArchivalService } from '../services/employees-archival.service';
|
||||||
|
// import { EmployeeProfileItemDto } from 'src/modules/employees/dtos/profil-employee.dto';
|
||||||
|
|
||||||
|
// @ApiTags('Employees')
|
||||||
|
// @ApiBearerAuth('access-token')
|
||||||
|
// // @UseGuards()
|
||||||
|
// @Controller('employees')
|
||||||
|
// export class EmployeesController {
|
||||||
|
// constructor(
|
||||||
|
// private readonly employeesService: EmployeesService,
|
||||||
|
// private readonly archiveService: EmployeesArchivalService,
|
||||||
|
// ) {}
|
||||||
|
|
||||||
|
// @Get('employee-list')
|
||||||
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ACCOUNTING)
|
||||||
|
// @ApiOperation({summary: 'Find all employees with scoped info' })
|
||||||
|
// @ApiResponse({ status: 200, description: 'List of employees with scoped info found', type: EmployeeListItemDto, isArray: true })
|
||||||
|
// @ApiResponse({ status: 400, description: 'List of employees with scoped info not found' })
|
||||||
|
// findListEmployees(): Promise<EmployeeListItemDto[]> {
|
||||||
|
// return this.employeesService.findListEmployees();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Patch(':email')
|
||||||
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||||
|
// @ApiBearerAuth('access-token')
|
||||||
|
// @ApiOperation({ summary: 'Update, archive or restore an employee' })
|
||||||
|
// @ApiParam({ name: 'email', type: Number, description: 'Email of the employee' })
|
||||||
|
// @ApiResponse({ status: 200, description: 'Employee updated or restored', type: CreateEmployeeDto })
|
||||||
|
// @ApiResponse({ status: 202, description: 'Employee archived successfully', type: CreateEmployeeDto })
|
||||||
|
// @ApiResponse({ status: 404, description: 'Employee not found in active or archive' })
|
||||||
|
// async updateOrArchiveOrRestore(@Param('email') email: string, @Body() dto: UpdateEmployeeDto,) {
|
||||||
|
// // if last_work_day is set => archive the employee
|
||||||
|
// // else if employee is archived and first_work_day or last_work_day = null => restore
|
||||||
|
// //otherwise => standard update
|
||||||
|
// const result = await this.archiveService.patchEmployee(email, dto);
|
||||||
|
// if(!result) {
|
||||||
|
// throw new NotFoundException(`Employee with email: ${ email } is not found in active or archive.`)
|
||||||
|
// }
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //_____________________________________________________________________________________________
|
||||||
|
// // Deprecated or unused methods
|
||||||
|
// //_____________________________________________________________________________________________
|
||||||
|
|
||||||
|
// // @Post()
|
||||||
|
// // //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||||
|
// // @ApiOperation({summary: 'Create employee' })
|
||||||
|
// // @ApiResponse({ status: 201, description: 'Employee created', type: CreateEmployeeDto })
|
||||||
|
// // @ApiResponse({ status: 400, description: 'Incomplete task or invalid data' })
|
||||||
|
// // create(@Body() dto: CreateEmployeeDto): Promise<Employees> {
|
||||||
|
// // return this.employeesService.create(dto);
|
||||||
|
// // }
|
||||||
|
// // @Get()
|
||||||
|
// // //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ACCOUNTING)
|
||||||
|
// // @ApiOperation({summary: 'Find all employees' })
|
||||||
|
// // @ApiResponse({ status: 200, description: 'List of employees found', type: CreateEmployeeDto, isArray: true })
|
||||||
|
// // @ApiResponse({ status: 400, description: 'List of employees not found' })
|
||||||
|
// // findAll(): Promise<Employees[]> {
|
||||||
|
// // return this.employeesService.findAll();
|
||||||
|
// // }
|
||||||
|
|
||||||
|
|
||||||
|
// // @Get(':email')
|
||||||
|
// // //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR,RoleEnum.ACCOUNTING )
|
||||||
|
// // @ApiOperation({summary: 'Find employee' })
|
||||||
|
// // @ApiResponse({ status: 200, description: 'Employee found', type: CreateEmployeeDto })
|
||||||
|
// // @ApiResponse({ status: 400, description: 'Employee not found' })
|
||||||
|
// // findOne(@Param('email', ParseIntPipe) email: string): Promise<Employees> {
|
||||||
|
// // return this.employeesService.findOne(email);
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// @Get('profile/:email')
|
||||||
|
// @ApiOperation({summary: 'Find employee profile' })
|
||||||
|
// @ApiParam({ name: 'email', type: String, description: 'Identifier of the employee' })
|
||||||
|
// @ApiResponse({ status: 200, description: 'Employee profile found', type: EmployeeProfileItemDto })
|
||||||
|
// @ApiResponse({ status: 400, description: 'Employee profile not found' })
|
||||||
|
// findOneProfile(@Param('email') email: string): Promise<EmployeeProfileItemDto> {
|
||||||
|
// return this.employeesService.findOneProfile(email);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // @Delete(':email')
|
||||||
|
// // //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR )
|
||||||
|
// // @ApiOperation({summary: 'Delete employee' })
|
||||||
|
// // @ApiParam({ name: 'email', type: Number, description: 'Email of the employee to delete' })
|
||||||
|
// // @ApiResponse({ status: 204, description: 'Employee deleted' })
|
||||||
|
// // @ApiResponse({ status: 404, description: 'Employee not found' })
|
||||||
|
// // remove(@Param('email', ParseIntPipe) email: string): Promise<Employees> {
|
||||||
|
// // return this.employeesService.remove(email);
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// }
|
||||||
118
src/identity-and-account/employees/dtos/create-employee.dto.ts
Normal file
118
src/identity-and-account/employees/dtos/create-employee.dto.ts
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
// import {
|
||||||
|
// Allow,
|
||||||
|
// IsBoolean,
|
||||||
|
// IsDateString,
|
||||||
|
// IsEmail,
|
||||||
|
// IsInt,
|
||||||
|
// IsNotEmpty,
|
||||||
|
// IsOptional,
|
||||||
|
// IsPositive,
|
||||||
|
// IsString,
|
||||||
|
// IsUUID,
|
||||||
|
// } from 'class-validator';
|
||||||
|
// import { Type } from 'class-transformer';
|
||||||
|
// import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
// export class CreateEmployeeDto {
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: 1,
|
||||||
|
// description: 'Unique ID of an employee(primary-key, auto-incremented)',
|
||||||
|
// })
|
||||||
|
// @Allow()
|
||||||
|
// id: number;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: '0e6e2e1f-b157-4c7c-ae3f-999b3e4f914d',
|
||||||
|
// description: 'UUID of the user linked to that employee',
|
||||||
|
// })
|
||||||
|
// @IsUUID()
|
||||||
|
// @IsOptional()
|
||||||
|
// user_id?: string;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: 'Frodo',
|
||||||
|
// description: 'Employee`s first name',
|
||||||
|
// })
|
||||||
|
// @IsString()
|
||||||
|
// @IsNotEmpty()
|
||||||
|
// first_name: string;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: 'Baggins',
|
||||||
|
// description: 'Employee`s last name',
|
||||||
|
// })
|
||||||
|
// @IsString()
|
||||||
|
// @IsNotEmpty()
|
||||||
|
// last_name: string;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: 'i_cant_do_this_sam@targointernet.com',
|
||||||
|
// description: 'Employee`s email',
|
||||||
|
// })
|
||||||
|
// @IsEmail()
|
||||||
|
// @IsOptional()
|
||||||
|
// email: string;
|
||||||
|
|
||||||
|
|
||||||
|
// @IsOptional()
|
||||||
|
// @IsBoolean()
|
||||||
|
// is_supervisor: boolean;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: '82538437464',
|
||||||
|
// description: 'Employee`s phone number',
|
||||||
|
// })
|
||||||
|
// @IsString()
|
||||||
|
// phone_number: string;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: '1 Bagshot Row, Hobbiton, The Shire, Middle-earth',
|
||||||
|
// description: 'Employee`s residence',
|
||||||
|
// required: false,
|
||||||
|
// })
|
||||||
|
// @IsString()
|
||||||
|
// @IsOptional()
|
||||||
|
// residence?: string;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: 7464,
|
||||||
|
// description: 'external ID for the pay system',
|
||||||
|
// })
|
||||||
|
// @IsInt()
|
||||||
|
// @IsPositive()
|
||||||
|
// @Type(() => Number)
|
||||||
|
// external_payroll_id: number;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: 335567447,
|
||||||
|
// description: 'Employee`s company code',
|
||||||
|
// })
|
||||||
|
// @IsInt()
|
||||||
|
// @IsPositive()
|
||||||
|
// @Type(() => Number)
|
||||||
|
// company_code: number;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example:'technicient',
|
||||||
|
// description: 'employee`s job title',
|
||||||
|
// })
|
||||||
|
// @IsString()
|
||||||
|
// @IsOptional()
|
||||||
|
// job_title: string;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: '23/09/3018',
|
||||||
|
// description: 'Employee`s first working day',
|
||||||
|
// })
|
||||||
|
// @IsDateString()
|
||||||
|
// first_work_day: string;
|
||||||
|
|
||||||
|
// @ApiProperty({
|
||||||
|
// example: '25/03/3019',
|
||||||
|
// description: 'Employee`s last working day',
|
||||||
|
// required: false,
|
||||||
|
// })
|
||||||
|
// @IsDateString()
|
||||||
|
// @IsOptional()
|
||||||
|
// last_work_day?: string;
|
||||||
|
// }
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// export class EmployeeListItemDto {
|
||||||
|
// first_name: string;
|
||||||
|
// last_name: string;
|
||||||
|
// email: string;
|
||||||
|
// supervisor_full_name: string | null;
|
||||||
|
// company_name: number | null;
|
||||||
|
// job_title: string | null;
|
||||||
|
// }
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// export class EmployeeProfileItemDto {
|
||||||
|
// first_name: string;
|
||||||
|
// last_name: string;
|
||||||
|
// employee_full_name: string;
|
||||||
|
// supervisor_full_name: string | null;
|
||||||
|
// company_name: number | null;
|
||||||
|
// job_title: string | null;
|
||||||
|
// email: string | null;
|
||||||
|
// phone_number: string;
|
||||||
|
// first_work_day: string;
|
||||||
|
// last_work_day?: string | null;
|
||||||
|
// residence: string | null;
|
||||||
|
// }
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
// import { ApiProperty, PartialType } from '@nestjs/swagger';
|
||||||
|
// import { CreateEmployeeDto } from './create-employee.dto';
|
||||||
|
// import { IsDateString, IsOptional, Max } from 'class-validator';
|
||||||
|
|
||||||
|
// export class UpdateEmployeeDto extends PartialType(CreateEmployeeDto) {
|
||||||
|
// @ApiProperty({ required: false, type: Date, description: 'New hire date or undefined' })
|
||||||
|
// @IsDateString()
|
||||||
|
// @IsOptional()
|
||||||
|
// first_work_day?: string;
|
||||||
|
|
||||||
|
// @ApiProperty({ required: false, type: Date, description: 'Termination date (null to restore)' })
|
||||||
|
// @IsDateString()
|
||||||
|
// @IsOptional()
|
||||||
|
// last_work_day?: string;
|
||||||
|
|
||||||
|
// @ApiProperty({ required: false, type: Number, description: 'Supervisor ID' })
|
||||||
|
// @IsOptional()
|
||||||
|
// supervisor_id?: number;
|
||||||
|
|
||||||
|
// @IsOptional()
|
||||||
|
// phone_number: string;
|
||||||
|
// }
|
||||||
12
src/identity-and-account/employees/employees.module.ts
Normal file
12
src/identity-and-account/employees/employees.module.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
// import { Module } from '@nestjs/common';
|
||||||
|
// import { EmployeesController } from './controllers/employees.controller';
|
||||||
|
// import { EmployeesService } from './services/employees.service';
|
||||||
|
// import { SharedModule } from '../../time-and-attendance/modules/shared/shared.module';
|
||||||
|
|
||||||
|
// @Module({
|
||||||
|
// imports: [SharedModule],
|
||||||
|
// controllers: [EmployeesController],
|
||||||
|
// providers: [EmployeesService],
|
||||||
|
// exports: [EmployeesService ],
|
||||||
|
// })
|
||||||
|
// export class EmployeesModule {}
|
||||||
|
|
@ -0,0 +1,173 @@
|
||||||
|
// import { Injectable } from "@nestjs/common";
|
||||||
|
// import { Employees, EmployeesArchive, Users } from "@prisma/client";
|
||||||
|
// import { PrismaService } from "src/prisma/prisma.service";
|
||||||
|
// import { UpdateEmployeeDto } from "../dtos/update-employee.dto";
|
||||||
|
// import { toDateOrUndefined, toDateOrNull } from "../utils/employee.utils";
|
||||||
|
|
||||||
|
// @Injectable()
|
||||||
|
// export class EmployeesArchivalService {
|
||||||
|
// constructor(private readonly prisma: PrismaService) { }
|
||||||
|
|
||||||
|
// async patchEmployee(email: string, dto: UpdateEmployeeDto): Promise<Employees | EmployeesArchive | null> {
|
||||||
|
// // 1) Tenter sur employés actifs
|
||||||
|
// const active = await this.prisma.employees.findFirst({
|
||||||
|
// where: { user: { email } },
|
||||||
|
// include: { user: true },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (active) {
|
||||||
|
// // Archivage : si on reçoit un last_work_day défini et que l'employé n’est pas déjà terminé
|
||||||
|
// if (dto.last_work_day !== undefined && active.last_work_day == null && dto.last_work_day !== null) {
|
||||||
|
// return this.archiveOnTermination(active, dto);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Sinon, update standard (split Users/Employees)
|
||||||
|
// const {
|
||||||
|
// first_name,
|
||||||
|
// last_name,
|
||||||
|
// email: new_email,
|
||||||
|
// phone_number,
|
||||||
|
// residence,
|
||||||
|
// external_payroll_id,
|
||||||
|
// company_code,
|
||||||
|
// job_title,
|
||||||
|
// first_work_day,
|
||||||
|
// last_work_day,
|
||||||
|
// supervisor_id,
|
||||||
|
// is_supervisor,
|
||||||
|
// } = dto as any;
|
||||||
|
|
||||||
|
// const first_work_d = toDateOrUndefined(first_work_day);
|
||||||
|
// const last_work_d = Object.prototype.hasOwnProperty('last_work_day')
|
||||||
|
// ? toDateOrNull(last_work_day ?? null)
|
||||||
|
// : undefined;
|
||||||
|
|
||||||
|
// await this.prisma.$transaction(async (transaction) => {
|
||||||
|
// if (
|
||||||
|
// first_name !== undefined ||
|
||||||
|
// last_name !== undefined ||
|
||||||
|
// new_email !== undefined ||
|
||||||
|
// phone_number !== undefined ||
|
||||||
|
// residence !== undefined
|
||||||
|
// ) {
|
||||||
|
// await transaction.users.update({
|
||||||
|
// where: { id: active.user_id },
|
||||||
|
// data: {
|
||||||
|
// ...(first_name !== undefined ? { first_name } : {}),
|
||||||
|
// ...(last_name !== undefined ? { last_name } : {}),
|
||||||
|
// ...(email !== undefined ? { email: new_email } : {}),
|
||||||
|
// ...(phone_number !== undefined ? { phone_number } : {}),
|
||||||
|
// ...(residence !== undefined ? { residence } : {}),
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const updated = await transaction.employees.update({
|
||||||
|
// where: { id: active.id },
|
||||||
|
// data: {
|
||||||
|
// ...(external_payroll_id !== undefined ? { external_payroll_id } : {}),
|
||||||
|
// ...(company_code !== undefined ? { company_code } : {}),
|
||||||
|
// ...(job_title !== undefined ? { job_title } : {}),
|
||||||
|
// ...(first_work_d !== undefined ? { first_work_day: first_work_d } : {}),
|
||||||
|
// ...(last_work_d !== undefined ? { last_work_day: last_work_d } : {}),
|
||||||
|
// ...(is_supervisor !== undefined ? { is_supervisor } : {}),
|
||||||
|
// ...(supervisor_id !== undefined ? { supervisor_id } : {}),
|
||||||
|
// },
|
||||||
|
// include: { user: true },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return updated;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return this.prisma.employees.findFirst({ where: { user: { email } } });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const user = await this.prisma.users.findUnique({ where: { email } });
|
||||||
|
// if (!user) return null;
|
||||||
|
// // 2) Pas trouvé en actifs → regarder en archive (pour restauration)
|
||||||
|
// const archived = await this.prisma.employeesArchive.findFirst({
|
||||||
|
// where: { user_id: user.id },
|
||||||
|
// include: { user: true },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (archived) {
|
||||||
|
// // Condition de restauration : last_work_day === null ou first_work_day fourni
|
||||||
|
// const restore = dto.last_work_day === null || dto.first_work_day != null;
|
||||||
|
// if (restore) {
|
||||||
|
// return this.restoreEmployee(archived, dto);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // 3) Ni actif, ni archivé → 404 dans le controller
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //transfers the employee to archive and then delete from employees table
|
||||||
|
// private async archiveOnTermination(active: Employees & { user: Users }, dto: UpdateEmployeeDto): Promise<EmployeesArchive> {
|
||||||
|
// const last_work_d = toDateOrNull(dto.last_work_day!);
|
||||||
|
// if (!last_work_d) throw new Error('invalide last_work_day for archive');
|
||||||
|
// return this.prisma.$transaction(async transaction => {
|
||||||
|
// //detach crew from supervisor if employee is a supervisor
|
||||||
|
// await transaction.employees.updateMany({
|
||||||
|
// where: { supervisor_id: active.id },
|
||||||
|
// data: { supervisor_id: null },
|
||||||
|
// })
|
||||||
|
// const archived = await transaction.employeesArchive.create({
|
||||||
|
// data: {
|
||||||
|
// employee_id: active.id,
|
||||||
|
// user_id: active.user_id,
|
||||||
|
// first_name: active.user.first_name,
|
||||||
|
// last_name: active.user.last_name,
|
||||||
|
// company_code: active.company_code,
|
||||||
|
// job_title: active.job_title,
|
||||||
|
// first_work_day: active.first_work_day,
|
||||||
|
// last_work_day: last_work_d,
|
||||||
|
// supervisor_id: active.supervisor_id ?? null,
|
||||||
|
// is_supervisor: active.is_supervisor,
|
||||||
|
// external_payroll_id: active.external_payroll_id,
|
||||||
|
// },
|
||||||
|
// include: { user: true }
|
||||||
|
// });
|
||||||
|
// //delete from employees table
|
||||||
|
// await transaction.employees.delete({ where: { id: active.id } });
|
||||||
|
// //return archived employee
|
||||||
|
// return archived
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //transfers the employee from archive to the employees table
|
||||||
|
// private async restoreEmployee(archived: EmployeesArchive & { user: Users }, dto: UpdateEmployeeDto): Promise<Employees> {
|
||||||
|
// // const first_work_d = toDateOrUndefined(dto.first_work_day);
|
||||||
|
// return this.prisma.$transaction(async transaction => {
|
||||||
|
// //restores the archived employee into the employees table
|
||||||
|
// const restored = await transaction.employees.create({
|
||||||
|
// data: {
|
||||||
|
// user_id: archived.user_id,
|
||||||
|
// company_code: archived.company_code,
|
||||||
|
// job_title: archived.job_title,
|
||||||
|
// first_work_day: archived.first_work_day,
|
||||||
|
// last_work_day: null,
|
||||||
|
// is_supervisor: archived.is_supervisor ?? false,
|
||||||
|
// external_payroll_id: archived.external_payroll_id,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// //deleting archived entry by id
|
||||||
|
// await transaction.employeesArchive.delete({ where: { id: archived.id } });
|
||||||
|
|
||||||
|
// //return restored employee
|
||||||
|
// return restored;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //fetches all archived employees
|
||||||
|
// async findAllArchived(): Promise<EmployeesArchive[]> {
|
||||||
|
// return this.prisma.employeesArchive.findMany();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //fetches an archived employee
|
||||||
|
// async findOneArchived(id: number): Promise<EmployeesArchive> {
|
||||||
|
// return this.prisma.employeesArchive.findUniqueOrThrow({ where: { id } });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
230
src/identity-and-account/employees/services/employees.service.ts
Normal file
230
src/identity-and-account/employees/services/employees.service.ts
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
// import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
|
// import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
|
// import { EmployeeListItemDto } from '../dtos/list-employee.dto';
|
||||||
|
// import { EmployeeProfileItemDto } from '../dtos/profil-employee.dto';
|
||||||
|
|
||||||
|
// @Injectable()
|
||||||
|
// export class EmployeesService {
|
||||||
|
// constructor(private readonly prisma: PrismaService) { }
|
||||||
|
|
||||||
|
// findListEmployees(): Promise<EmployeeListItemDto[]> {
|
||||||
|
// return this.prisma.employees.findMany({
|
||||||
|
// select: {
|
||||||
|
// user: {
|
||||||
|
// select: {
|
||||||
|
// first_name: true,
|
||||||
|
// last_name: true,
|
||||||
|
// email: true,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// supervisor: {
|
||||||
|
// select: {
|
||||||
|
// user: {
|
||||||
|
// select: {
|
||||||
|
// first_name: true,
|
||||||
|
// last_name: true,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// job_title: true,
|
||||||
|
// company_code: true,
|
||||||
|
// }
|
||||||
|
// }).then(rows => rows.map(r => ({
|
||||||
|
// first_name: r.user.first_name,
|
||||||
|
// last_name: r.user.last_name,
|
||||||
|
// email: r.user.email,
|
||||||
|
// company_name: r.company_code,
|
||||||
|
// job_title: r.job_title,
|
||||||
|
// employee_full_name: `${r.user.first_name} ${r.user.last_name}`,
|
||||||
|
// supervisor_full_name: r.supervisor ? `${r.supervisor.user.first_name} ${r.supervisor.user.last_name}` : null,
|
||||||
|
// })),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async findOneProfile(email: string): Promise<EmployeeProfileItemDto> {
|
||||||
|
// const emp = await this.prisma.employees.findFirst({
|
||||||
|
// where: { user: { email } },
|
||||||
|
// select: {
|
||||||
|
// user: {
|
||||||
|
// select: {
|
||||||
|
// first_name: true,
|
||||||
|
// last_name: true,
|
||||||
|
// email: true,
|
||||||
|
// phone_number: true,
|
||||||
|
// residence: true,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// supervisor: {
|
||||||
|
// select: {
|
||||||
|
// user: {
|
||||||
|
// select: {
|
||||||
|
// first_name: true,
|
||||||
|
// last_name: true,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// job_title: true,
|
||||||
|
// company_code: true,
|
||||||
|
// first_work_day: true,
|
||||||
|
// last_work_day: true,
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// if (!emp) throw new NotFoundException(`Employee with email ${email} not found`);
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// first_name: emp.user.first_name,
|
||||||
|
// last_name: emp.user.last_name,
|
||||||
|
// email: emp.user.email,
|
||||||
|
// residence: emp.user.residence,
|
||||||
|
// phone_number: emp.user.phone_number,
|
||||||
|
// company_name: emp.company_code,
|
||||||
|
// job_title: emp.job_title,
|
||||||
|
// employee_full_name: `${emp.user.first_name} ${emp.user.last_name}`,
|
||||||
|
// first_work_day: emp.first_work_day.toISOString().slice(0, 10),
|
||||||
|
// last_work_day: emp.last_work_day ? emp.last_work_day.toISOString().slice(0, 10) : null,
|
||||||
|
// supervisor_full_name: emp.supervisor ? `${emp.supervisor.user.first_name}, ${emp.supervisor.user.last_name}` : null,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //_____________________________________________________________________________________________
|
||||||
|
// // Deprecated or unused methods
|
||||||
|
// //_____________________________________________________________________________________________
|
||||||
|
|
||||||
|
// // async create(dto: CreateEmployeeDto): Promise<Employees> {
|
||||||
|
// // const {
|
||||||
|
// // first_name,
|
||||||
|
// // last_name,
|
||||||
|
// // email,
|
||||||
|
// // phone_number,
|
||||||
|
// // residence,
|
||||||
|
// // external_payroll_id,
|
||||||
|
// // company_code,
|
||||||
|
// // job_title,
|
||||||
|
// // first_work_day,
|
||||||
|
// // last_work_day,
|
||||||
|
// // is_supervisor,
|
||||||
|
// // } = dto;
|
||||||
|
|
||||||
|
// // return this.prisma.$transaction(async (transaction) => {
|
||||||
|
// // const user: Users = await transaction.users.create({
|
||||||
|
// // data: {
|
||||||
|
// // first_name,
|
||||||
|
// // last_name,
|
||||||
|
// // email,
|
||||||
|
// // phone_number,
|
||||||
|
// // residence,
|
||||||
|
// // },
|
||||||
|
// // });
|
||||||
|
// // return transaction.employees.create({
|
||||||
|
// // data: {
|
||||||
|
// // user_id: user.id,
|
||||||
|
// // external_payroll_id,
|
||||||
|
// // company_code,
|
||||||
|
// // job_title,
|
||||||
|
// // first_work_day,
|
||||||
|
// // last_work_day,
|
||||||
|
// // is_supervisor,
|
||||||
|
// // },
|
||||||
|
// // });
|
||||||
|
// // });
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // findAll(): Promise<Employees[]> {
|
||||||
|
// // return this.prisma.employees.findMany({
|
||||||
|
// // include: { user: true },
|
||||||
|
// // });
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // async findOne(email: string): Promise<Employees> {
|
||||||
|
// // const emp = await this.prisma.employees.findFirst({
|
||||||
|
// // where: { user: { email } },
|
||||||
|
// // include: { user: true },
|
||||||
|
// // });
|
||||||
|
|
||||||
|
// // //add search for archived employees
|
||||||
|
// // if (!emp) {
|
||||||
|
// // throw new NotFoundException(`Employee with email: ${email} not found`);
|
||||||
|
// // }
|
||||||
|
// // return emp;
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // async update(
|
||||||
|
// // email: string,
|
||||||
|
// // dto: UpdateEmployeeDto,
|
||||||
|
// // ): Promise<Employees> {
|
||||||
|
// // const emp = await this.findOne(email);
|
||||||
|
|
||||||
|
// // const {
|
||||||
|
// // first_name,
|
||||||
|
// // last_name,
|
||||||
|
// // phone_number,
|
||||||
|
// // residence,
|
||||||
|
// // external_payroll_id,
|
||||||
|
// // company_code,
|
||||||
|
// // job_title,
|
||||||
|
// // first_work_day,
|
||||||
|
// // last_work_day,
|
||||||
|
// // is_supervisor,
|
||||||
|
// // email: new_email,
|
||||||
|
// // } = dto;
|
||||||
|
|
||||||
|
// // return this.prisma.$transaction(async (transaction) => {
|
||||||
|
// // if(
|
||||||
|
// // first_name !== undefined ||
|
||||||
|
// // last_name !== undefined ||
|
||||||
|
// // new_email !== undefined ||
|
||||||
|
// // phone_number !== undefined ||
|
||||||
|
// // residence !== undefined
|
||||||
|
// // ){
|
||||||
|
// // await transaction.users.update({
|
||||||
|
// // where: { id: emp.user_id },
|
||||||
|
// // data: {
|
||||||
|
// // ...(first_name !== undefined && { first_name }),
|
||||||
|
// // ...(last_name !== undefined && { last_name }),
|
||||||
|
// // ...(email !== undefined && { email }),
|
||||||
|
// // ...(phone_number !== undefined && { phone_number }),
|
||||||
|
// // ...(residence !== undefined && { residence }),
|
||||||
|
// // },
|
||||||
|
// // });
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // const updated = await transaction.employees.update({
|
||||||
|
// // where: { id: emp.id },
|
||||||
|
// // data: {
|
||||||
|
// // ...(external_payroll_id !== undefined && { external_payroll_id }),
|
||||||
|
// // ...(company_code !== undefined && { company_code }),
|
||||||
|
// // ...(first_work_day !== undefined && { first_work_day }),
|
||||||
|
// // ...(last_work_day !== undefined && { last_work_day }),
|
||||||
|
// // ...(job_title !== undefined && { job_title }),
|
||||||
|
// // ...(is_supervisor !== undefined && { is_supervisor }),
|
||||||
|
// // },
|
||||||
|
// // });
|
||||||
|
// // return updated;
|
||||||
|
// // });
|
||||||
|
// // }
|
||||||
|
|
||||||
|
|
||||||
|
// // async remove(email: string): Promise<Employees> {
|
||||||
|
|
||||||
|
// // const emp = await this.findOne(email);
|
||||||
|
|
||||||
|
// // return this.prisma.$transaction(async (transaction) => {
|
||||||
|
// // await transaction.employees.updateMany({
|
||||||
|
// // where: { supervisor_id: emp.id },
|
||||||
|
// // data: { supervisor_id: null },
|
||||||
|
// // });
|
||||||
|
// // const deleted_employee = await transaction.employees.delete({
|
||||||
|
// // where: {id: emp.id },
|
||||||
|
// // });
|
||||||
|
// // await transaction.users.delete({
|
||||||
|
// // where: { id: emp.user_id },
|
||||||
|
// // });
|
||||||
|
// // return deleted_employee;
|
||||||
|
// // });
|
||||||
|
// // }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// export function toDateOrNull(v?: string | null): Date | null {
|
||||||
|
// if (!v) return null;
|
||||||
|
// const day = new Date(v);
|
||||||
|
// return isNaN(day.getTime()) ? null : day;
|
||||||
|
// }
|
||||||
|
// export function toDateOrUndefined(v?: string | null): Date | undefined {
|
||||||
|
// const day = toDateOrNull(v ?? undefined);
|
||||||
|
// return day === null ? undefined : day;
|
||||||
|
// }
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
import { PreferencesController } from "./controllers/preferences.controller";
|
import { PreferencesController } from "./controllers/preferences.controller";
|
||||||
import { PreferencesService } from "./services/preferences.service";
|
import { PreferencesService } from "./services/preferences.service";
|
||||||
import { SharedModule } from "../shared/shared.module";
|
import { SharedModule } from "../../time-and-attendance/modules/shared/shared.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [SharedModule],
|
imports: [SharedModule],
|
||||||
|
|
@ -2,7 +2,7 @@ import { Injectable } from "@nestjs/common";
|
||||||
import { Preferences } from "@prisma/client";
|
import { Preferences } from "@prisma/client";
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
import { PrismaService } from "src/prisma/prisma.service";
|
||||||
import { PreferencesDto } from "../dtos/preferences.dto";
|
import { PreferencesDto } from "../dtos/preferences.dto";
|
||||||
import { EmailToIdResolver } from "src/modules/shared/utils/resolve-email-id.utils";
|
import { EmailToIdResolver } from "src/time-and-attendance/modules/shared/utils/resolve-email-id.utils";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PreferencesService {
|
export class PreferencesService {
|
||||||
|
|
@ -1,33 +1,33 @@
|
||||||
import { Controller, Get, NotFoundException, Param, ParseIntPipe, UseGuards } from "@nestjs/common";
|
// import { Controller, Get, NotFoundException, Param, ParseIntPipe, UseGuards } from "@nestjs/common";
|
||||||
import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
|
// import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
// import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||||
import { EmployeesArchive, Roles as RoleEnum } from '@prisma/client';
|
// import { EmployeesArchive, Roles as RoleEnum } from '@prisma/client';
|
||||||
import { EmployeesArchivalService } from "src/modules/employees/services/employees-archival.service";
|
// import { EmployeesArchivalService } from "src/modules/employees/services/employees-archival.service";
|
||||||
|
|
||||||
@ApiTags('Employee Archives')
|
// @ApiTags('Employee Archives')
|
||||||
// @UseGuards()
|
// // @UseGuards()
|
||||||
@Controller('archives/employees')
|
// @Controller('archives/employees')
|
||||||
export class EmployeesArchiveController {
|
// export class EmployeesArchiveController {
|
||||||
constructor(private readonly employeesArchiveService: EmployeesArchivalService) {}
|
// constructor(private readonly employeesArchiveService: EmployeesArchivalService) {}
|
||||||
|
|
||||||
@Get()
|
// @Get()
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||||
@ApiOperation({ summary: 'List of archived employees'})
|
// @ApiOperation({ summary: 'List of archived employees'})
|
||||||
@ApiResponse({ status: 200, description: 'List of archived employees', isArray: true })
|
// @ApiResponse({ status: 200, description: 'List of archived employees', isArray: true })
|
||||||
async findAllArchived(): Promise<EmployeesArchive[]> {
|
// async findAllArchived(): Promise<EmployeesArchive[]> {
|
||||||
return this.employeesArchiveService.findAllArchived();
|
// return this.employeesArchiveService.findAllArchived();
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Get()
|
// @Get()
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR,RoleEnum.SUPERVISOR)
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR,RoleEnum.SUPERVISOR)
|
||||||
@ApiOperation({ summary: 'Fetch employee in archives with its Id'})
|
// @ApiOperation({ summary: 'Fetch employee in archives with its Id'})
|
||||||
@ApiResponse({ status: 200, description: 'Archived employee found'})
|
// @ApiResponse({ status: 200, description: 'Archived employee found'})
|
||||||
async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise<EmployeesArchive> {
|
// async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise<EmployeesArchive> {
|
||||||
try{
|
// try{
|
||||||
return await this.employeesArchiveService.findOneArchived(id);
|
// return await this.employeesArchiveService.findOneArchived(id);
|
||||||
}catch {
|
// }catch {
|
||||||
throw new NotFoundException(`Archived employee #${id} not found`);
|
// throw new NotFoundException(`Archived employee #${id} not found`);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
@ -1,32 +1,32 @@
|
||||||
import { UseGuards, Controller, Get, Param, ParseIntPipe, NotFoundException } from "@nestjs/common";
|
// import { UseGuards, Controller, Get, Param, ParseIntPipe, NotFoundException } from "@nestjs/common";
|
||||||
import { ApiTags, ApiOperation, ApiResponse } from "@nestjs/swagger";
|
// import { ApiTags, ApiOperation, ApiResponse } from "@nestjs/swagger";
|
||||||
import { ExpensesArchive,Roles as RoleEnum } from "@prisma/client";
|
// import { ExpensesArchive,Roles as RoleEnum } from "@prisma/client";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
// import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||||
import { ExpensesArchivalService } from "src/modules/expenses/services/expenses-archival.service";
|
// import { ExpensesArchivalService } from "src/time-and-attendance/modules/expenses/services/expenses-archival.service";
|
||||||
|
|
||||||
@ApiTags('Expense Archives')
|
// @ApiTags('Expense Archives')
|
||||||
// @UseGuards()
|
// // @UseGuards()
|
||||||
@Controller('archives/expenses')
|
// @Controller('archives/expenses')
|
||||||
export class ExpensesArchiveController {
|
// export class ExpensesArchiveController {
|
||||||
constructor(private readonly expensesService: ExpensesArchivalService) {}
|
// constructor(private readonly expensesService: ExpensesArchivalService) {}
|
||||||
|
|
||||||
@Get()
|
// @Get()
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||||
@ApiOperation({ summary: 'List of archived expenses'})
|
// @ApiOperation({ summary: 'List of archived expenses'})
|
||||||
@ApiResponse({ status: 200, description: 'List of archived expenses', isArray: true })
|
// @ApiResponse({ status: 200, description: 'List of archived expenses', isArray: true })
|
||||||
async findAllArchived(): Promise<ExpensesArchive[]> {
|
// async findAllArchived(): Promise<ExpensesArchive[]> {
|
||||||
return this.expensesService.findAllArchived();
|
// return this.expensesService.findAllArchived();
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Get()
|
// @Get()
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||||
@ApiOperation({ summary: 'Fetch expense in archives with its Id'})
|
// @ApiOperation({ summary: 'Fetch expense in archives with its Id'})
|
||||||
@ApiResponse({ status: 200, description: 'Archived expense found'})
|
// @ApiResponse({ status: 200, description: 'Archived expense found'})
|
||||||
async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise<ExpensesArchive> {
|
// async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise<ExpensesArchive> {
|
||||||
try{
|
// try{
|
||||||
return await this.expensesService.findOneArchived(id);
|
// return await this.expensesService.findOneArchived(id);
|
||||||
}catch {
|
// }catch {
|
||||||
throw new NotFoundException(`Archived expense #${id} not found`);
|
// throw new NotFoundException(`Archived expense #${id} not found`);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Controller } from '@nestjs/common';
|
// import { Controller } from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
// import { ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
@ApiTags('LeaveRequests Archives')
|
// @ApiTags('LeaveRequests Archives')
|
||||||
// @UseGuards()
|
// // @UseGuards()
|
||||||
@Controller('archives/leaveRequests')
|
// @Controller('archives/leaveRequests')
|
||||||
export class LeaveRequestsArchiveController {}
|
// export class LeaveRequestsArchiveController {}
|
||||||
|
|
@ -1,32 +1,32 @@
|
||||||
import { Get, Param, ParseIntPipe, NotFoundException, Controller, UseGuards } from "@nestjs/common";
|
// import { Get, Param, ParseIntPipe, NotFoundException, Controller, UseGuards } from "@nestjs/common";
|
||||||
import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
|
// import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
|
||||||
import { ShiftsArchive, Roles as RoleEnum } from "@prisma/client";
|
// import { ShiftsArchive, Roles as RoleEnum } from "@prisma/client";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
// import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||||
import { ShiftsArchivalService } from "src/modules/shifts/services/shifts-archival.service";
|
// import { ShiftsArchivalService } from "src/time-and-attendance/modules/time-tracker/shifts/services/shifts-archival.service";
|
||||||
|
|
||||||
@ApiTags('Shift Archives')
|
// @ApiTags('Shift Archives')
|
||||||
// @UseGuards()
|
// // @UseGuards()
|
||||||
@Controller('archives/shifts')
|
// @Controller('archives/shifts')
|
||||||
export class ShiftsArchiveController {
|
// export class ShiftsArchiveController {
|
||||||
constructor(private readonly shiftsService: ShiftsArchivalService) {}
|
// constructor(private readonly shiftsService: ShiftsArchivalService) {}
|
||||||
|
|
||||||
@Get()
|
// @Get()
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||||
@ApiOperation({ summary: 'List of archived shifts'})
|
// @ApiOperation({ summary: 'List of archived shifts'})
|
||||||
@ApiResponse({ status: 200, description: 'List of archived shifts', isArray: true })
|
// @ApiResponse({ status: 200, description: 'List of archived shifts', isArray: true })
|
||||||
async findAllArchived(): Promise<ShiftsArchive[]> {
|
// async findAllArchived(): Promise<ShiftsArchive[]> {
|
||||||
return this.shiftsService.findAllArchived();
|
// return this.shiftsService.findAllArchived();
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Get()
|
// @Get()
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR,RoleEnum.SUPERVISOR)
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR,RoleEnum.SUPERVISOR)
|
||||||
@ApiOperation({ summary: 'Fetch shift in archives with its Id'})
|
// @ApiOperation({ summary: 'Fetch shift in archives with its Id'})
|
||||||
@ApiResponse({ status: 200, description: 'Archived shift found'})
|
// @ApiResponse({ status: 200, description: 'Archived shift found'})
|
||||||
async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise<ShiftsArchive> {
|
// async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise<ShiftsArchive> {
|
||||||
try{
|
// try{
|
||||||
return await this.shiftsService.findOneArchived(id);
|
// return await this.shiftsService.findOneArchived(id);
|
||||||
}catch {
|
// }catch {
|
||||||
throw new NotFoundException(`Archived shift #${id} not found`);
|
// throw new NotFoundException(`Archived shift #${id} not found`);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
@ -1,33 +1,33 @@
|
||||||
import { Controller, Get, NotFoundException, Param, ParseIntPipe, UseGuards } from "@nestjs/common";
|
// import { Controller, Get, NotFoundException, Param, ParseIntPipe, UseGuards } from "@nestjs/common";
|
||||||
import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
|
// import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
// import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
||||||
import { TimesheetsArchive, Roles as RoleEnum } from '@prisma/client';
|
// import { TimesheetsArchive, Roles as RoleEnum } from '@prisma/client';
|
||||||
import { TimesheetArchiveService } from "src/modules/timesheets/services/timesheet-archive.service";
|
// import { TimesheetArchiveService } from "src/time-and-attendance/modules/time-tracker/timesheets/services/timesheet-archive.service";
|
||||||
|
|
||||||
@ApiTags('Timesheet Archives')
|
// @ApiTags('Timesheet Archives')
|
||||||
// @UseGuards()
|
// // @UseGuards()
|
||||||
@Controller('archives/timesheets')
|
// @Controller('archives/timesheets')
|
||||||
export class TimesheetsArchiveController {
|
// export class TimesheetsArchiveController {
|
||||||
constructor(private readonly timesheetsService: TimesheetArchiveService) {}
|
// constructor(private readonly timesheetsService: TimesheetArchiveService) {}
|
||||||
|
|
||||||
@Get()
|
// @Get()
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||||
@ApiOperation({ summary: 'List of archived timesheets'})
|
// @ApiOperation({ summary: 'List of archived timesheets'})
|
||||||
@ApiResponse({ status: 200, description: 'List of archived timesheets', isArray: true })
|
// @ApiResponse({ status: 200, description: 'List of archived timesheets', isArray: true })
|
||||||
async findAllArchived(): Promise<TimesheetsArchive[]> {
|
// async findAllArchived(): Promise<TimesheetsArchive[]> {
|
||||||
return this.timesheetsService.findAllArchived();
|
// return this.timesheetsService.findAllArchived();
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Get()
|
// @Get()
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
||||||
@ApiOperation({ summary: 'Fetch timesheet in archives with its Id'})
|
// @ApiOperation({ summary: 'Fetch timesheet in archives with its Id'})
|
||||||
@ApiResponse({ status: 200, description: 'Archived timesheet found'})
|
// @ApiResponse({ status: 200, description: 'Archived timesheet found'})
|
||||||
async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise<TimesheetsArchive> {
|
// async findOneArchived(@Param('id', ParseIntPipe) id: number ): Promise<TimesheetsArchive> {
|
||||||
try{
|
// try{
|
||||||
return await this.timesheetsService.findOneArchived(id);
|
// return await this.timesheetsService.findOneArchived(id);
|
||||||
}catch {
|
// }catch {
|
||||||
throw new NotFoundException(`Archived timesheet #${id} not found`);
|
// throw new NotFoundException(`Archived timesheet #${id} not found`);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
@ -1,38 +1,38 @@
|
||||||
import { Injectable, Logger } from "@nestjs/common";
|
// import { Injectable, Logger } from "@nestjs/common";
|
||||||
import { Cron } from "@nestjs/schedule";
|
// import { Cron } from "@nestjs/schedule";
|
||||||
import { ExpensesArchivalService } from "src/modules/expenses/services/expenses-archival.service";
|
// import { ExpensesArchivalService } from "src/time-and-attendance/modules/expenses/services/expenses-archival.service";
|
||||||
import { ShiftsArchivalService } from "src/modules/shifts/services/shifts-archival.service";
|
// import { ShiftsArchivalService } from "src/time-and-attendance/modules/time-tracker/shifts/services/shifts-archival.service";
|
||||||
import { TimesheetArchiveService } from "src/modules/timesheets/services/timesheet-archive.service";
|
// import { TimesheetArchiveService } from "src/time-and-attendance/modules/time-tracker/timesheets/services/timesheet-archive.service";
|
||||||
|
|
||||||
@Injectable()
|
// @Injectable()
|
||||||
export class ArchivalService {
|
// export class ArchivalService {
|
||||||
private readonly logger = new Logger(ArchivalService.name);
|
// private readonly logger = new Logger(ArchivalService.name);
|
||||||
|
|
||||||
constructor(
|
// constructor(
|
||||||
private readonly timesheetsService: TimesheetArchiveService,
|
// private readonly timesheetsService: TimesheetArchiveService,
|
||||||
private readonly expensesService: ExpensesArchivalService,
|
// private readonly expensesService: ExpensesArchivalService,
|
||||||
private readonly shiftsService: ShiftsArchivalService,
|
// private readonly shiftsService: ShiftsArchivalService,
|
||||||
) {}
|
// ) {}
|
||||||
|
|
||||||
@Cron('0 0 3 * * 1', {timeZone:'America/Toronto'}) // chaque premier lundi du mois à 03h00
|
// @Cron('0 0 3 * * 1', {timeZone:'America/Toronto'}) // chaque premier lundi du mois à 03h00
|
||||||
async handleMonthlyArchival() {
|
// async handleMonthlyArchival() {
|
||||||
const today = new Date();
|
// const today = new Date();
|
||||||
const dayOfMonth = today.getDate();
|
// const dayOfMonth = today.getDate();
|
||||||
|
|
||||||
if (dayOfMonth > 7) {
|
// if (dayOfMonth > 7) {
|
||||||
this.logger.warn('Archive {awaiting 1st monday of the month for archivation process}')
|
// this.logger.warn('Archive {awaiting 1st monday of the month for archivation process}')
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.logger.log('monthly archivation in process');
|
// this.logger.log('monthly archivation in process');
|
||||||
try {
|
// try {
|
||||||
await this.timesheetsService.archiveOld();
|
// await this.timesheetsService.archiveOld();
|
||||||
await this.expensesService.archiveOld();
|
// await this.expensesService.archiveOld();
|
||||||
await this.shiftsService.archiveOld();
|
// await this.shiftsService.archiveOld();
|
||||||
// await this.leaveRequestsService.archiveExpired();
|
// // await this.leaveRequestsService.archiveExpired();
|
||||||
this.logger.log('archivation process done');
|
// this.logger.log('archivation process done');
|
||||||
} catch (err) {
|
// } catch (err) {
|
||||||
this.logger.error('an error occured during archivation process ', err);
|
// this.logger.error('an error occured during archivation process ', err);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
@ -4,8 +4,6 @@ import {
|
||||||
Controller,NotFoundException, UseInterceptors, Post, Get, Param, Res,
|
Controller,NotFoundException, UseInterceptors, Post, Get, Param, Res,
|
||||||
UploadedFile, BadRequestException, UnsupportedMediaTypeException, Body, Delete,
|
UploadedFile, BadRequestException, UnsupportedMediaTypeException, Body, Delete,
|
||||||
Query,
|
Query,
|
||||||
DefaultValuePipe,
|
|
||||||
ParseIntPipe
|
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
import { maxUploadBytes, allowedMimes } from "../config/upload.config";
|
import { maxUploadBytes, allowedMimes } from "../config/upload.config";
|
||||||
import { memoryStorage } from 'multer';
|
import { memoryStorage } from 'multer';
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { Module } from "@nestjs/common";
|
// import { Module } from "@nestjs/common";
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
// import { PrismaService } from "src/prisma/prisma.service";
|
||||||
import { BankCodesControllers } from "./controllers/bank-codes.controller";
|
// import { BankCodesControllers } from "./controllers/bank-codes.controller";
|
||||||
import { BankCodesService } from "./services/bank-codes.service";
|
// import { BankCodesService } from "./services/bank-codes.service";
|
||||||
|
|
||||||
@Module({
|
// @Module({
|
||||||
controllers: [BankCodesControllers],
|
// controllers: [BankCodesControllers],
|
||||||
providers: [BankCodesService, PrismaService],
|
// providers: [BankCodesService, PrismaService],
|
||||||
})
|
// })
|
||||||
|
|
||||||
export class BankCodesModule {}
|
// export class BankCodesModule {}
|
||||||
|
|
@ -1,49 +1,49 @@
|
||||||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from "@nestjs/common";
|
// import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from "@nestjs/common";
|
||||||
import { BankCodesService } from "../services/bank-codes.service";
|
// import { BankCodesService } from "../services/bank-codes.service";
|
||||||
import { CreateBankCodeDto } from "../dtos/create-bank-code.dto";
|
// import { CreateBankCodeDto } from "../dtos/create-bank-code.dto";
|
||||||
import { UpdateBankCodeDto } from "../dtos/update-bank-code.dto";
|
// import { UpdateBankCodeDto } from "../dtos/update-bank-code.dto";
|
||||||
import { ApiBadRequestResponse, ApiNotFoundResponse, ApiOperation, ApiResponse } from "@nestjs/swagger";
|
// import { ApiBadRequestResponse, ApiNotFoundResponse, ApiOperation, ApiResponse } from "@nestjs/swagger";
|
||||||
|
|
||||||
@Controller('bank-codes')
|
// @Controller('bank-codes')
|
||||||
export class BankCodesControllers {
|
// export class BankCodesControllers {
|
||||||
constructor(private readonly bankCodesService: BankCodesService) {}
|
// constructor(private readonly bankCodesService: BankCodesService) {}
|
||||||
//_____________________________________________________________________________________________
|
// //_____________________________________________________________________________________________
|
||||||
// Deprecated or unused methods
|
// // Deprecated or unused methods
|
||||||
//_____________________________________________________________________________________________
|
// //_____________________________________________________________________________________________
|
||||||
|
|
||||||
// @Post()
|
// // @Post()
|
||||||
// @ApiOperation({ summary: 'Create a new bank code' })
|
// // @ApiOperation({ summary: 'Create a new bank code' })
|
||||||
// @ApiResponse({ status: 201, description: 'Bank code successfully created.' })
|
// // @ApiResponse({ status: 201, description: 'Bank code successfully created.' })
|
||||||
// @ApiBadRequestResponse({ description: 'Invalid input data.' })
|
// // @ApiBadRequestResponse({ description: 'Invalid input data.' })
|
||||||
// create(@Body() dto: CreateBankCodeDto) {
|
// // create(@Body() dto: CreateBankCodeDto) {
|
||||||
// return this.bankCodesService.create(dto);
|
// // return this.bankCodesService.create(dto);
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // @Get()
|
||||||
|
// // @ApiOperation({ summary: 'Retrieve all bank codes' })
|
||||||
|
// // @ApiResponse({ status: 200, description: 'List of bank codes.' })
|
||||||
|
// // findAll() {
|
||||||
|
// // return this.bankCodesService.findAll();
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // @Get(':id')
|
||||||
|
// // @ApiOperation({ summary: 'Retrieve a bank code by its ID' })
|
||||||
|
// // @ApiNotFoundResponse({ description: 'Bank code not found.' })
|
||||||
|
// // findOne(@Param('id', ParseIntPipe) id: number){
|
||||||
|
// // return this.bankCodesService.findOne(id);
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // @Patch(':id')
|
||||||
|
// // @ApiOperation({ summary: 'Update an existing bank code' })
|
||||||
|
// // @ApiNotFoundResponse({ description: 'Bank code not found.' })
|
||||||
|
// // update(@Param('id', ParseIntPipe) id: number, @Body() dto: UpdateBankCodeDto) {
|
||||||
|
// // return this.bankCodesService.update(id, dto)
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// // @Delete(':id')
|
||||||
|
// // @ApiOperation({ summary: 'Delete a bank code' })
|
||||||
|
// // @ApiNotFoundResponse({ description: 'Bank code not found.' })
|
||||||
|
// // remove(@Param('id', ParseIntPipe) id: number) {
|
||||||
|
// // return this.bankCodesService.remove(id);
|
||||||
|
// // }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// @Get()
|
|
||||||
// @ApiOperation({ summary: 'Retrieve all bank codes' })
|
|
||||||
// @ApiResponse({ status: 200, description: 'List of bank codes.' })
|
|
||||||
// findAll() {
|
|
||||||
// return this.bankCodesService.findAll();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Get(':id')
|
|
||||||
// @ApiOperation({ summary: 'Retrieve a bank code by its ID' })
|
|
||||||
// @ApiNotFoundResponse({ description: 'Bank code not found.' })
|
|
||||||
// findOne(@Param('id', ParseIntPipe) id: number){
|
|
||||||
// return this.bankCodesService.findOne(id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Patch(':id')
|
|
||||||
// @ApiOperation({ summary: 'Update an existing bank code' })
|
|
||||||
// @ApiNotFoundResponse({ description: 'Bank code not found.' })
|
|
||||||
// update(@Param('id', ParseIntPipe) id: number, @Body() dto: UpdateBankCodeDto) {
|
|
||||||
// return this.bankCodesService.update(id, dto)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Delete(':id')
|
|
||||||
// @ApiOperation({ summary: 'Delete a bank code' })
|
|
||||||
// @ApiNotFoundResponse({ description: 'Bank code not found.' })
|
|
||||||
// remove(@Param('id', ParseIntPipe) id: number) {
|
|
||||||
// return this.bankCodesService.remove(id);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +1,46 @@
|
||||||
import { ApiProperty } from "@nestjs/swagger";
|
// import { ApiProperty } from "@nestjs/swagger";
|
||||||
import { Type } from "class-transformer";
|
// import { Type } from "class-transformer";
|
||||||
import { Allow, IsNotEmpty, IsNumber, IsString } from "class-validator";
|
// import { Allow, IsNotEmpty, IsNumber, IsString } from "class-validator";
|
||||||
|
|
||||||
export class CreateBankCodeDto {
|
// export class CreateBankCodeDto {
|
||||||
@ApiProperty({
|
// @ApiProperty({
|
||||||
example: 1,
|
// example: 1,
|
||||||
description: 'Unique ID of a bank-code (auto-generated)',
|
// description: 'Unique ID of a bank-code (auto-generated)',
|
||||||
readOnly: true,
|
// readOnly: true,
|
||||||
})
|
// })
|
||||||
@Allow()
|
// @Allow()
|
||||||
id: number;
|
// id: number;
|
||||||
|
|
||||||
@ApiProperty({
|
// @ApiProperty({
|
||||||
example: 'regular, vacation, emergency, sick, parental, etc',
|
// example: 'regular, vacation, emergency, sick, parental, etc',
|
||||||
description: 'Type of codes',
|
// description: 'Type of codes',
|
||||||
})
|
// })
|
||||||
@IsString()
|
// @IsString()
|
||||||
@IsNotEmpty()
|
// @IsNotEmpty()
|
||||||
type: string;
|
// type: string;
|
||||||
|
|
||||||
@ApiProperty({
|
// @ApiProperty({
|
||||||
example: 'shift, expense, leave',
|
// example: 'shift, expense, leave',
|
||||||
description: 'categorie of the related code',
|
// description: 'categorie of the related code',
|
||||||
})
|
// })
|
||||||
@IsString()
|
// @IsString()
|
||||||
@IsNotEmpty()
|
// @IsNotEmpty()
|
||||||
categorie: string;
|
// categorie: string;
|
||||||
|
|
||||||
@ApiProperty({
|
// @ApiProperty({
|
||||||
example: '0, 0.72, 1, 1.5, 2',
|
// example: '0, 0.72, 1, 1.5, 2',
|
||||||
description: 'modifier number to apply to salary',
|
// description: 'modifier number to apply to salary',
|
||||||
})
|
// })
|
||||||
@Type(()=> Number)
|
// @Type(()=> Number)
|
||||||
@IsNumber()
|
// @IsNumber()
|
||||||
@IsNotEmpty()
|
// @IsNotEmpty()
|
||||||
modifier: number;
|
// modifier: number;
|
||||||
|
|
||||||
@ApiProperty({
|
// @ApiProperty({
|
||||||
example: 'G1, G345, G501, G43, G700',
|
// example: 'G1, G345, G501, G43, G700',
|
||||||
description: 'codes given by the bank',
|
// description: 'codes given by the bank',
|
||||||
})
|
// })
|
||||||
@IsString()
|
// @IsString()
|
||||||
@IsNotEmpty()
|
// @IsNotEmpty()
|
||||||
bank_code: string;
|
// bank_code: string;
|
||||||
}
|
// }
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { PartialType } from "@nestjs/swagger";
|
// import { PartialType } from "@nestjs/swagger";
|
||||||
import { CreateBankCodeDto } from "./create-bank-code.dto";
|
// import { CreateBankCodeDto } from "./create-bank-code.dto";
|
||||||
|
|
||||||
export class UpdateBankCodeDto extends PartialType(CreateBankCodeDto) {}
|
// export class UpdateBankCodeDto extends PartialType(CreateBankCodeDto) {}
|
||||||
|
|
@ -1,51 +1,51 @@
|
||||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
// import { Injectable, NotFoundException } from "@nestjs/common";
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
// import { PrismaService } from "src/prisma/prisma.service";
|
||||||
import { CreateBankCodeDto } from "../dtos/create-bank-code.dto";
|
// import { CreateBankCodeDto } from "../dtos/create-bank-code.dto";
|
||||||
import { BankCodes } from "@prisma/client";
|
// import { BankCodes } from "@prisma/client";
|
||||||
import { UpdateBankCodeDto } from "../dtos/update-bank-code.dto";
|
// import { UpdateBankCodeDto } from "../dtos/update-bank-code.dto";
|
||||||
|
|
||||||
@Injectable()
|
// @Injectable()
|
||||||
export class BankCodesService {
|
// export class BankCodesService {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
// constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
async create(dto: CreateBankCodeDto): Promise<BankCodes>{
|
// async create(dto: CreateBankCodeDto): Promise<BankCodes>{
|
||||||
return this.prisma.bankCodes.create({
|
// return this.prisma.bankCodes.create({
|
||||||
data: {
|
// data: {
|
||||||
type: dto.type,
|
// type: dto.type,
|
||||||
categorie: dto.categorie,
|
// categorie: dto.categorie,
|
||||||
modifier: dto.modifier,
|
// modifier: dto.modifier,
|
||||||
bank_code: dto.bank_code,
|
// bank_code: dto.bank_code,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
findAll() {
|
// findAll() {
|
||||||
return this.prisma.bankCodes.findMany();
|
// return this.prisma.bankCodes.findMany();
|
||||||
}
|
// }
|
||||||
|
|
||||||
async findOne(id: number) {
|
// async findOne(id: number) {
|
||||||
const bankCode = await this.prisma.bankCodes.findUnique({ where: {id} });
|
// const bankCode = await this.prisma.bankCodes.findUnique({ where: {id} });
|
||||||
|
|
||||||
if(!bankCode) throw new NotFoundException(`Bank Code #${id} not found`);
|
// if(!bankCode) throw new NotFoundException(`Bank Code #${id} not found`);
|
||||||
|
|
||||||
return bankCode;
|
// return bankCode;
|
||||||
}
|
// }
|
||||||
|
|
||||||
async update(id:number, dto: UpdateBankCodeDto) {
|
// async update(id:number, dto: UpdateBankCodeDto) {
|
||||||
return await this.prisma.bankCodes.update({
|
// return await this.prisma.bankCodes.update({
|
||||||
where: { id },
|
// where: { id },
|
||||||
data: {
|
// data: {
|
||||||
type: dto.type,
|
// type: dto.type,
|
||||||
categorie: dto.categorie,
|
// categorie: dto.categorie,
|
||||||
modifier: dto.modifier as any,
|
// modifier: dto.modifier as any,
|
||||||
bank_code: dto.bank_code,
|
// bank_code: dto.bank_code,
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
async remove(id: number) {
|
// async remove(id: number) {
|
||||||
await this.findOne(id);
|
// await this.findOne(id);
|
||||||
return this.prisma.bankCodes.delete({ where: {id} });
|
// return this.prisma.bankCodes.delete({ where: {id} });
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, UseGuards } from '@nestjs/common';
|
|
||||||
import { CustomersService } from '../services/customers.service';
|
|
||||||
import { Customers } from '@prisma/client';
|
|
||||||
import { CreateCustomerDto } from '../dtos/create-customer.dto';
|
|
||||||
import { UpdateCustomerDto } from '../dtos/update-customer.dto';
|
|
||||||
import { RolesAllowed } from "src/common/decorators/roles.decorators";
|
|
||||||
import { Roles as RoleEnum } from '.prisma/client';
|
|
||||||
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
@ApiTags('Customers')
|
|
||||||
@ApiBearerAuth('access-token')
|
|
||||||
// @UseGuards()
|
|
||||||
@Controller('customers')
|
|
||||||
export class CustomersController {
|
|
||||||
constructor(private readonly customersService: CustomersService) {}
|
|
||||||
|
|
||||||
//_____________________________________________________________________________________________
|
|
||||||
// Deprecated or unused methods
|
|
||||||
//_____________________________________________________________________________________________
|
|
||||||
|
|
||||||
// @Post()
|
|
||||||
// //@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.SUPERVISOR)
|
|
||||||
// @ApiOperation({ summary: 'Create customer' })
|
|
||||||
// @ApiResponse({ status: 201, description: 'Customer created', type: CreateCustomerDto })
|
|
||||||
// @ApiResponse({ status: 400, description: 'Invalid task or invalid data' })
|
|
||||||
// create(@Body() dto: CreateCustomerDto): Promise<Customers> {
|
|
||||||
// return this.customersService.create(dto);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Get()
|
|
||||||
// //@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
||||||
// @ApiOperation({ summary: 'Find all customers' })
|
|
||||||
// @ApiResponse({ status: 201, description: 'List of customers found', type: CreateCustomerDto, isArray: true })
|
|
||||||
// @ApiResponse({ status: 400, description: 'List of customers not found' })
|
|
||||||
// findAll(): Promise<Customers[]> {
|
|
||||||
// return this.customersService.findAll();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Get(':id')
|
|
||||||
// //@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
||||||
// @ApiOperation({ summary: 'Find customer' })
|
|
||||||
// @ApiResponse({ status: 201, description: 'Customer found', type: CreateCustomerDto })
|
|
||||||
// @ApiResponse({ status: 400, description: 'Customer not found' })
|
|
||||||
// findOne(@Param('id', ParseIntPipe) id: number): Promise<Customers> {
|
|
||||||
// return this.customersService.findOne(id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Patch(':id')
|
|
||||||
// //@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.EMPLOYEE,RoleEnum.SUPERVISOR)
|
|
||||||
// @ApiOperation({ summary: 'Update customer' })
|
|
||||||
// @ApiResponse({ status: 201, description: 'Customer updated', type: CreateCustomerDto })
|
|
||||||
// @ApiResponse({ status: 400, description: 'Customer not found' })
|
|
||||||
// update(
|
|
||||||
// @Param('id', ParseIntPipe) id: number,
|
|
||||||
// @Body() dto: UpdateCustomerDto,
|
|
||||||
// ): Promise<Customers> {
|
|
||||||
// return this.customersService.update(id, dto);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Delete(':id')
|
|
||||||
// //@RolesAllowed(RoleEnum.ACCOUNTING, RoleEnum.ADMIN, RoleEnum.SUPERVISOR)
|
|
||||||
// @ApiOperation({ summary: 'Delete customer' })
|
|
||||||
// @ApiResponse({ status: 201, description: 'Customer deleted', type: CreateCustomerDto })
|
|
||||||
// @ApiResponse({ status: 400, description: 'Customer not found' })
|
|
||||||
// remove(@Param('id', ParseIntPipe) id: number): Promise<Customers>{
|
|
||||||
// return this.customersService.remove(id);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
|
|
||||||
import { Module } from '@nestjs/common';
|
|
||||||
import { CustomersController } from './controllers/customers.controller';
|
|
||||||
import { CustomersService } from './services/customers.service';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
controllers:[CustomersController],
|
|
||||||
providers:[CustomersService],
|
|
||||||
})
|
|
||||||
export class CustomersModule {}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
import { ApiProperty } from "@nestjs/swagger";
|
|
||||||
import { Type } from "class-transformer";
|
|
||||||
import {
|
|
||||||
Allow,
|
|
||||||
IsEmail,
|
|
||||||
IsInt,
|
|
||||||
IsNotEmpty,
|
|
||||||
IsOptional,
|
|
||||||
IsPositive,
|
|
||||||
IsString,
|
|
||||||
IsUUID,
|
|
||||||
} from "class-validator";
|
|
||||||
|
|
||||||
export class CreateCustomerDto {
|
|
||||||
@ApiProperty({
|
|
||||||
example: 1,
|
|
||||||
description: 'Unique ID of a customer(primary-key, auto-incremented)',
|
|
||||||
})
|
|
||||||
@Allow()
|
|
||||||
id?: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: '0e6e2e1f-b157-4c7c-ae3f-999b3e4f914d',
|
|
||||||
description: 'UUID of the user linked to that customer',
|
|
||||||
})
|
|
||||||
@IsUUID()
|
|
||||||
@IsOptional()
|
|
||||||
user_id?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: 'Gandalf',
|
|
||||||
description: 'Customer`s first name',
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
first_name: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: 'TheGray',
|
|
||||||
description: 'Customer`s last name',
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
last_name: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: 'you_shall_not_pass@middleEarth.com',
|
|
||||||
description: 'Customer`s email',
|
|
||||||
})
|
|
||||||
@IsEmail()
|
|
||||||
@IsOptional()
|
|
||||||
email: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: '8436637464',
|
|
||||||
description: 'Customer`s phone number',
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
phone_number: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: '1 Ringbearer`s way, Mount Doom city, ME, T1R 1N6 ',
|
|
||||||
description: 'Customer`s residence',
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
@IsOptional()
|
|
||||||
residence?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: '4263253',
|
|
||||||
description: 'Customer`s invoice number',
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@Type(() => Number)
|
|
||||||
@IsInt()
|
|
||||||
@IsNotEmpty()
|
|
||||||
invoice_id: number;
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
import { PartialType } from "@nestjs/swagger";
|
|
||||||
import { CreateCustomerDto } from "./create-customer.dto";
|
|
||||||
|
|
||||||
export class UpdateCustomerDto extends PartialType(CreateCustomerDto) {}
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class CustomersService {
|
|
||||||
|
|
||||||
//_____________________________________________________________________________________________
|
|
||||||
// Deprecated or unused methods
|
|
||||||
//_____________________________________________________________________________________________
|
|
||||||
|
|
||||||
// constructor(private readonly prisma: PrismaService) {}
|
|
||||||
|
|
||||||
// async create(dto: CreateCustomerDto): Promise<Customers> {
|
|
||||||
// const {
|
|
||||||
// first_name,
|
|
||||||
// last_name,
|
|
||||||
// email,
|
|
||||||
// phone_number,
|
|
||||||
// residence,
|
|
||||||
// invoice_id,
|
|
||||||
// } = dto;
|
|
||||||
|
|
||||||
// return this.prisma.$transaction(async (transaction) => {
|
|
||||||
// const user: Users = await transaction.users.create({
|
|
||||||
// data: {
|
|
||||||
// first_name,
|
|
||||||
// last_name,
|
|
||||||
// email,
|
|
||||||
// phone_number,
|
|
||||||
// residence,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// return transaction.customers.create({
|
|
||||||
// data: {
|
|
||||||
// user_id: user.id,
|
|
||||||
// invoice_id,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// findAll(): Promise<Customers[]> {
|
|
||||||
// return this.prisma.customers.findMany({
|
|
||||||
// include: { user: true },
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async findOne(id:number): Promise<Customers> {
|
|
||||||
// const customer = await this.prisma.customers.findUnique({
|
|
||||||
// where: { id },
|
|
||||||
// include: { user: true },
|
|
||||||
// });
|
|
||||||
// if(!customer) throw new NotFoundException(`Customer #${id} not found`);
|
|
||||||
// return customer;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async update(id: number,dto: UpdateCustomerDto): Promise<Customers> {
|
|
||||||
// const customer = await this.findOne(id);
|
|
||||||
|
|
||||||
// const {
|
|
||||||
// first_name,
|
|
||||||
// last_name,
|
|
||||||
// email,
|
|
||||||
// phone_number,
|
|
||||||
// residence,
|
|
||||||
// invoice_id,
|
|
||||||
// } = dto;
|
|
||||||
|
|
||||||
// return this.prisma.$transaction(async (transaction) => {
|
|
||||||
// await transaction.users.update({
|
|
||||||
// where: { id: customer.user_id },
|
|
||||||
// data: {
|
|
||||||
// ...(first_name !== undefined && { first_name }),
|
|
||||||
// ...(last_name !== undefined && { last_name }),
|
|
||||||
// ...(email !== undefined && { email }),
|
|
||||||
// ...(phone_number !== undefined && { phone_number }),
|
|
||||||
// ...(residence !== undefined && { residence }),
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return transaction.customers.update({
|
|
||||||
// where: { id },
|
|
||||||
// data: {
|
|
||||||
// ...(invoice_id !== undefined && { invoice_id }),
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async remove(id: number): Promise<Customers> {
|
|
||||||
// await this.findOne(id);
|
|
||||||
// return this.prisma.customers.delete({ where: { id }});
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
import { Body,Controller,Get,NotFoundException,Param,Patch } from '@nestjs/common';
|
|
||||||
import { EmployeesService } from '../services/employees.service';
|
|
||||||
import { CreateEmployeeDto } from '../dtos/create-employee.dto';
|
|
||||||
import { UpdateEmployeeDto } from '../dtos/update-employee.dto';
|
|
||||||
import { RolesAllowed } from '../../../common/decorators/roles.decorators';
|
|
||||||
import { ApiBearerAuth, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
|
||||||
import { EmployeeListItemDto } from '../dtos/list-employee.dto';
|
|
||||||
import { EmployeesArchivalService } from '../services/employees-archival.service';
|
|
||||||
import { EmployeeProfileItemDto } from 'src/modules/employees/dtos/profil-employee.dto';
|
|
||||||
|
|
||||||
@ApiTags('Employees')
|
|
||||||
@ApiBearerAuth('access-token')
|
|
||||||
// @UseGuards()
|
|
||||||
@Controller('employees')
|
|
||||||
export class EmployeesController {
|
|
||||||
constructor(
|
|
||||||
private readonly employeesService: EmployeesService,
|
|
||||||
private readonly archiveService: EmployeesArchivalService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
@Get('employee-list')
|
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ACCOUNTING)
|
|
||||||
@ApiOperation({summary: 'Find all employees with scoped info' })
|
|
||||||
@ApiResponse({ status: 200, description: 'List of employees with scoped info found', type: EmployeeListItemDto, isArray: true })
|
|
||||||
@ApiResponse({ status: 400, description: 'List of employees with scoped info not found' })
|
|
||||||
findListEmployees(): Promise<EmployeeListItemDto[]> {
|
|
||||||
return this.employeesService.findListEmployees();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Patch(':email')
|
|
||||||
//@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
||||||
@ApiBearerAuth('access-token')
|
|
||||||
@ApiOperation({ summary: 'Update, archive or restore an employee' })
|
|
||||||
@ApiParam({ name: 'email', type: Number, description: 'Email of the employee' })
|
|
||||||
@ApiResponse({ status: 200, description: 'Employee updated or restored', type: CreateEmployeeDto })
|
|
||||||
@ApiResponse({ status: 202, description: 'Employee archived successfully', type: CreateEmployeeDto })
|
|
||||||
@ApiResponse({ status: 404, description: 'Employee not found in active or archive' })
|
|
||||||
async updateOrArchiveOrRestore(@Param('email') email: string, @Body() dto: UpdateEmployeeDto,) {
|
|
||||||
// if last_work_day is set => archive the employee
|
|
||||||
// else if employee is archived and first_work_day or last_work_day = null => restore
|
|
||||||
//otherwise => standard update
|
|
||||||
const result = await this.archiveService.patchEmployee(email, dto);
|
|
||||||
if(!result) {
|
|
||||||
throw new NotFoundException(`Employee with email: ${ email } is not found in active or archive.`)
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//_____________________________________________________________________________________________
|
|
||||||
// Deprecated or unused methods
|
|
||||||
//_____________________________________________________________________________________________
|
|
||||||
|
|
||||||
// @Post()
|
|
||||||
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR)
|
|
||||||
// @ApiOperation({summary: 'Create employee' })
|
|
||||||
// @ApiResponse({ status: 201, description: 'Employee created', type: CreateEmployeeDto })
|
|
||||||
// @ApiResponse({ status: 400, description: 'Incomplete task or invalid data' })
|
|
||||||
// create(@Body() dto: CreateEmployeeDto): Promise<Employees> {
|
|
||||||
// return this.employeesService.create(dto);
|
|
||||||
// }
|
|
||||||
// @Get()
|
|
||||||
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR, RoleEnum.ACCOUNTING)
|
|
||||||
// @ApiOperation({summary: 'Find all employees' })
|
|
||||||
// @ApiResponse({ status: 200, description: 'List of employees found', type: CreateEmployeeDto, isArray: true })
|
|
||||||
// @ApiResponse({ status: 400, description: 'List of employees not found' })
|
|
||||||
// findAll(): Promise<Employees[]> {
|
|
||||||
// return this.employeesService.findAll();
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// @Get(':email')
|
|
||||||
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR,RoleEnum.ACCOUNTING )
|
|
||||||
// @ApiOperation({summary: 'Find employee' })
|
|
||||||
// @ApiResponse({ status: 200, description: 'Employee found', type: CreateEmployeeDto })
|
|
||||||
// @ApiResponse({ status: 400, description: 'Employee not found' })
|
|
||||||
// findOne(@Param('email', ParseIntPipe) email: string): Promise<Employees> {
|
|
||||||
// return this.employeesService.findOne(email);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Get('profile/:email')
|
|
||||||
@ApiOperation({summary: 'Find employee profile' })
|
|
||||||
@ApiParam({ name: 'email', type: String, description: 'Identifier of the employee' })
|
|
||||||
@ApiResponse({ status: 200, description: 'Employee profile found', type: EmployeeProfileItemDto })
|
|
||||||
@ApiResponse({ status: 400, description: 'Employee profile not found' })
|
|
||||||
findOneProfile(@Param('email') email: string): Promise<EmployeeProfileItemDto> {
|
|
||||||
return this.employeesService.findOneProfile(email);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Delete(':email')
|
|
||||||
// //@RolesAllowed(RoleEnum.ADMIN, RoleEnum.HR, RoleEnum.SUPERVISOR )
|
|
||||||
// @ApiOperation({summary: 'Delete employee' })
|
|
||||||
// @ApiParam({ name: 'email', type: Number, description: 'Email of the employee to delete' })
|
|
||||||
// @ApiResponse({ status: 204, description: 'Employee deleted' })
|
|
||||||
// @ApiResponse({ status: 404, description: 'Employee not found' })
|
|
||||||
// remove(@Param('email', ParseIntPipe) email: string): Promise<Employees> {
|
|
||||||
// return this.employeesService.remove(email);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
import {
|
|
||||||
Allow,
|
|
||||||
IsBoolean,
|
|
||||||
IsDateString,
|
|
||||||
IsEmail,
|
|
||||||
IsInt,
|
|
||||||
IsNotEmpty,
|
|
||||||
IsOptional,
|
|
||||||
IsPositive,
|
|
||||||
IsString,
|
|
||||||
IsUUID,
|
|
||||||
} from 'class-validator';
|
|
||||||
import { Type } from 'class-transformer';
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
export class CreateEmployeeDto {
|
|
||||||
@ApiProperty({
|
|
||||||
example: 1,
|
|
||||||
description: 'Unique ID of an employee(primary-key, auto-incremented)',
|
|
||||||
})
|
|
||||||
@Allow()
|
|
||||||
id: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: '0e6e2e1f-b157-4c7c-ae3f-999b3e4f914d',
|
|
||||||
description: 'UUID of the user linked to that employee',
|
|
||||||
})
|
|
||||||
@IsUUID()
|
|
||||||
@IsOptional()
|
|
||||||
user_id?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: 'Frodo',
|
|
||||||
description: 'Employee`s first name',
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
first_name: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: 'Baggins',
|
|
||||||
description: 'Employee`s last name',
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
last_name: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: 'i_cant_do_this_sam@targointernet.com',
|
|
||||||
description: 'Employee`s email',
|
|
||||||
})
|
|
||||||
@IsEmail()
|
|
||||||
@IsOptional()
|
|
||||||
email: string;
|
|
||||||
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsBoolean()
|
|
||||||
is_supervisor: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: '82538437464',
|
|
||||||
description: 'Employee`s phone number',
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
phone_number: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: '1 Bagshot Row, Hobbiton, The Shire, Middle-earth',
|
|
||||||
description: 'Employee`s residence',
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
@IsOptional()
|
|
||||||
residence?: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: 7464,
|
|
||||||
description: 'external ID for the pay system',
|
|
||||||
})
|
|
||||||
@IsInt()
|
|
||||||
@IsPositive()
|
|
||||||
@Type(() => Number)
|
|
||||||
external_payroll_id: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: 335567447,
|
|
||||||
description: 'Employee`s company code',
|
|
||||||
})
|
|
||||||
@IsInt()
|
|
||||||
@IsPositive()
|
|
||||||
@Type(() => Number)
|
|
||||||
company_code: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example:'technicient',
|
|
||||||
description: 'employee`s job title',
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
@IsOptional()
|
|
||||||
job_title: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: '23/09/3018',
|
|
||||||
description: 'Employee`s first working day',
|
|
||||||
})
|
|
||||||
@IsDateString()
|
|
||||||
first_work_day: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
example: '25/03/3019',
|
|
||||||
description: 'Employee`s last working day',
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsDateString()
|
|
||||||
@IsOptional()
|
|
||||||
last_work_day?: string;
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
export class EmployeeListItemDto {
|
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
email: string;
|
|
||||||
supervisor_full_name: string | null;
|
|
||||||
company_name: number | null;
|
|
||||||
job_title: string | null;
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
export class EmployeeProfileItemDto {
|
|
||||||
first_name: string;
|
|
||||||
last_name: string;
|
|
||||||
employee_full_name: string;
|
|
||||||
supervisor_full_name: string | null;
|
|
||||||
company_name: number | null;
|
|
||||||
job_title: string | null;
|
|
||||||
email: string | null;
|
|
||||||
phone_number: string;
|
|
||||||
first_work_day: string;
|
|
||||||
last_work_day?: string | null;
|
|
||||||
residence: string | null;
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import { ApiProperty, PartialType } from '@nestjs/swagger';
|
|
||||||
import { CreateEmployeeDto } from './create-employee.dto';
|
|
||||||
import { IsDateString, IsOptional, Max } from 'class-validator';
|
|
||||||
|
|
||||||
export class UpdateEmployeeDto extends PartialType(CreateEmployeeDto) {
|
|
||||||
@ApiProperty({ required: false, type: Date, description: 'New hire date or undefined' })
|
|
||||||
@IsDateString()
|
|
||||||
@IsOptional()
|
|
||||||
first_work_day?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, type: Date, description: 'Termination date (null to restore)' })
|
|
||||||
@IsDateString()
|
|
||||||
@IsOptional()
|
|
||||||
last_work_day?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false, type: Number, description: 'Supervisor ID' })
|
|
||||||
@IsOptional()
|
|
||||||
supervisor_id?: number;
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
phone_number: string;
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import { Module } from '@nestjs/common';
|
|
||||||
import { EmployeesController } from './controllers/employees.controller';
|
|
||||||
import { EmployeesService } from './services/employees.service';
|
|
||||||
import { EmployeesArchivalService } from './services/employees-archival.service';
|
|
||||||
import { SharedModule } from '../shared/shared.module';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [SharedModule],
|
|
||||||
controllers: [EmployeesController],
|
|
||||||
providers: [EmployeesService, EmployeesArchivalService],
|
|
||||||
exports: [EmployeesService, EmployeesArchivalService],
|
|
||||||
})
|
|
||||||
export class EmployeesModule {}
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
import { Injectable } from "@nestjs/common";
|
|
||||||
import { Employees, EmployeesArchive, Users } from "@prisma/client";
|
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
|
||||||
import { UpdateEmployeeDto } from "../dtos/update-employee.dto";
|
|
||||||
import { toDateOrUndefined, toDateOrNull } from "../utils/employee.utils";
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class EmployeesArchivalService {
|
|
||||||
constructor(private readonly prisma: PrismaService) { }
|
|
||||||
|
|
||||||
async patchEmployee(email: string, dto: UpdateEmployeeDto): Promise<Employees | EmployeesArchive | null> {
|
|
||||||
// 1) Tenter sur employés actifs
|
|
||||||
const active = await this.prisma.employees.findFirst({
|
|
||||||
where: { user: { email } },
|
|
||||||
include: { user: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (active) {
|
|
||||||
// Archivage : si on reçoit un last_work_day défini et que l'employé n’est pas déjà terminé
|
|
||||||
if (dto.last_work_day !== undefined && active.last_work_day == null && dto.last_work_day !== null) {
|
|
||||||
return this.archiveOnTermination(active, dto);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sinon, update standard (split Users/Employees)
|
|
||||||
const {
|
|
||||||
first_name,
|
|
||||||
last_name,
|
|
||||||
email: new_email,
|
|
||||||
phone_number,
|
|
||||||
residence,
|
|
||||||
external_payroll_id,
|
|
||||||
company_code,
|
|
||||||
job_title,
|
|
||||||
first_work_day,
|
|
||||||
last_work_day,
|
|
||||||
supervisor_id,
|
|
||||||
is_supervisor,
|
|
||||||
} = dto as any;
|
|
||||||
|
|
||||||
const first_work_d = toDateOrUndefined(first_work_day);
|
|
||||||
const last_work_d = Object.prototype.hasOwnProperty('last_work_day')
|
|
||||||
? toDateOrNull(last_work_day ?? null)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
await this.prisma.$transaction(async (transaction) => {
|
|
||||||
if (
|
|
||||||
first_name !== undefined ||
|
|
||||||
last_name !== undefined ||
|
|
||||||
new_email !== undefined ||
|
|
||||||
phone_number !== undefined ||
|
|
||||||
residence !== undefined
|
|
||||||
) {
|
|
||||||
await transaction.users.update({
|
|
||||||
where: { id: active.user_id },
|
|
||||||
data: {
|
|
||||||
...(first_name !== undefined ? { first_name } : {}),
|
|
||||||
...(last_name !== undefined ? { last_name } : {}),
|
|
||||||
...(email !== undefined ? { email: new_email } : {}),
|
|
||||||
...(phone_number !== undefined ? { phone_number } : {}),
|
|
||||||
...(residence !== undefined ? { residence } : {}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const updated = await transaction.employees.update({
|
|
||||||
where: { id: active.id },
|
|
||||||
data: {
|
|
||||||
...(external_payroll_id !== undefined ? { external_payroll_id } : {}),
|
|
||||||
...(company_code !== undefined ? { company_code } : {}),
|
|
||||||
...(job_title !== undefined ? { job_title } : {}),
|
|
||||||
...(first_work_d !== undefined ? { first_work_day: first_work_d } : {}),
|
|
||||||
...(last_work_d !== undefined ? { last_work_day: last_work_d } : {}),
|
|
||||||
...(is_supervisor !== undefined ? { is_supervisor } : {}),
|
|
||||||
...(supervisor_id !== undefined ? { supervisor_id } : {}),
|
|
||||||
},
|
|
||||||
include: { user: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.prisma.employees.findFirst({ where: { user: { email } } });
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await this.prisma.users.findUnique({ where: { email } });
|
|
||||||
if (!user) return null;
|
|
||||||
// 2) Pas trouvé en actifs → regarder en archive (pour restauration)
|
|
||||||
const archived = await this.prisma.employeesArchive.findFirst({
|
|
||||||
where: { user_id: user.id },
|
|
||||||
include: { user: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (archived) {
|
|
||||||
// Condition de restauration : last_work_day === null ou first_work_day fourni
|
|
||||||
const restore = dto.last_work_day === null || dto.first_work_day != null;
|
|
||||||
if (restore) {
|
|
||||||
return this.restoreEmployee(archived, dto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 3) Ni actif, ni archivé → 404 dans le controller
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//transfers the employee to archive and then delete from employees table
|
|
||||||
private async archiveOnTermination(active: Employees & { user: Users }, dto: UpdateEmployeeDto): Promise<EmployeesArchive> {
|
|
||||||
const last_work_d = toDateOrNull(dto.last_work_day!);
|
|
||||||
if (!last_work_d) throw new Error('invalide last_work_day for archive');
|
|
||||||
return this.prisma.$transaction(async transaction => {
|
|
||||||
//detach crew from supervisor if employee is a supervisor
|
|
||||||
await transaction.employees.updateMany({
|
|
||||||
where: { supervisor_id: active.id },
|
|
||||||
data: { supervisor_id: null },
|
|
||||||
})
|
|
||||||
const archived = await transaction.employeesArchive.create({
|
|
||||||
data: {
|
|
||||||
employee_id: active.id,
|
|
||||||
user_id: active.user_id,
|
|
||||||
first_name: active.user.first_name,
|
|
||||||
last_name: active.user.last_name,
|
|
||||||
company_code: active.company_code,
|
|
||||||
job_title: active.job_title,
|
|
||||||
first_work_day: active.first_work_day,
|
|
||||||
last_work_day: last_work_d,
|
|
||||||
supervisor_id: active.supervisor_id ?? null,
|
|
||||||
is_supervisor: active.is_supervisor,
|
|
||||||
external_payroll_id: active.external_payroll_id,
|
|
||||||
},
|
|
||||||
include: { user: true }
|
|
||||||
});
|
|
||||||
//delete from employees table
|
|
||||||
await transaction.employees.delete({ where: { id: active.id } });
|
|
||||||
//return archived employee
|
|
||||||
return archived
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//transfers the employee from archive to the employees table
|
|
||||||
private async restoreEmployee(archived: EmployeesArchive & { user: Users }, dto: UpdateEmployeeDto): Promise<Employees> {
|
|
||||||
// const first_work_d = toDateOrUndefined(dto.first_work_day);
|
|
||||||
return this.prisma.$transaction(async transaction => {
|
|
||||||
//restores the archived employee into the employees table
|
|
||||||
const restored = await transaction.employees.create({
|
|
||||||
data: {
|
|
||||||
user_id: archived.user_id,
|
|
||||||
company_code: archived.company_code,
|
|
||||||
job_title: archived.job_title,
|
|
||||||
first_work_day: archived.first_work_day,
|
|
||||||
last_work_day: null,
|
|
||||||
is_supervisor: archived.is_supervisor ?? false,
|
|
||||||
external_payroll_id: archived.external_payroll_id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
//deleting archived entry by id
|
|
||||||
await transaction.employeesArchive.delete({ where: { id: archived.id } });
|
|
||||||
|
|
||||||
//return restored employee
|
|
||||||
return restored;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//fetches all archived employees
|
|
||||||
async findAllArchived(): Promise<EmployeesArchive[]> {
|
|
||||||
return this.prisma.employeesArchive.findMany();
|
|
||||||
}
|
|
||||||
|
|
||||||
//fetches an archived employee
|
|
||||||
async findOneArchived(id: number): Promise<EmployeesArchive> {
|
|
||||||
return this.prisma.employeesArchive.findUniqueOrThrow({ where: { id } });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,230 +0,0 @@
|
||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
|
||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
|
||||||
import { EmployeeListItemDto } from '../dtos/list-employee.dto';
|
|
||||||
import { EmployeeProfileItemDto } from '../dtos/profil-employee.dto';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class EmployeesService {
|
|
||||||
constructor(private readonly prisma: PrismaService) { }
|
|
||||||
|
|
||||||
findListEmployees(): Promise<EmployeeListItemDto[]> {
|
|
||||||
return this.prisma.employees.findMany({
|
|
||||||
select: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
first_name: true,
|
|
||||||
last_name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
supervisor: {
|
|
||||||
select: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
first_name: true,
|
|
||||||
last_name: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
job_title: true,
|
|
||||||
company_code: true,
|
|
||||||
}
|
|
||||||
}).then(rows => rows.map(r => ({
|
|
||||||
first_name: r.user.first_name,
|
|
||||||
last_name: r.user.last_name,
|
|
||||||
email: r.user.email,
|
|
||||||
company_name: r.company_code,
|
|
||||||
job_title: r.job_title,
|
|
||||||
employee_full_name: `${r.user.first_name} ${r.user.last_name}`,
|
|
||||||
supervisor_full_name: r.supervisor ? `${r.supervisor.user.first_name} ${r.supervisor.user.last_name}` : null,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async findOneProfile(email: string): Promise<EmployeeProfileItemDto> {
|
|
||||||
const emp = await this.prisma.employees.findFirst({
|
|
||||||
where: { user: { email } },
|
|
||||||
select: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
first_name: true,
|
|
||||||
last_name: true,
|
|
||||||
email: true,
|
|
||||||
phone_number: true,
|
|
||||||
residence: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
supervisor: {
|
|
||||||
select: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
first_name: true,
|
|
||||||
last_name: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
job_title: true,
|
|
||||||
company_code: true,
|
|
||||||
first_work_day: true,
|
|
||||||
last_work_day: true,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!emp) throw new NotFoundException(`Employee with email ${email} not found`);
|
|
||||||
|
|
||||||
return {
|
|
||||||
first_name: emp.user.first_name,
|
|
||||||
last_name: emp.user.last_name,
|
|
||||||
email: emp.user.email,
|
|
||||||
residence: emp.user.residence,
|
|
||||||
phone_number: emp.user.phone_number,
|
|
||||||
company_name: emp.company_code,
|
|
||||||
job_title: emp.job_title,
|
|
||||||
employee_full_name: `${emp.user.first_name} ${emp.user.last_name}`,
|
|
||||||
first_work_day: emp.first_work_day.toISOString().slice(0, 10),
|
|
||||||
last_work_day: emp.last_work_day ? emp.last_work_day.toISOString().slice(0, 10) : null,
|
|
||||||
supervisor_full_name: emp.supervisor ? `${emp.supervisor.user.first_name}, ${emp.supervisor.user.last_name}` : null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//_____________________________________________________________________________________________
|
|
||||||
// Deprecated or unused methods
|
|
||||||
//_____________________________________________________________________________________________
|
|
||||||
|
|
||||||
// async create(dto: CreateEmployeeDto): Promise<Employees> {
|
|
||||||
// const {
|
|
||||||
// first_name,
|
|
||||||
// last_name,
|
|
||||||
// email,
|
|
||||||
// phone_number,
|
|
||||||
// residence,
|
|
||||||
// external_payroll_id,
|
|
||||||
// company_code,
|
|
||||||
// job_title,
|
|
||||||
// first_work_day,
|
|
||||||
// last_work_day,
|
|
||||||
// is_supervisor,
|
|
||||||
// } = dto;
|
|
||||||
|
|
||||||
// return this.prisma.$transaction(async (transaction) => {
|
|
||||||
// const user: Users = await transaction.users.create({
|
|
||||||
// data: {
|
|
||||||
// first_name,
|
|
||||||
// last_name,
|
|
||||||
// email,
|
|
||||||
// phone_number,
|
|
||||||
// residence,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// return transaction.employees.create({
|
|
||||||
// data: {
|
|
||||||
// user_id: user.id,
|
|
||||||
// external_payroll_id,
|
|
||||||
// company_code,
|
|
||||||
// job_title,
|
|
||||||
// first_work_day,
|
|
||||||
// last_work_day,
|
|
||||||
// is_supervisor,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// findAll(): Promise<Employees[]> {
|
|
||||||
// return this.prisma.employees.findMany({
|
|
||||||
// include: { user: true },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async findOne(email: string): Promise<Employees> {
|
|
||||||
// const emp = await this.prisma.employees.findFirst({
|
|
||||||
// where: { user: { email } },
|
|
||||||
// include: { user: true },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// //add search for archived employees
|
|
||||||
// if (!emp) {
|
|
||||||
// throw new NotFoundException(`Employee with email: ${email} not found`);
|
|
||||||
// }
|
|
||||||
// return emp;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async update(
|
|
||||||
// email: string,
|
|
||||||
// dto: UpdateEmployeeDto,
|
|
||||||
// ): Promise<Employees> {
|
|
||||||
// const emp = await this.findOne(email);
|
|
||||||
|
|
||||||
// const {
|
|
||||||
// first_name,
|
|
||||||
// last_name,
|
|
||||||
// phone_number,
|
|
||||||
// residence,
|
|
||||||
// external_payroll_id,
|
|
||||||
// company_code,
|
|
||||||
// job_title,
|
|
||||||
// first_work_day,
|
|
||||||
// last_work_day,
|
|
||||||
// is_supervisor,
|
|
||||||
// email: new_email,
|
|
||||||
// } = dto;
|
|
||||||
|
|
||||||
// return this.prisma.$transaction(async (transaction) => {
|
|
||||||
// if(
|
|
||||||
// first_name !== undefined ||
|
|
||||||
// last_name !== undefined ||
|
|
||||||
// new_email !== undefined ||
|
|
||||||
// phone_number !== undefined ||
|
|
||||||
// residence !== undefined
|
|
||||||
// ){
|
|
||||||
// await transaction.users.update({
|
|
||||||
// where: { id: emp.user_id },
|
|
||||||
// data: {
|
|
||||||
// ...(first_name !== undefined && { first_name }),
|
|
||||||
// ...(last_name !== undefined && { last_name }),
|
|
||||||
// ...(email !== undefined && { email }),
|
|
||||||
// ...(phone_number !== undefined && { phone_number }),
|
|
||||||
// ...(residence !== undefined && { residence }),
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const updated = await transaction.employees.update({
|
|
||||||
// where: { id: emp.id },
|
|
||||||
// data: {
|
|
||||||
// ...(external_payroll_id !== undefined && { external_payroll_id }),
|
|
||||||
// ...(company_code !== undefined && { company_code }),
|
|
||||||
// ...(first_work_day !== undefined && { first_work_day }),
|
|
||||||
// ...(last_work_day !== undefined && { last_work_day }),
|
|
||||||
// ...(job_title !== undefined && { job_title }),
|
|
||||||
// ...(is_supervisor !== undefined && { is_supervisor }),
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// return updated;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// async remove(email: string): Promise<Employees> {
|
|
||||||
|
|
||||||
// const emp = await this.findOne(email);
|
|
||||||
|
|
||||||
// return this.prisma.$transaction(async (transaction) => {
|
|
||||||
// await transaction.employees.updateMany({
|
|
||||||
// where: { supervisor_id: emp.id },
|
|
||||||
// data: { supervisor_id: null },
|
|
||||||
// });
|
|
||||||
// const deleted_employee = await transaction.employees.delete({
|
|
||||||
// where: {id: emp.id },
|
|
||||||
// });
|
|
||||||
// await transaction.users.delete({
|
|
||||||
// where: { id: emp.user_id },
|
|
||||||
// });
|
|
||||||
// return deleted_employee;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
export function toDateOrNull(v?: string | null): Date | null {
|
|
||||||
if (!v) return null;
|
|
||||||
const day = new Date(v);
|
|
||||||
return isNaN(day.getTime()) ? null : day;
|
|
||||||
}
|
|
||||||
export function toDateOrUndefined(v?: string | null): Date | undefined {
|
|
||||||
const day = toDateOrNull(v ?? undefined);
|
|
||||||
return day === null ? undefined : day;
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import { Body, Controller, Param, ParseIntPipe, 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";
|
|
||||||
|
|
||||||
|
|
||||||
@Controller('expense')
|
|
||||||
export class ExpenseController {
|
|
||||||
constructor(
|
|
||||||
private readonly prisma: PrismaService,
|
|
||||||
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);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
// 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";
|
|
||||||
|
|
||||||
// @Module({
|
|
||||||
// imports: [BusinessLogicsModule, SharedModule],
|
|
||||||
// controllers: [ExpensesController],
|
|
||||||
// providers: [
|
|
||||||
// ExpensesQueryService,
|
|
||||||
// ExpensesArchivalService,
|
|
||||||
// ExpensesCommandService,
|
|
||||||
// ],
|
|
||||||
// exports: [
|
|
||||||
// ExpensesQueryService,
|
|
||||||
// ExpensesArchivalService,
|
|
||||||
// ],
|
|
||||||
// })
|
|
||||||
|
|
||||||
// export class ExpensesModule {}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
import { Injectable } from "@nestjs/common";
|
|
||||||
import { PrismaService } from "src/prisma/prisma.service";
|
|
||||||
import { GetExpenseDto } from "../dtos/get-expense.dto";
|
|
||||||
import { updateExpenseDto } from "../dtos/update-expense.dto";
|
|
||||||
import { ExpenseDto } from "../dtos/expense.dto";
|
|
||||||
import { toDateFromString } from "../helpers/expenses-date-time-helpers";
|
|
||||||
|
|
||||||
type Normalized = { date: Date; comment: string; supervisor_comment: string; };
|
|
||||||
|
|
||||||
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 };
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ExpenseUpsertService {
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//_________________________________________________________________
|
|
||||||
// LOCAL HELPERS
|
|
||||||
//_________________________________________________________________
|
|
||||||
private normalizeExpenseDto(dto: ExpenseDto): Normalized {
|
|
||||||
const date = toDateFromString(dto.date);
|
|
||||||
const comment = this.truncate280(dto.comment);
|
|
||||||
const supervisor_comment = this.truncate280(dto.supervisor_comment? dto.supervisor_comment : '');
|
|
||||||
return { date, comment, supervisor_comment };
|
|
||||||
}
|
|
||||||
|
|
||||||
//makes sure that a string cannot exceed 280 chars
|
|
||||||
private truncate280 = (input: string): string => {
|
|
||||||
return input.length > 280 ? input.slice(0, 280) : input;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
import { CsvExportController } from "./controllers/csv-exports.controller";
|
import { CsvExportController } from "./controllers/csv-exports.controller";
|
||||||
import { CsvExportService } from "./services/csv-exports.service";
|
import { CsvExportService } from "./services/csv-exports.service";
|
||||||
import { SharedModule } from "../shared/shared.module";
|
import { SharedModule } from "../../time-and-attendance/modules/shared/shared.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers:[CsvExportService, SharedModule],
|
providers:[CsvExportService, SharedModule],
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
// import { Body, Controller, Post } from "@nestjs/common";
|
|
||||||
// import { ApiBearerAuth, ApiTags } from "@nestjs/swagger";
|
|
||||||
// import { LeaveRequestsService } from "../services/leave-request.service";
|
|
||||||
// import { UpsertLeaveRequestDto } from "../dtos/upsert-leave-request.dto";
|
|
||||||
// import { LeaveTypes } from "@prisma/client";
|
|
||||||
|
|
||||||
// @ApiTags('Leave Requests')
|
|
||||||
// @ApiBearerAuth('access-token')
|
|
||||||
// // @UseGuards()
|
|
||||||
// @Controller('leave-requests')
|
|
||||||
// export class LeaveRequestController {
|
|
||||||
// constructor(private readonly leave_service: LeaveRequestsService){}
|
|
||||||
|
|
||||||
// @Post('upsert')
|
|
||||||
// async upsertLeaveRequest(@Body() dto: UpsertLeaveRequestDto) {
|
|
||||||
// const { action, leave_requests } = await this.leave_service.handle(dto);
|
|
||||||
// return { action, leave_requests };
|
|
||||||
// }q
|
|
||||||
|
|
||||||
// //TODO:
|
|
||||||
// /*
|
|
||||||
// @Get('archive')
|
|
||||||
// findAllArchived(){...}
|
|
||||||
|
|
||||||
// @Get('archive/:id')
|
|
||||||
// findOneArchived(id){...}
|
|
||||||
// */
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
// import { PrismaService } from "src/prisma/prisma.service";
|
|
||||||
// import { LeaveRequestController } from "./controllers/leave-requests.controller";
|
|
||||||
// import { HolidayLeaveRequestsService } from "./services/holiday-leave-requests.service";
|
|
||||||
// import { Module } from "@nestjs/common";
|
|
||||||
// import { BusinessLogicsModule } from "src/modules/business-logics/business-logics.module";
|
|
||||||
// import { VacationLeaveRequestsService } from "./services/vacation-leave-requests.service";
|
|
||||||
// import { SickLeaveRequestsService } from "./services/sick-leave-requests.service";
|
|
||||||
// import { LeaveRequestsService } from "./services/leave-request.service";
|
|
||||||
// import { ShiftsModule } from "../shifts/shifts.module";
|
|
||||||
// import { LeaveRequestsUtils } from "./utils/leave-request.util";
|
|
||||||
// import { SharedModule } from "../shared/shared.module";
|
|
||||||
|
|
||||||
// @Module({
|
|
||||||
// imports: [BusinessLogicsModule, ShiftsModule, SharedModule],
|
|
||||||
// controllers: [LeaveRequestController],
|
|
||||||
// providers: [
|
|
||||||
// VacationLeaveRequestsService,
|
|
||||||
// SickLeaveRequestsService,
|
|
||||||
// HolidayLeaveRequestsService,
|
|
||||||
// LeaveRequestsService,
|
|
||||||
// PrismaService,
|
|
||||||
// LeaveRequestsUtils,
|
|
||||||
// ],
|
|
||||||
// exports: [
|
|
||||||
// LeaveRequestsService,
|
|
||||||
// ],
|
|
||||||
// })
|
|
||||||
|
|
||||||
// export class LeaveRequestsModule {}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
// import { UpsertLeaveRequestDto, UpsertResult } from '../dtos/upsert-leave-request.dto';
|
|
||||||
// import { LeaveRequestViewDto } from '../dtos/leave-request-view.dto';
|
|
||||||
// import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
|
||||||
// import { LeaveApprovalStatus, LeaveTypes } from '@prisma/client';
|
|
||||||
// import { HolidayService } from 'src/modules/business-logics/services/holiday.service';
|
|
||||||
// import { PrismaService } from 'src/prisma/prisma.service';
|
|
||||||
// import { mapRowToView } from '../mappers/leave-requests.mapper';
|
|
||||||
// import { leaveRequestsSelect } from '../utils/leave-requests.select';
|
|
||||||
// import { LeaveRequestsUtils} from '../utils/leave-request.util';
|
|
||||||
// import { normalizeDates, toDateOnly } from 'src/modules/shared/helpers/date-time.helpers';
|
|
||||||
// import { BankCodesResolver } from 'src/modules/shared/utils/resolve-bank-type-id.utils';
|
|
||||||
// import { EmailToIdResolver } from 'src/modules/shared/utils/resolve-email-id.utils';
|
|
||||||
|
|
||||||
|
|
||||||
// @Injectable()
|
|
||||||
// export class HolidayLeaveRequestsService {
|
|
||||||
// constructor(
|
|
||||||
// private readonly prisma: PrismaService,
|
|
||||||
// private readonly holidayService: HolidayService,
|
|
||||||
// private readonly leaveUtils: LeaveRequestsUtils,
|
|
||||||
// private readonly emailResolver: EmailToIdResolver,
|
|
||||||
// private readonly typeResolver: BankCodesResolver,
|
|
||||||
// ) {}
|
|
||||||
|
|
||||||
// async create(dto: UpsertLeaveRequestDto): Promise<UpsertResult> {
|
|
||||||
// const email = dto.email.trim();
|
|
||||||
// const employee_id = await this.emailResolver.findIdByEmail(email);
|
|
||||||
// const bank_code = await this.typeResolver.findByType(LeaveTypes.HOLIDAY);
|
|
||||||
// if(!bank_code) throw new NotFoundException(`bank_code not found`);
|
|
||||||
// const dates = normalizeDates(dto.dates);
|
|
||||||
// if (!dates.length) throw new BadRequestException('Dates array must not be empty');
|
|
||||||
|
|
||||||
// const created: LeaveRequestViewDto[] = [];
|
|
||||||
|
|
||||||
// for (const iso_date of dates) {
|
|
||||||
// const date = toDateOnly(iso_date);
|
|
||||||
|
|
||||||
// const existing = await this.prisma.leaveRequests.findUnique({
|
|
||||||
// where: {
|
|
||||||
// leave_per_employee_date: {
|
|
||||||
// employee_id: employee_id,
|
|
||||||
// leave_type: LeaveTypes.HOLIDAY,
|
|
||||||
// date,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// select: { id: true },
|
|
||||||
// });
|
|
||||||
// if (existing) {
|
|
||||||
// throw new BadRequestException(`Holiday request already exists for ${iso_date}`);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const payable = await this.holidayService.calculateHolidayPay(email, date, bank_code.modifier);
|
|
||||||
// const row = await this.prisma.leaveRequests.create({
|
|
||||||
// data: {
|
|
||||||
// employee_id: employee_id,
|
|
||||||
// bank_code_id: bank_code.id,
|
|
||||||
// leave_type: LeaveTypes.HOLIDAY,
|
|
||||||
// date,
|
|
||||||
// comment: dto.comment ?? '',
|
|
||||||
// requested_hours: dto.requested_hours ?? 8,
|
|
||||||
// payable_hours: payable,
|
|
||||||
// approval_status: dto.approval_status ?? LeaveApprovalStatus.PENDING,
|
|
||||||
// },
|
|
||||||
// select: leaveRequestsSelect,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const hours = Number(row.payable_hours ?? row.requested_hours ?? 0);
|
|
||||||
// if (row.approval_status === LeaveApprovalStatus.APPROVED) {
|
|
||||||
// await this.leaveUtils.syncShift(email, employee_id, iso_date, hours,LeaveTypes.HOLIDAY, row.comment);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// created.push({ ...mapRowToView(row), action: 'create' });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return { action: 'create', leave_requests: created };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
@ -1,248 +0,0 @@
|
||||||
// import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
|
||||||
// import { LeaveApprovalStatus, LeaveTypes } from "@prisma/client";
|
|
||||||
// import { roundToQuarterHour } from "src/common/utils/date-utils";
|
|
||||||
// import { UpsertLeaveRequestDto, UpsertResult } from "../dtos/upsert-leave-request.dto";
|
|
||||||
// import { LeaveRequestViewDto } from "../dtos/leave-request-view.dto";
|
|
||||||
// import { mapRowToView } from "../mappers/leave-requests.mapper";
|
|
||||||
// import { leaveRequestsSelect } from "../utils/leave-requests.select";
|
|
||||||
// import { HolidayLeaveRequestsService } from "./holiday-leave-requests.service";
|
|
||||||
// import { SickLeaveRequestsService } from "./sick-leave-requests.service";
|
|
||||||
// import { VacationLeaveRequestsService } from "./vacation-leave-requests.service";
|
|
||||||
// import { HolidayService } from "src/modules/business-logics/services/holiday.service";
|
|
||||||
// import { SickLeaveService } from "src/modules/business-logics/services/sick-leave.service";
|
|
||||||
// import { VacationService } from "src/modules/business-logics/services/vacation.service";
|
|
||||||
// import { PrismaService } from "src/prisma/prisma.service";
|
|
||||||
// import { LeaveRequestsUtils } from "../utils/leave-request.util";
|
|
||||||
// import { normalizeDates, toDateOnly, toISODateKey } from "src/modules/shared/helpers/date-time.helpers";
|
|
||||||
// import { EmailToIdResolver } from "src/modules/shared/utils/resolve-email-id.utils";
|
|
||||||
// import { BankCodesResolver } from "src/modules/shared/utils/resolve-bank-type-id.utils";
|
|
||||||
|
|
||||||
// @Injectable()
|
|
||||||
// export class LeaveRequestsService {
|
|
||||||
// constructor(
|
|
||||||
// private readonly prisma: PrismaService,
|
|
||||||
// private readonly holidayLeaveService: HolidayLeaveRequestsService,
|
|
||||||
// private readonly holidayService: HolidayService,
|
|
||||||
// private readonly sickLogic: SickLeaveService,
|
|
||||||
// private readonly sickLeaveService: SickLeaveRequestsService,
|
|
||||||
// private readonly vacationLeaveService: VacationLeaveRequestsService,
|
|
||||||
// private readonly vacationLogic: VacationService,
|
|
||||||
// private readonly leaveUtils: LeaveRequestsUtils,
|
|
||||||
// private readonly emailResolver: EmailToIdResolver,
|
|
||||||
// private readonly typeResolver: BankCodesResolver,
|
|
||||||
// ) {}
|
|
||||||
|
|
||||||
// //handle distribution to the right service according to the selected type and action
|
|
||||||
// async handle(dto: UpsertLeaveRequestDto): Promise<UpsertResult> {
|
|
||||||
// switch (dto.type) {
|
|
||||||
// case LeaveTypes.HOLIDAY:
|
|
||||||
// if( dto.action === 'create'){
|
|
||||||
// return this.holidayLeaveService.create(dto);
|
|
||||||
// } else if (dto.action === 'update') {
|
|
||||||
// return this.update(dto, LeaveTypes.HOLIDAY);
|
|
||||||
// } else if (dto.action === 'delete'){
|
|
||||||
// return this.delete(dto, LeaveTypes.HOLIDAY);
|
|
||||||
// }
|
|
||||||
// case LeaveTypes.VACATION:
|
|
||||||
// if( dto.action === 'create'){
|
|
||||||
// return this.vacationLeaveService.create(dto);
|
|
||||||
// } else if (dto.action === 'update') {
|
|
||||||
// return this.update(dto, LeaveTypes.VACATION);
|
|
||||||
// } else if (dto.action === 'delete'){
|
|
||||||
// return this.delete(dto, LeaveTypes.VACATION);
|
|
||||||
// }
|
|
||||||
// case LeaveTypes.SICK:
|
|
||||||
// if( dto.action === 'create'){
|
|
||||||
// return this.sickLeaveService.create(dto);
|
|
||||||
// } else if (dto.action === 'update') {
|
|
||||||
// return this.update(dto, LeaveTypes.SICK);
|
|
||||||
// } else if (dto.action === 'delete'){
|
|
||||||
// return this.delete(dto, LeaveTypes.SICK);
|
|
||||||
// }
|
|
||||||
// default:
|
|
||||||
// throw new BadRequestException(`Unsupported leave type: ${dto.type} or action: ${dto.action}`);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async delete(dto: UpsertLeaveRequestDto, type: LeaveTypes): Promise<UpsertResult> {
|
|
||||||
// const email = dto.email.trim();
|
|
||||||
// const dates = normalizeDates(dto.dates);
|
|
||||||
// const employee_id = await this.emailResolver.findIdByEmail(email);
|
|
||||||
// if (!dates.length) throw new BadRequestException("Dates array must not be empty");
|
|
||||||
|
|
||||||
// const rows = await this.prisma.leaveRequests.findMany({
|
|
||||||
// where: {
|
|
||||||
// employee_id: employee_id,
|
|
||||||
// leave_type: type,
|
|
||||||
// date: { in: dates.map((d) => toDateOnly(d)) },
|
|
||||||
// },
|
|
||||||
// select: leaveRequestsSelect,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (rows.length !== dates.length) {
|
|
||||||
// const missing = dates.filter((isoDate) => !rows.some((row) => toISODateKey(row.date) === isoDate));
|
|
||||||
// throw new NotFoundException(`No Leave request found for: ${missing.join(", ")}`);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (const row of rows) {
|
|
||||||
// if (row.approval_status === LeaveApprovalStatus.APPROVED) {
|
|
||||||
// const iso = toISODateKey(row.date);
|
|
||||||
// await this.leaveUtils.removeShift(email, employee_id, iso, type);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// await this.prisma.leaveRequests.deleteMany({
|
|
||||||
// where: { id: { in: rows.map((row) => row.id) } },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const deleted = rows.map((row) => ({ ...mapRowToView(row), action: "delete" as const }));
|
|
||||||
// return { action: "delete", leave_requests: deleted };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async update(dto: UpsertLeaveRequestDto, type: LeaveTypes): Promise<UpsertResult> {
|
|
||||||
// const email = dto.email.trim();
|
|
||||||
// const employee_id = await this.emailResolver.findIdByEmail(email);
|
|
||||||
// const bank_code = await this.typeResolver.findByType(type);
|
|
||||||
// if(!bank_code) throw new NotFoundException(`bank_code not found`);
|
|
||||||
// const modifier = Number(bank_code.modifier ?? 1);
|
|
||||||
// const dates = normalizeDates(dto.dates);
|
|
||||||
// if (!dates.length) {
|
|
||||||
// throw new BadRequestException("Dates array must not be empty");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const entries = await Promise.all(
|
|
||||||
// dates.map(async (iso_date) => {
|
|
||||||
// const date = toDateOnly(iso_date);
|
|
||||||
// const existing = await this.prisma.leaveRequests.findUnique({
|
|
||||||
// where: {
|
|
||||||
// leave_per_employee_date: {
|
|
||||||
// employee_id: employee_id,
|
|
||||||
// leave_type: type,
|
|
||||||
// date,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// select: leaveRequestsSelect,
|
|
||||||
// });
|
|
||||||
// if (!existing) throw new NotFoundException(`No Leave request found for ${iso_date}`);
|
|
||||||
// return { iso_date, date, existing };
|
|
||||||
// }),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const updated: LeaveRequestViewDto[] = [];
|
|
||||||
|
|
||||||
// if (type === LeaveTypes.SICK) {
|
|
||||||
// const firstExisting = entries[0].existing;
|
|
||||||
// const fallbackRequested =
|
|
||||||
// firstExisting.requested_hours !== null && firstExisting.requested_hours !== undefined
|
|
||||||
// ? Number(firstExisting.requested_hours)
|
|
||||||
// : 8;
|
|
||||||
// const requested_hours_per_day = dto.requested_hours ?? fallbackRequested;
|
|
||||||
// const reference_date = entries.reduce(
|
|
||||||
// (latest, entry) => (entry.date > latest ? entry.date : latest),
|
|
||||||
// entries[0].date,
|
|
||||||
// );
|
|
||||||
// const total_payable_hours = await this.sickLogic.calculateSickLeavePay(
|
|
||||||
// employee_id,
|
|
||||||
// reference_date,
|
|
||||||
// entries.length,
|
|
||||||
// requested_hours_per_day,
|
|
||||||
// modifier,
|
|
||||||
// );
|
|
||||||
// let remaining_payable_hours = roundToQuarterHour(Math.max(0, total_payable_hours));
|
|
||||||
// const daily_payable_cap = roundToQuarterHour(requested_hours_per_day * modifier);
|
|
||||||
|
|
||||||
// for (const { iso_date, existing } of entries) {
|
|
||||||
// const previous_status = existing.approval_status;
|
|
||||||
// const payable = Math.min(remaining_payable_hours, daily_payable_cap);
|
|
||||||
// const payable_rounded = roundToQuarterHour(Math.max(0, payable));
|
|
||||||
// remaining_payable_hours = roundToQuarterHour(
|
|
||||||
// Math.max(0, remaining_payable_hours - payable_rounded),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const row = await this.prisma.leaveRequests.update({
|
|
||||||
// where: { id: existing.id },
|
|
||||||
// data: {
|
|
||||||
// comment: dto.comment ?? existing.comment,
|
|
||||||
// requested_hours: requested_hours_per_day,
|
|
||||||
// payable_hours: payable_rounded,
|
|
||||||
// bank_code_id: bank_code.id,
|
|
||||||
// approval_status: dto.approval_status ?? existing.approval_status,
|
|
||||||
// },
|
|
||||||
// select: leaveRequestsSelect,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const was_approved = previous_status === LeaveApprovalStatus.APPROVED;
|
|
||||||
// const is_approved = row.approval_status === LeaveApprovalStatus.APPROVED;
|
|
||||||
// const hours = Number(row.payable_hours ?? row.requested_hours ?? 0);
|
|
||||||
|
|
||||||
// if (!was_approved && is_approved) {
|
|
||||||
// await this.leaveUtils.syncShift(email, employee_id, iso_date, hours, type, row.comment);
|
|
||||||
// } else if (was_approved && !is_approved) {
|
|
||||||
// await this.leaveUtils.removeShift(email, employee_id, iso_date, type);
|
|
||||||
// } else if (was_approved && is_approved) {
|
|
||||||
// await this.leaveUtils.syncShift(email, employee_id, iso_date, hours, type, row.comment);
|
|
||||||
// }
|
|
||||||
// updated.push({ ...mapRowToView(row), action: "update" });
|
|
||||||
// }
|
|
||||||
// return { action: "update", leave_requests: updated };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (const { iso_date, date, existing } of entries) {
|
|
||||||
// const previous_status = existing.approval_status;
|
|
||||||
// const fallbackRequested =
|
|
||||||
// existing.requested_hours !== null && existing.requested_hours !== undefined
|
|
||||||
// ? Number(existing.requested_hours)
|
|
||||||
// : 8;
|
|
||||||
// const requested_hours = dto.requested_hours ?? fallbackRequested;
|
|
||||||
|
|
||||||
// let payable: number;
|
|
||||||
// switch (type) {
|
|
||||||
// case LeaveTypes.HOLIDAY:
|
|
||||||
// payable = await this.holidayService.calculateHolidayPay(email, date, modifier);
|
|
||||||
// break;
|
|
||||||
// case LeaveTypes.VACATION: {
|
|
||||||
// const days_requested = requested_hours / 8;
|
|
||||||
// payable = await this.vacationLogic.calculateVacationPay(
|
|
||||||
// employee_id,
|
|
||||||
// date,
|
|
||||||
// Math.max(0, days_requested),
|
|
||||||
// modifier,
|
|
||||||
// );
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// default:
|
|
||||||
// payable = existing.payable_hours !== null && existing.payable_hours !== undefined
|
|
||||||
// ? Number(existing.payable_hours)
|
|
||||||
// : requested_hours;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const row = await this.prisma.leaveRequests.update({
|
|
||||||
// where: { id: existing.id },
|
|
||||||
// data: {
|
|
||||||
// requested_hours,
|
|
||||||
// comment: dto.comment ?? existing.comment,
|
|
||||||
// payable_hours: payable,
|
|
||||||
// bank_code_id: bank_code.id,
|
|
||||||
// approval_status: dto.approval_status ?? existing.approval_status,
|
|
||||||
// },
|
|
||||||
// select: leaveRequestsSelect,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const was_approved = previous_status === LeaveApprovalStatus.APPROVED;
|
|
||||||
// const is_approved = row.approval_status === LeaveApprovalStatus.APPROVED;
|
|
||||||
// const hours = Number(row.payable_hours ?? row.requested_hours ?? 0);
|
|
||||||
|
|
||||||
// if (!was_approved && is_approved) {
|
|
||||||
// await this.leaveUtils.syncShift(email, employee_id, iso_date, hours, type, row.comment);
|
|
||||||
// } else if (was_approved && !is_approved) {
|
|
||||||
// await this.leaveUtils.removeShift(email, employee_id, iso_date, type);
|
|
||||||
// } else if (was_approved && is_approved) {
|
|
||||||
// await this.leaveUtils.syncShift(email, employee_id, iso_date, hours, type, row.comment);
|
|
||||||
// }
|
|
||||||
// updated.push({ ...mapRowToView(row), action: "update" });
|
|
||||||
// }
|
|
||||||
// return { action: "update", leave_requests: updated };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
// import { UpsertLeaveRequestDto, UpsertResult } from "../dtos/upsert-leave-request.dto";
|
|
||||||
// import { LeaveRequestViewDto } from "../dtos/leave-request-view.dto";
|
|
||||||
// import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
|
||||||
// import { LeaveApprovalStatus, LeaveTypes } from "@prisma/client";
|
|
||||||
// import { leaveRequestsSelect } from "../utils/leave-requests.select";
|
|
||||||
// import { mapRowToView } from "../mappers/leave-requests.mapper";
|
|
||||||
// import { PrismaService } from "src/prisma/prisma.service";
|
|
||||||
// import { SickLeaveService } from "src/modules/business-logics/services/sick-leave.service";
|
|
||||||
// import { roundToQuarterHour } from "src/common/utils/date-utils";
|
|
||||||
// import { LeaveRequestsUtils } from "../utils/leave-request.util";
|
|
||||||
// import { normalizeDates, toDateOnly } from "src/modules/shared/helpers/date-time.helpers";
|
|
||||||
// import { EmailToIdResolver } from "src/modules/shared/utils/resolve-email-id.utils";
|
|
||||||
// import { BankCodesResolver } from "src/modules/shared/utils/resolve-bank-type-id.utils";
|
|
||||||
|
|
||||||
// @Injectable()
|
|
||||||
// export class SickLeaveRequestsService {
|
|
||||||
// constructor(
|
|
||||||
// private readonly prisma: PrismaService,
|
|
||||||
// private readonly sickService: SickLeaveService,
|
|
||||||
// private readonly leaveUtils: LeaveRequestsUtils,
|
|
||||||
// private readonly emailResolver: EmailToIdResolver,
|
|
||||||
// private readonly typeResolver: BankCodesResolver,
|
|
||||||
// ) {}
|
|
||||||
|
|
||||||
// async create(dto: UpsertLeaveRequestDto): Promise<UpsertResult> {
|
|
||||||
// const email = dto.email.trim();
|
|
||||||
// const employee_id = await this.emailResolver.findIdByEmail(email);
|
|
||||||
// const bank_code = await this.typeResolver.findByType(LeaveTypes.SICK);
|
|
||||||
// if(!bank_code) throw new NotFoundException(`bank_code not found`);
|
|
||||||
|
|
||||||
// const modifier = bank_code.modifier ?? 1;
|
|
||||||
// const dates = normalizeDates(dto.dates);
|
|
||||||
// if (!dates.length) throw new BadRequestException("Dates array must not be empty");
|
|
||||||
// const requested_hours_per_day = dto.requested_hours ?? 8;
|
|
||||||
|
|
||||||
// const entries = dates.map((iso) => ({ iso, date: toDateOnly(iso) }));
|
|
||||||
// const reference_date = entries.reduce(
|
|
||||||
// (latest, entry) => (entry.date > latest ? entry.date : latest),
|
|
||||||
// entries[0].date,
|
|
||||||
// );
|
|
||||||
// const total_payable_hours = await this.sickService.calculateSickLeavePay(
|
|
||||||
// employee_id,
|
|
||||||
// reference_date,
|
|
||||||
// entries.length,
|
|
||||||
// requested_hours_per_day,
|
|
||||||
// modifier,
|
|
||||||
// );
|
|
||||||
// let remaining_payable_hours = roundToQuarterHour(Math.max(0, total_payable_hours));
|
|
||||||
// const daily_payable_cap = roundToQuarterHour(requested_hours_per_day * modifier);
|
|
||||||
|
|
||||||
// const created: LeaveRequestViewDto[] = [];
|
|
||||||
|
|
||||||
// for (const { iso, date } of entries) {
|
|
||||||
// const existing = await this.prisma.leaveRequests.findUnique({
|
|
||||||
// where: {
|
|
||||||
// leave_per_employee_date: {
|
|
||||||
// employee_id: employee_id,
|
|
||||||
// leave_type: LeaveTypes.SICK,
|
|
||||||
// date,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// select: { id: true },
|
|
||||||
// });
|
|
||||||
// if (existing) {
|
|
||||||
// throw new BadRequestException(`Sick request already exists for ${iso}`);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const payable = Math.min(remaining_payable_hours, daily_payable_cap);
|
|
||||||
// const payable_rounded = roundToQuarterHour(Math.max(0, payable));
|
|
||||||
// remaining_payable_hours = roundToQuarterHour(
|
|
||||||
// Math.max(0, remaining_payable_hours - payable_rounded),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const row = await this.prisma.leaveRequests.create({
|
|
||||||
// data: {
|
|
||||||
// employee_id: employee_id,
|
|
||||||
// bank_code_id: bank_code.id,
|
|
||||||
// leave_type: LeaveTypes.SICK,
|
|
||||||
// comment: dto.comment ?? "",
|
|
||||||
// requested_hours: requested_hours_per_day,
|
|
||||||
// payable_hours: payable_rounded,
|
|
||||||
// approval_status: dto.approval_status ?? LeaveApprovalStatus.PENDING,
|
|
||||||
// date,
|
|
||||||
// },
|
|
||||||
// select: leaveRequestsSelect,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const hours = Number(row.payable_hours ?? row.requested_hours ?? 0);
|
|
||||||
// if (row.approval_status === LeaveApprovalStatus.APPROVED) {
|
|
||||||
// await this.leaveUtils.syncShift(email, employee_id, iso, hours,LeaveTypes.SICK, row.comment);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// created.push({ ...mapRowToView(row), action: "create" });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return { action: "create", leave_requests: created };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
|
|
||||||
// import { UpsertLeaveRequestDto, UpsertResult } from "../dtos/upsert-leave-request.dto";
|
|
||||||
// import { LeaveRequestViewDto } from "../dtos/leave-request-view.dto";
|
|
||||||
// import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
|
||||||
// import { LeaveApprovalStatus, LeaveTypes } from "@prisma/client";
|
|
||||||
// import { VacationService } from "src/modules/business-logics/services/vacation.service";
|
|
||||||
// import { PrismaService } from "src/prisma/prisma.service";
|
|
||||||
// import { mapRowToView } from "../mappers/leave-requests.mapper";
|
|
||||||
// import { leaveRequestsSelect } from "../utils/leave-requests.select";
|
|
||||||
// import { roundToQuarterHour } from "src/common/utils/date-utils";
|
|
||||||
// import { LeaveRequestsUtils } from "../utils/leave-request.util";
|
|
||||||
// import { normalizeDates, toDateOnly } from "src/modules/shared/helpers/date-time.helpers";
|
|
||||||
// import { EmailToIdResolver } from "src/modules/shared/utils/resolve-email-id.utils";
|
|
||||||
// import { BankCodesResolver } from "src/modules/shared/utils/resolve-bank-type-id.utils";
|
|
||||||
|
|
||||||
// @Injectable()
|
|
||||||
// export class VacationLeaveRequestsService {
|
|
||||||
// constructor(
|
|
||||||
// private readonly prisma: PrismaService,
|
|
||||||
// private readonly vacationService: VacationService,
|
|
||||||
// private readonly leaveUtils: LeaveRequestsUtils,
|
|
||||||
// private readonly emailResolver: EmailToIdResolver,
|
|
||||||
// private readonly typeResolver: BankCodesResolver,
|
|
||||||
// ) {}
|
|
||||||
|
|
||||||
// async create(dto: UpsertLeaveRequestDto): Promise<UpsertResult> {
|
|
||||||
// const email = dto.email.trim();
|
|
||||||
// const employee_id = await this.emailResolver.findIdByEmail(email);
|
|
||||||
// const bank_code = await this.typeResolver.findByType(LeaveTypes.VACATION);
|
|
||||||
// if(!bank_code) throw new NotFoundException(`bank_code not found`);
|
|
||||||
|
|
||||||
// const modifier = bank_code.modifier ?? 1;
|
|
||||||
// const dates = normalizeDates(dto.dates);
|
|
||||||
// const requested_hours_per_day = dto.requested_hours ?? 8;
|
|
||||||
// if (!dates.length) throw new BadRequestException("Dates array must not be empty");
|
|
||||||
|
|
||||||
// const entries = dates
|
|
||||||
// .map((iso) => ({ iso, date: toDateOnly(iso) }))
|
|
||||||
// .sort((a, b) => a.date.getTime() - b.date.getTime());
|
|
||||||
// const start_date = entries[0].date;
|
|
||||||
// const total_payable_hours = await this.vacationService.calculateVacationPay(
|
|
||||||
// employee_id,
|
|
||||||
// start_date,
|
|
||||||
// entries.length,
|
|
||||||
// modifier,
|
|
||||||
// );
|
|
||||||
// let remaining_payable_hours = roundToQuarterHour(Math.max(0, total_payable_hours));
|
|
||||||
// const daily_payable_cap = roundToQuarterHour(requested_hours_per_day * modifier);
|
|
||||||
|
|
||||||
// const created: LeaveRequestViewDto[] = [];
|
|
||||||
|
|
||||||
// for (const { iso, date } of entries) {
|
|
||||||
// const existing = await this.prisma.leaveRequests.findUnique({
|
|
||||||
// where: {
|
|
||||||
// leave_per_employee_date: {
|
|
||||||
// employee_id: employee_id,
|
|
||||||
// leave_type: LeaveTypes.VACATION,
|
|
||||||
// date,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// select: { id: true },
|
|
||||||
// });
|
|
||||||
// if (existing) throw new BadRequestException(`Vacation request already exists for ${iso}`);
|
|
||||||
|
|
||||||
// const payable = Math.min(remaining_payable_hours, daily_payable_cap);
|
|
||||||
// const payable_rounded = roundToQuarterHour(Math.max(0, payable));
|
|
||||||
// remaining_payable_hours = roundToQuarterHour(
|
|
||||||
// Math.max(0, remaining_payable_hours - payable_rounded),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const row = await this.prisma.leaveRequests.create({
|
|
||||||
// data: {
|
|
||||||
// employee_id: employee_id,
|
|
||||||
// bank_code_id: bank_code.id,
|
|
||||||
// payable_hours: payable_rounded,
|
|
||||||
// requested_hours: requested_hours_per_day,
|
|
||||||
// leave_type: LeaveTypes.VACATION,
|
|
||||||
// comment: dto.comment ?? "",
|
|
||||||
// approval_status: dto.approval_status ?? LeaveApprovalStatus.PENDING,
|
|
||||||
// date,
|
|
||||||
// },
|
|
||||||
// select: leaveRequestsSelect,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const hours = Number(row.payable_hours ?? row.requested_hours ?? 0);
|
|
||||||
// if (row.approval_status === LeaveApprovalStatus.APPROVED) {
|
|
||||||
// await this.leaveUtils.syncShift(email, employee_id, iso, hours, LeaveTypes.VACATION, row.comment);
|
|
||||||
// }
|
|
||||||
// created.push({ ...mapRowToView(row), action: "create" });
|
|
||||||
// }
|
|
||||||
// return { action: "create", leave_requests: created };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
// import { hhmmFromLocal, toDateOnly, toStringFromDate } from "src/modules/shared/helpers/date-time.helpers";
|
|
||||||
// import { BadRequestException, Injectable } from "@nestjs/common";
|
|
||||||
// import { PrismaService } from "src/prisma/prisma.service";
|
|
||||||
// import { LeaveTypes } from "@prisma/client";
|
|
||||||
// import { UpsertAction } from "src/modules/shared/types/upsert-actions.types";
|
|
||||||
|
|
||||||
// @Injectable()
|
|
||||||
// export class LeaveRequestsUtils {
|
|
||||||
// constructor(
|
|
||||||
// private readonly prisma: PrismaService,
|
|
||||||
// private readonly shiftsCommand: ShiftsCommandService,
|
|
||||||
// ){}
|
|
||||||
|
|
||||||
// async syncShift(
|
|
||||||
// email: string,
|
|
||||||
// employee_id: number,
|
|
||||||
// date: string,
|
|
||||||
// hours: number,
|
|
||||||
// type: LeaveTypes,
|
|
||||||
// comment?: string,
|
|
||||||
// ) {
|
|
||||||
// if (hours <= 0) return;
|
|
||||||
|
|
||||||
// const duration_minutes = Math.round(hours * 60);
|
|
||||||
// if (duration_minutes > 8 * 60) {
|
|
||||||
// throw new BadRequestException("Amount of hours cannot exceed 8 hours per day.");
|
|
||||||
// }
|
|
||||||
// const date_only = toDateOnly(date);
|
|
||||||
// const yyyy_mm_dd = toStringFromDate(date_only);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// const start_minutes = 8 * 60;
|
|
||||||
// const end_minutes = start_minutes + duration_minutes;
|
|
||||||
// const toHHmm = (total: number) =>
|
|
||||||
// `${String(Math.floor(total / 60)).padStart(2, "0")}:${String(total % 60).padStart(2, "0")}`;
|
|
||||||
|
|
||||||
// const existing = await this.prisma.shifts.findFirst({
|
|
||||||
// where: {
|
|
||||||
// date: date_only,
|
|
||||||
// bank_code: { type },
|
|
||||||
// timesheet: { employee_id: employee_id },
|
|
||||||
// },
|
|
||||||
// include: { bank_code: true },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const action: UpsertAction = existing ? 'update' : 'create';
|
|
||||||
|
|
||||||
// await this.shiftsCommand.upsertShifts(email, action, {
|
|
||||||
// old_shift: existing
|
|
||||||
// ? {
|
|
||||||
// date: yyyy_mm_dd,
|
|
||||||
// start_time: existing.start_time.toISOString().slice(11, 16),
|
|
||||||
// end_time: existing.end_time.toISOString().slice(11, 16),
|
|
||||||
// type: existing.bank_code?.type ?? type,
|
|
||||||
// is_remote: existing.is_remote,
|
|
||||||
// is_approved:existing.is_approved,
|
|
||||||
// comment: existing.comment ?? undefined,
|
|
||||||
// }
|
|
||||||
// : undefined,
|
|
||||||
// new_shift: {
|
|
||||||
// date: yyyy_mm_dd,
|
|
||||||
// start_time: toHHmm(start_minutes),
|
|
||||||
// end_time: toHHmm(end_minutes),
|
|
||||||
// is_remote: existing?.is_remote ?? false,
|
|
||||||
// is_approved:existing?.is_approved ?? false,
|
|
||||||
// comment: comment ?? existing?.comment ?? "",
|
|
||||||
// type: type,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async removeShift(
|
|
||||||
// email: string,
|
|
||||||
// employee_id: number,
|
|
||||||
// iso_date: string,
|
|
||||||
// type: LeaveTypes,
|
|
||||||
// ) {
|
|
||||||
// const date_only = toDateOnly(iso_date);
|
|
||||||
// const yyyy_mm_dd = toStringFromDate(date_only);
|
|
||||||
// const existing = await this.prisma.shifts.findFirst({
|
|
||||||
// where: {
|
|
||||||
// date: date_only,
|
|
||||||
// bank_code: { type },
|
|
||||||
// timesheet: { employee_id: employee_id },
|
|
||||||
// },
|
|
||||||
// include: { bank_code: true },
|
|
||||||
// });
|
|
||||||
// if (!existing) return;
|
|
||||||
|
|
||||||
// await this.shiftsCommand.upsertShifts(email, 'delete', {
|
|
||||||
// old_shift: {
|
|
||||||
// date: yyyy_mm_dd,
|
|
||||||
// start_time: hhmmFromLocal(existing.start_time),
|
|
||||||
// end_time: hhmmFromLocal(existing.end_time),
|
|
||||||
// type: existing.bank_code?.type ?? type,
|
|
||||||
// is_remote: existing.is_remote,
|
|
||||||
// is_approved:existing.is_approved,
|
|
||||||
// comment: existing.comment ?? undefined,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
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, UpdateResult } from "../services/expense-upsert.service";
|
||||||
|
import { updateExpenseDto } from "src/time-and-attendance/modules/expenses/dtos/update-expense.dto";
|
||||||
|
|
||||||
|
|
||||||
|
@Controller('expense')
|
||||||
|
export class ExpenseController {
|
||||||
|
constructor(
|
||||||
|
private readonly prisma: PrismaService,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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,7 +3,7 @@ import { IsBoolean, IsInt, IsOptional, IsString, MaxLength } from "class-validat
|
||||||
export class ExpenseDto {
|
export class ExpenseDto {
|
||||||
@IsInt() bank_code_id!: number;
|
@IsInt() bank_code_id!: number;
|
||||||
@IsInt() timesheet_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() amount?: number;
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
export class GetExpenseDto {
|
export class GetExpenseDto {
|
||||||
|
id: number;
|
||||||
timesheet_id: number;
|
timesheet_id: number;
|
||||||
bank_code_id: number;
|
bank_code_id: number;
|
||||||
attachment?: string;
|
attachment?: number;
|
||||||
date: string;
|
date: string;
|
||||||
comment: string;
|
comment: string;
|
||||||
mileage?: number;
|
mileage?: number;
|
||||||
15
src/time-and-attendance/modules/expenses/expenses.module.ts
Normal file
15
src/time-and-attendance/modules/expenses/expenses.module.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { ExpensesArchivalService } from "./services/expenses-archival.service";
|
||||||
|
import { ExpenseUpsertService } from "src/time-and-attendance/modules/expenses/services/expense-upsert.service";
|
||||||
|
import { ExpenseController } from "src/time-and-attendance/modules/expenses/controllers/expense.controller";
|
||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
import { BusinessLogicsModule } from "src/time-and-attendance/domains/business-logics.module";
|
||||||
|
import { SharedModule } from "src/time-and-attendance/modules/shared/shared.module";
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [ BusinessLogicsModule, SharedModule ],
|
||||||
|
controllers: [ ExpenseController ],
|
||||||
|
providers: [ ExpenseUpsertService, ExpensesArchivalService ],
|
||||||
|
exports: [ ExpensesArchivalService ],
|
||||||
|
})
|
||||||
|
|
||||||
|
export class ExpensesModule {}
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
export const toDateFromString = (ymd: string): Date => {
|
export const toDateFromString = (ymd: string): Date => {
|
||||||
return new Date(`${ymd}T00:00:00:000Z`);
|
return new Date(`${ymd}T00:00:00:000Z`);
|
||||||
}
|
}
|
||||||
|
export const toStringFromDate = (date: Date) =>
|
||||||
|
date.toISOString().slice(0,10);
|
||||||
|
|
@ -0,0 +1,184 @@
|
||||||
|
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";
|
||||||
|
|
||||||
|
type Normalized = { date: Date; comment: string; supervisor_comment?: string; };
|
||||||
|
|
||||||
|
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 };
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ExpenseUpsertService {
|
||||||
|
constructor(private readonly prisma: PrismaService) { }
|
||||||
|
|
||||||
|
//_________________________________________________________________
|
||||||
|
// CREATE
|
||||||
|
//_________________________________________________________________
|
||||||
|
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 comment = this.truncate280(dto.comment);
|
||||||
|
const supervisor_comment =
|
||||||
|
dto.supervisor_comment && dto.supervisor_comment.trim()
|
||||||
|
? this.truncate280(dto.supervisor_comment.trim())
|
||||||
|
: undefined;
|
||||||
|
return { date, comment, supervisor_comment };
|
||||||
|
}
|
||||||
|
|
||||||
|
//makes sure that a string cannot exceed 280 chars
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Body, Controller, Post } from "@nestjs/common";
|
||||||
|
import { ApiBearerAuth, ApiTags } from "@nestjs/swagger";
|
||||||
|
import { LeaveRequestsService } from "../services/leave-request.service";
|
||||||
|
import { UpsertLeaveRequestDto } from "../dtos/upsert-leave-request.dto";
|
||||||
|
import { LeaveTypes } from "@prisma/client";
|
||||||
|
|
||||||
|
@ApiTags('Leave Requests')
|
||||||
|
@ApiBearerAuth('access-token')
|
||||||
|
// @UseGuards()
|
||||||
|
@Controller('leave-requests')
|
||||||
|
export class LeaveRequestController {
|
||||||
|
constructor(private readonly leave_service: LeaveRequestsService){}
|
||||||
|
|
||||||
|
@Post('upsert')
|
||||||
|
async upsertLeaveRequest(@Body() dto: UpsertLeaveRequestDto) {
|
||||||
|
const { action, leave_requests } = await this.leave_service.handle(dto);
|
||||||
|
return { action, leave_requests };
|
||||||
|
}q
|
||||||
|
|
||||||
|
//TODO:
|
||||||
|
/*
|
||||||
|
@Get('archive')
|
||||||
|
findAllArchived(){...}
|
||||||
|
|
||||||
|
@Get('archive/:id')
|
||||||
|
findOneArchived(id){...}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Module } from "@nestjs/common";
|
||||||
|
import { PrismaService } from "src/prisma/prisma.service";
|
||||||
|
import { BusinessLogicsModule } from "src/time-and-attendance/domains/business-logics.module";
|
||||||
|
import { HolidayService } from "src/time-and-attendance/domains/services/holiday.service";
|
||||||
|
import { SickLeaveService } from "src/time-and-attendance/domains/services/sick-leave.service";
|
||||||
|
import { VacationService } from "src/time-and-attendance/domains/services/vacation.service";
|
||||||
|
import { LeaveRequestController } from "src/time-and-attendance/modules/leave-requests/controllers/leave-requests.controller";
|
||||||
|
import { LeaveRequestsService } from "src/time-and-attendance/modules/leave-requests/services/leave-request.service";
|
||||||
|
import { LeaveRequestsUtils } from "src/time-and-attendance/modules/leave-requests/utils/leave-request.util";
|
||||||
|
import { SharedModule } from "src/time-and-attendance/modules/shared/shared.module";
|
||||||
|
import { ShiftsModule } from "src/time-and-attendance/modules/time-tracker/shifts/shifts.module";
|
||||||
|
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [BusinessLogicsModule, ShiftsModule, SharedModule],
|
||||||
|
controllers: [LeaveRequestController],
|
||||||
|
providers: [
|
||||||
|
VacationService,
|
||||||
|
SickLeaveService,
|
||||||
|
HolidayService,
|
||||||
|
LeaveRequestsService,
|
||||||
|
PrismaService,
|
||||||
|
LeaveRequestsUtils,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
LeaveRequestsService,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export class LeaveRequestsModule {}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user