Init
This commit is contained in:
30
backend/.eslintrc.js.old
Normal file
30
backend/.eslintrc.js.old
Normal file
@@ -0,0 +1,30 @@
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
'warn',
|
||||
{
|
||||
prefer: 'type-imports',
|
||||
fixStyle: 'inline-type-imports',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'max-len': ['error', 120, 2],
|
||||
},
|
||||
};
|
||||
45
backend/.gitignore
vendored
Normal file
45
backend/.gitignore
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Tests
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.run
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode
|
||||
|
||||
# Http request env
|
||||
artifacts/_environment-config/http-client.env.json
|
||||
|
||||
# Environment configuration
|
||||
.env.local
|
||||
|
||||
# Yarn
|
||||
.yarn/cache/
|
||||
.yarn/unplugged/
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
145
backend/.gitlab-ci.yml
Normal file
145
backend/.gitlab-ci.yml
Normal file
@@ -0,0 +1,145 @@
|
||||
stages:
|
||||
- prepare
|
||||
- build
|
||||
- deploy
|
||||
|
||||
default:
|
||||
image: kroniak/ssh-client
|
||||
interruptible: true
|
||||
before_script:
|
||||
- mkdir -p ~/.ssh
|
||||
- chmod 700 ~/.ssh
|
||||
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
|
||||
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
|
||||
- chmod 400 ~/.ssh/id_rsa
|
||||
|
||||
.prepare_script: &prepare_script
|
||||
- tar -czf sources.tar.gz .
|
||||
- scp -r sources.tar.gz $USER@$SERVER:$FOLDER
|
||||
|
||||
.build_script: &build_script
|
||||
- ssh $USER@$SERVER "cd $FOLDER && ./build.sh"
|
||||
|
||||
.deploy_script: &deploy_script
|
||||
- ssh $USER@$SERVER "cd $FOLDER && ./deploy.sh"
|
||||
|
||||
.staging_job:
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "develop"
|
||||
variables:
|
||||
SSH_PRIVATE_KEY: $STAGING_SSH_PRIVATE_KEY
|
||||
USER: $STAGING_USER
|
||||
SERVER: $STAGING_SERVER
|
||||
FOLDER: /amwork/backend
|
||||
environment:
|
||||
name: staging
|
||||
url: https://amwork.dev
|
||||
|
||||
.amwork_job:
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
variables:
|
||||
SSH_PRIVATE_KEY: $AMWORK_PROD_SSH_PRIVATE_KEY
|
||||
USER: $AMWORK_PROD_USER
|
||||
SERVER: $AMWORK_PROD_SERVER
|
||||
FOLDER: /amwork/backend
|
||||
environment:
|
||||
name: production/amwork
|
||||
url: https://amwork.com
|
||||
|
||||
.mywork_job:
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
variables:
|
||||
SSH_PRIVATE_KEY: $MYWORK_PROD_SSH_PRIVATE_KEY
|
||||
USER: $MYWORK_PROD_USER
|
||||
SERVER: $MYWORK_PROD_SERVER
|
||||
FOLDER: /mywork/backend
|
||||
environment:
|
||||
name: production/mywork
|
||||
url: https://mywork.app
|
||||
|
||||
# Staging
|
||||
staging_prepare:
|
||||
extends: .staging_job
|
||||
stage: prepare
|
||||
script: *prepare_script
|
||||
staging_build:
|
||||
extends: .staging_job
|
||||
stage: build
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script: *build_script
|
||||
staging_deploy:
|
||||
extends: .staging_job
|
||||
stage: deploy
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script: *deploy_script
|
||||
|
||||
# Amwork Production
|
||||
amwork_prepare:
|
||||
extends: .amwork_job
|
||||
stage: prepare
|
||||
script: *prepare_script
|
||||
amwork_build:
|
||||
extends: .amwork_job
|
||||
stage: build
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script: *build_script
|
||||
amwork_deploy:
|
||||
extends: .amwork_job
|
||||
stage: deploy
|
||||
when: manual
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script: *deploy_script
|
||||
|
||||
# Mywork Production
|
||||
mywork_prepare:
|
||||
extends: .mywork_job
|
||||
stage: prepare
|
||||
variables:
|
||||
FOLDER: /apps/mywork/backend
|
||||
script: *prepare_script
|
||||
mywork_build:
|
||||
extends: .mywork_job
|
||||
stage: build
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
FOLDER: /apps/mywork/backend
|
||||
script: *build_script
|
||||
mywork_deploy:
|
||||
extends: .mywork_job
|
||||
stage: deploy
|
||||
when: manual
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
FOLDER: /apps/mywork/backend
|
||||
script: *deploy_script
|
||||
|
||||
# Platforma500 Production
|
||||
platforma500_prepare:
|
||||
extends: .mywork_job
|
||||
stage: prepare
|
||||
needs: [mywork_prepare]
|
||||
variables:
|
||||
FOLDER: /apps/platforma500/backend
|
||||
script: *prepare_script
|
||||
platforma500_build:
|
||||
extends: .mywork_job
|
||||
stage: build
|
||||
needs: [mywork_build]
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
FOLDER: /apps/platforma500/backend
|
||||
script: *build_script
|
||||
platforma500_deploy:
|
||||
extends: .mywork_job
|
||||
stage: deploy
|
||||
when: manual
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
FOLDER: /apps/platforma500/backend
|
||||
script: *deploy_script
|
||||
4
backend/.prettierrc
Normal file
4
backend/.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"printWidth": 120
|
||||
}
|
||||
948
backend/.yarn/releases/yarn-4.9.1.cjs
vendored
Normal file
948
backend/.yarn/releases/yarn-4.9.1.cjs
vendored
Normal file
File diff suppressed because one or more lines are too long
5
backend/.yarnrc.yml
Normal file
5
backend/.yarnrc.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
compressionLevel: mixed
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.9.1.cjs
|
||||
26
backend/README.md
Normal file
26
backend/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Rifeberry backend
|
||||
|
||||
## Общее описание системы
|
||||
|
||||
* [Описание системы](https://olivergrand.atlassian.net/wiki/spaces/TEAM/pages/6291457)
|
||||
* [Упрощенная ER диаграмма](https://olivergrand.atlassian.net/wiki/spaces/BACK/pages/6389854/ER).
|
||||
|
||||
## Настройка локального окружения для разработки
|
||||
|
||||
[Setup local environment](doc/setup-local.md).
|
||||
|
||||
## Deploy
|
||||
|
||||
Деплой: [Gitlab](https://gitlab.com/rifeberry1/nest-backend/-/pipelines).
|
||||
|
||||
## Links
|
||||
|
||||
* [Jira project board](https://olivergrand.atlassian.net/jira/software/projects/BACK/boards/1)
|
||||
* [Confluence space](https://olivergrand.atlassian.net/wiki/spaces/BACK/pages)
|
||||
|
||||
## Именование веток и комитов
|
||||
|
||||
Ветки именуем следующим образом: название задачи и описание в настоящем времени,
|
||||
например, `BACK-123-add-api-doc`
|
||||
|
||||
Комиты именуем название задачи + описание комита: `BACK-123: Add api documentation`
|
||||
104
backend/artifacts/_environment-config/http-client.env.json.dist
Normal file
104
backend/artifacts/_environment-config/http-client.env.json.dist
Normal file
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"nestdev": {
|
||||
"url": "http://test.amwork.loc",
|
||||
"baseDomain": "amwork.loc",
|
||||
"subdomain": "test",
|
||||
"email": "test@test.com",
|
||||
"password": "test",
|
||||
"entityTypeId": 123,
|
||||
"entityId": 123,
|
||||
"teslaDealEntityId": 123,
|
||||
"elonContactEntityId": 123,
|
||||
"boardId": 123,
|
||||
"stageId": 123,
|
||||
"fieldGroupId": 123,
|
||||
"activityTypeId": 123,
|
||||
"taskId": 123,
|
||||
"subtaskId": 123,
|
||||
"taskBoardId": 123,
|
||||
"taskStageId": 15022001,
|
||||
"taskSettingsId": 123,
|
||||
"taskCommentId": 123,
|
||||
"activityId": 123,
|
||||
"noteId": 123,
|
||||
"userId": 123,
|
||||
"budgetFieldId": 123,
|
||||
"fileId": "11111111-1111-1111-1111-111111111111",
|
||||
"mailboxId": 123,
|
||||
"folderId": 123,
|
||||
"messageId": 123,
|
||||
"payloadId": 123,
|
||||
"automationId": 123,
|
||||
"taskAutomationId": 123,
|
||||
"changeStageAutomationId": 123,
|
||||
"notificationId": 123
|
||||
},
|
||||
"nestprod": {
|
||||
"url": "https://test.amwork.com",
|
||||
"baseDomain": "amwork.com",
|
||||
"subdomain": "test",
|
||||
"email": "test@test.com",
|
||||
"password": "test",
|
||||
"entityTypeId": 123,
|
||||
"entityId": 123,
|
||||
"teslaDealEntityId": 123,
|
||||
"elonContactEntityId": 123,
|
||||
"boardId": 123,
|
||||
"stageId": 123,
|
||||
"fieldGroupId": 123,
|
||||
"activityTypeId": 123,
|
||||
"taskId": 123,
|
||||
"subtaskId": 123,
|
||||
"taskBoardId": 123,
|
||||
"taskStageId": 15022001,
|
||||
"taskSettingsId": 123,
|
||||
"taskCommentId": 123,
|
||||
"activityId": 123,
|
||||
"noteId": 123,
|
||||
"userId": 123,
|
||||
"budgetFieldId": 123,
|
||||
"fileId": "11111111-1111-1111-1111-111111111111",
|
||||
"mailboxId": 123,
|
||||
"folderId": 123,
|
||||
"messageId": 123,
|
||||
"payloadId": 123,
|
||||
"automationId": 123,
|
||||
"taskAutomationId": 123,
|
||||
"changeStageAutomationId": 123,
|
||||
"notificationId": 123
|
||||
},
|
||||
"neststaging": {
|
||||
"url": "https://test.amwork.com",
|
||||
"baseDomain": "amwork.com",
|
||||
"subdomain": "test",
|
||||
"email": "test@test.com",
|
||||
"password": "test",
|
||||
"entityTypeId": 123,
|
||||
"entityId": 123,
|
||||
"teslaDealEntityId": 123,
|
||||
"elonContactEntityId": 123,
|
||||
"boardId": 123,
|
||||
"stageId": 123,
|
||||
"fieldGroupId": 123,
|
||||
"activityTypeId": 123,
|
||||
"taskId": 123,
|
||||
"subtaskId": 123,
|
||||
"taskBoardId": 123,
|
||||
"taskStageId": 15022001,
|
||||
"taskSettingsId": 123,
|
||||
"taskCommentId": 123,
|
||||
"activityId": 123,
|
||||
"noteId": 123,
|
||||
"userId": 123,
|
||||
"budgetFieldId": 123,
|
||||
"fileId": "11111111-1111-1111-1111-111111111111",
|
||||
"mailboxId": 123,
|
||||
"folderId": 123,
|
||||
"messageId": 123,
|
||||
"payloadId": 123,
|
||||
"automationId": 123,
|
||||
"taskAutomationId": 123,
|
||||
"changeStageAutomationId": 123,
|
||||
"notificationId": 123
|
||||
}
|
||||
}
|
||||
BIN
backend/artifacts/_resources/test.png
Normal file
BIN
backend/artifacts/_resources/test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 96 KiB |
5
backend/artifacts/account-settings.http
Normal file
5
backend/artifacts/account-settings.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Get account settings
|
||||
|
||||
GET {{url}}/api/account/settings
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
92
backend/artifacts/auth.http
Normal file
92
backend/artifacts/auth.http
Normal file
@@ -0,0 +1,92 @@
|
||||
### Login by subdomain
|
||||
|
||||
POST {{url}}/api/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "{{email}}",
|
||||
"password": "{{password}}"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.global.set("token", response.body.token);
|
||||
client.global.set("userId", response.body.userId);
|
||||
%}
|
||||
|
||||
### Login for site
|
||||
|
||||
POST {{url}}/api/auth/login-site
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "test@test.com",
|
||||
"password": "test"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.global.set("loginLink", response.body.loginLink);
|
||||
client.global.set("subdomain", response.body.subdomain);
|
||||
%}
|
||||
|
||||
### Login for extension
|
||||
|
||||
POST {{url}}/api/auth/login-ext
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "test@test.com",
|
||||
"password": "test"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.global.set("token", response.body.token);
|
||||
client.global.set("userId", response.body.userId);
|
||||
%}
|
||||
|
||||
### Decode login link
|
||||
|
||||
POST {{subdomain}}.{{baseDomain}}/api/auth/decode-login-link
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"loginLink": "{{loginLink}}"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.global.set("token", response.body.token);
|
||||
client.global.set("userId", response.body.userId);
|
||||
%}
|
||||
|
||||
### Refresh token
|
||||
|
||||
POST {{url}}/api/auth/refresh-token
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
> {%
|
||||
client.global.set("token", response.body.token);
|
||||
client.global.set("userId", response.body.userId);
|
||||
|
||||
%}
|
||||
|
||||
### Create account
|
||||
|
||||
POST {{url}}/api/auth/accounts
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"email": "test{{$randomInt}}@test.com",
|
||||
"phone": "+79998887766",
|
||||
"companyName": "test5",
|
||||
"password": "test",
|
||||
"ref": "{{partnerRef}}",
|
||||
"promoCode": "some-promo-code",
|
||||
"rmsCode": "demo"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.global.set("loginLink", response.body.loginLink);
|
||||
client.global.set("subdomain", response.body.subdomain);
|
||||
%}
|
||||
93
backend/artifacts/automation/activity-automation.http
Normal file
93
backend/artifacts/automation/activity-automation.http
Normal file
@@ -0,0 +1,93 @@
|
||||
### Create automation with activity action
|
||||
|
||||
POST {{url}}/api/automation/automations
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"trigger": {
|
||||
"type": "move_or_create_entity",
|
||||
"settings": null
|
||||
},
|
||||
"action": {
|
||||
"type": "create_activity",
|
||||
"delay": 300,
|
||||
"settings": {
|
||||
"responsibleUserType": "custom",
|
||||
"responsibleUserId": {{userId}},
|
||||
"activityTypeId": {{activityTypeId}},
|
||||
"text": "some-text",
|
||||
"deadlineType": "immediately",
|
||||
"deadlineTime": null
|
||||
}
|
||||
},
|
||||
"stageIds": [
|
||||
{{stageId}}
|
||||
],
|
||||
"conditions": [
|
||||
{
|
||||
"type": "responsible_user",
|
||||
"settings": {
|
||||
"userIds": [{{userId}}]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"settings": {
|
||||
"fieldId": {{budgetFieldId}},
|
||||
"fieldType": "value",
|
||||
"payload": {
|
||||
"from": 100,
|
||||
"to": 200
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### Update automation with activity action
|
||||
|
||||
PUT {{url}}/api/automation/automations/{{activityAutomationId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"trigger": {
|
||||
"type": "move_or_create_entity",
|
||||
"settings": null
|
||||
},
|
||||
"action": {
|
||||
"type": "create_activity",
|
||||
"delay": 300,
|
||||
"settings": {
|
||||
"responsibleUserType": "custom",
|
||||
"responsibleUserId": {{userId}},
|
||||
"activityTypeId": {{activityTypeId}},
|
||||
"text": "test",
|
||||
"deadlineType": "immediately",
|
||||
"deadlineTime": null
|
||||
}
|
||||
},
|
||||
"stageIds": [
|
||||
{{stageId}}
|
||||
],
|
||||
"conditions": [
|
||||
{
|
||||
"type": "responsible_user",
|
||||
"settings": {
|
||||
"userIds": [{{userId}}]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "field",
|
||||
"settings": {
|
||||
"fieldId": {{budgetFieldId}},
|
||||
"fieldType": "value",
|
||||
"payload": {
|
||||
"from": 100,
|
||||
"to": 200
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
11
backend/artifacts/automation/automation.http
Normal file
11
backend/artifacts/automation/automation.http
Normal file
@@ -0,0 +1,11 @@
|
||||
### Get automations
|
||||
|
||||
GET {{url}}/api/automation/board/{{boardId}}/automations
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Delete automation
|
||||
|
||||
DELETE {{url}}/api/automation/automations/51011020
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
47
backend/artifacts/automation/change-stage-automation.http
Normal file
47
backend/artifacts/automation/change-stage-automation.http
Normal file
@@ -0,0 +1,47 @@
|
||||
### Create automation with task action
|
||||
|
||||
POST {{url}}/api/automation/automations
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"trigger": {
|
||||
"type": "move_or_create_entity",
|
||||
"settings": null
|
||||
},
|
||||
"action": {
|
||||
"type": "change_stage",
|
||||
"delay": null,
|
||||
"settings": {
|
||||
"stageId": {{stageId}}
|
||||
}
|
||||
},
|
||||
"stageIds": [
|
||||
{{stageId}}
|
||||
],
|
||||
"conditions": []
|
||||
}
|
||||
|
||||
### Update automation with task action
|
||||
|
||||
PUT {{url}}/api/automation/automations/{{changeStageAutomationId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"trigger": {
|
||||
"type": "move_or_create_entity",
|
||||
"settings": null
|
||||
},
|
||||
"action": {
|
||||
"type": "change_stage",
|
||||
"delay": 300,
|
||||
"settings": {
|
||||
"stageId": {{stageId}}
|
||||
}
|
||||
},
|
||||
"stageIds": [
|
||||
{{stageId}}
|
||||
],
|
||||
"conditions": []
|
||||
}
|
||||
63
backend/artifacts/automation/email-automation.http
Normal file
63
backend/artifacts/automation/email-automation.http
Normal file
@@ -0,0 +1,63 @@
|
||||
### Create automation with email action
|
||||
|
||||
POST {{url}}/api/automation/automations
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"trigger": {
|
||||
"type": "move_or_create_entity",
|
||||
"settings": null
|
||||
},
|
||||
"action": {
|
||||
"type": "send_email",
|
||||
"delay": null,
|
||||
"settings": {
|
||||
"subject": "email subject",
|
||||
"content": "email body",
|
||||
"signature": "some signature",
|
||||
"sendAsHtml": false,
|
||||
"mailboxId": 27023020,
|
||||
"userId": {{userId}},
|
||||
"fileIds": []
|
||||
}
|
||||
},
|
||||
"stageIds": [
|
||||
{{stageId}}
|
||||
],
|
||||
"conditions": [],
|
||||
"isActive": true,
|
||||
"applyTrigger": false
|
||||
}
|
||||
|
||||
### Update automation with email action
|
||||
|
||||
PUT {{url}}/api/automation/automations/{{emailAutomationId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"trigger": {
|
||||
"type": "move_or_create_entity",
|
||||
"settings": null
|
||||
},
|
||||
"action": {
|
||||
"type": "send_email",
|
||||
"delay": null,
|
||||
"settings": {
|
||||
"subject": "email subject",
|
||||
"content": "email body",
|
||||
"signature": "new signature",
|
||||
"sendAsHtml": false,
|
||||
"mailboxId": 27023020,
|
||||
"userId": {{userId}},
|
||||
"fileIds": []
|
||||
}
|
||||
},
|
||||
"stageIds": [
|
||||
{{stageId}}
|
||||
],
|
||||
"conditions": [],
|
||||
"isActive": true,
|
||||
"applyTrigger": false
|
||||
}
|
||||
57
backend/artifacts/automation/task-automation.http
Normal file
57
backend/artifacts/automation/task-automation.http
Normal file
@@ -0,0 +1,57 @@
|
||||
### Create automation with task action
|
||||
|
||||
POST {{url}}/api/automation/automations
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"trigger": {
|
||||
"type": "move_or_create_entity",
|
||||
"settings": null
|
||||
},
|
||||
"action": {
|
||||
"type": "create_task",
|
||||
"delay": 300,
|
||||
"settings": {
|
||||
"responsibleUserType": "custom",
|
||||
"responsibleUserId": {{userId}},
|
||||
"title": "some-title",
|
||||
"text": "some-text",
|
||||
"deadlineType": "immediately",
|
||||
"deadlineTime": null
|
||||
}
|
||||
},
|
||||
"stageIds": [
|
||||
{{stageId}}
|
||||
],
|
||||
"conditions": []
|
||||
}
|
||||
|
||||
### Update automation with task action
|
||||
|
||||
PUT {{url}}/api/automation/automations/{{taskAutomationId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"trigger": {
|
||||
"type": "move_entity",
|
||||
"settings": null
|
||||
},
|
||||
"action": {
|
||||
"type": "create_task",
|
||||
"delay": 3000,
|
||||
"settings": {
|
||||
"responsibleUserType": "custom",
|
||||
"responsibleUserId": {{userId}},
|
||||
"title": "new-title",
|
||||
"text": "new-text",
|
||||
"deadlineType": "custom",
|
||||
"deadlineTime": 3000
|
||||
}
|
||||
},
|
||||
"stageIds": [
|
||||
{{stageId}}
|
||||
],
|
||||
"conditions": []
|
||||
}
|
||||
35
backend/artifacts/board.http
Normal file
35
backend/artifacts/board.http
Normal file
@@ -0,0 +1,35 @@
|
||||
### Get boards
|
||||
|
||||
GET {{url}}/api/crm/boards
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create board
|
||||
|
||||
POST {{url}}/api/crm/boards
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "Board name",
|
||||
"sortOrder": 1,
|
||||
"type": "entity_type",
|
||||
"recordId": {{entityTypeId}}
|
||||
}
|
||||
|
||||
### Update board
|
||||
|
||||
PUT {{url}}/api/crm/boards/{{boardId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "Board name",
|
||||
"sortOrder": 1
|
||||
}
|
||||
|
||||
### Delete board
|
||||
|
||||
DELETE {{url}}/api/crm/boards/321
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
72
backend/artifacts/constructor.http
Normal file
72
backend/artifacts/constructor.http
Normal file
@@ -0,0 +1,72 @@
|
||||
### Create entity type
|
||||
|
||||
POST {{url}}/api/crm/constructor/create-entity-type
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "Object",
|
||||
"entityCategory": "universal",
|
||||
"fieldGroups": [
|
||||
{
|
||||
"id": {{fieldGroupId}},
|
||||
"name": "Details",
|
||||
"sortOrder": 0,
|
||||
"state": "created"
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"id": 4201,
|
||||
"name": "Field name",
|
||||
"type": "text",
|
||||
"sortOrder": 1,
|
||||
"fieldGroupId": {{fieldGroupId}},
|
||||
"state": "created"
|
||||
},
|
||||
{
|
||||
"id": 4202,
|
||||
"name": "Field name",
|
||||
"type": "select",
|
||||
"sortOrder": 1,
|
||||
"fieldGroupId": {{fieldGroupId}},
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"label": "Option 1",
|
||||
"sortOrder": 0,
|
||||
"state": "created"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"label": "Option 2",
|
||||
"sortOrder": 1,
|
||||
"state": "created"
|
||||
}
|
||||
],
|
||||
"state": "created"
|
||||
}
|
||||
],
|
||||
"featureIds": [1, 2, 3],
|
||||
"taskSettingsActiveFields": ["planned_time", "board_name", "start_date", "end_date", "description", "subtasks"],
|
||||
"linkedEntityTypes": [
|
||||
{
|
||||
"sortOrder": 0,
|
||||
"targetEntityTypeId": "{{entityTypeId}}"
|
||||
}
|
||||
],
|
||||
"linkedEntityCategories": [{
|
||||
"entityCategory": "contact",
|
||||
"entityTypeName": "Partner contact",
|
||||
"sectionName": "Partner contacts"
|
||||
}, {
|
||||
"entityCategory": "company",
|
||||
"entityTypeName": "Partner company",
|
||||
"sectionName": "Partner companies"
|
||||
}],
|
||||
"section": {
|
||||
"name": "Objects",
|
||||
"view": "board",
|
||||
"icon": "crown"
|
||||
}
|
||||
}
|
||||
10
backend/artifacts/crm.http
Normal file
10
backend/artifacts/crm.http
Normal file
@@ -0,0 +1,10 @@
|
||||
### Delete user and change responsible
|
||||
|
||||
DELETE {{url}}/api/crm/user/delete
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"currentUserId": 12022001,
|
||||
"newUserId": 12022002
|
||||
}
|
||||
5
backend/artifacts/demo.http
Normal file
5
backend/artifacts/demo.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Create demo massive data
|
||||
|
||||
POST {{url}}/api/crm/demo-massive-data
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
76
backend/artifacts/entity-type.http
Normal file
76
backend/artifacts/entity-type.http
Normal file
@@ -0,0 +1,76 @@
|
||||
### Get entity type
|
||||
|
||||
GET {{url}}/api/crm/entity-types/{{entityTypeId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get entity types
|
||||
GET {{url}}/api/crm/entity-types
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Delete entity type
|
||||
|
||||
DELETE {{url}}/api/crm/entity-types/321
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Update entity type
|
||||
|
||||
PUT {{url}}/api/crm/entity-types/{{entityTypeId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": {{entityTypeId}},
|
||||
"name": "Deal",
|
||||
"cardView": "fields_and_notes",
|
||||
"fieldGroups": [
|
||||
{
|
||||
"id": {{fieldGroupId}},
|
||||
"name": "Details",
|
||||
"sortOrder": 0,
|
||||
"state": "created"
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"id": 4201,
|
||||
"name": "Field name",
|
||||
"type": "text",
|
||||
"sortOrder": 1,
|
||||
"fieldGroupId": {{fieldGroupId}},
|
||||
"state": "updated"
|
||||
},
|
||||
{
|
||||
"id": 4202,
|
||||
"name": "Field name",
|
||||
"type": "select",
|
||||
"sortOrder": 1,
|
||||
"fieldGroupId": {{fieldGroupId}},
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"label": "Option 1",
|
||||
"sortOrder": 0,
|
||||
"state": "created"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"label": "Option 2",
|
||||
"sortOrder": 1,
|
||||
"state": "created"
|
||||
}
|
||||
],
|
||||
"state": "created"
|
||||
}
|
||||
],
|
||||
"featureIds": [1, 2, 3],
|
||||
"taskSettingsActiveFields": ["planned_time", "board_name", "start_date", "end_date", "description", "subtasks"],
|
||||
"linkedEntityTypes": [],
|
||||
"section": {
|
||||
"name": "Deals",
|
||||
"view": "board",
|
||||
"icon": "crown"
|
||||
}
|
||||
}
|
||||
108
backend/artifacts/entity.http
Normal file
108
backend/artifacts/entity.http
Normal file
@@ -0,0 +1,108 @@
|
||||
### Get entity
|
||||
|
||||
GET {{url}}/api/crm/entities/{{entityId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create entity
|
||||
|
||||
POST {{url}}/api/crm/entities
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": {{$randomInt}},
|
||||
"name": "Tesla",
|
||||
"responsibleUserId": {{userId}},
|
||||
"entityTypeId": {{entityTypeId}},
|
||||
"stageId": {{stageId}},
|
||||
"fieldValues": [
|
||||
{
|
||||
"id": {{$randomInt}},
|
||||
"fieldId": {{budgetFieldId}},
|
||||
"fieldType": "number",
|
||||
"payload": {
|
||||
"value": 100000
|
||||
},
|
||||
"state": "created"
|
||||
}
|
||||
],
|
||||
"entityLinks": [
|
||||
{
|
||||
"id": {{$randomInt}},
|
||||
"sourceId": {{entityId}},
|
||||
"targetId": {{elonContactEntityId}},
|
||||
"sortOrder": 0,
|
||||
"state": "created"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### Update entity
|
||||
|
||||
PUT {{url}}/api/crm/entities/{{entityId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": {{entityId}},
|
||||
"name": "Tesla",
|
||||
"responsibleUserId": {{userId}},
|
||||
"entityTypeId": {{entityTypeId}},
|
||||
"stageId": {{stageId}},
|
||||
"fieldValues": [
|
||||
{
|
||||
"fieldId": {{budgetFieldId}},
|
||||
"fieldType": "number",
|
||||
"payload": {
|
||||
"value": 10000
|
||||
},
|
||||
"state": "updated"
|
||||
}
|
||||
],
|
||||
"entityLinks": [
|
||||
{
|
||||
"id": {{$randomInt}},
|
||||
"sourceId": {{entityId}},
|
||||
"targetId": {{elonContactEntityId}},
|
||||
"sortOrder": 0,
|
||||
"state": "created"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### Update entity stage
|
||||
|
||||
PUT {{url}}/api/crm/entities/{{entityId}}/stage/{{stageId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Delete entity
|
||||
|
||||
DELETE {{url}}/api/crm/entities/321
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get entities for board
|
||||
|
||||
GET {{url}}/api/crm/entities/{{entityTypeId}}/{{boardId}}/cards
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get entities list items
|
||||
|
||||
GET {{url}}/api/crm/entities/{{entityTypeId}}/list-items
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Search entities in name, all fields and linked entities
|
||||
|
||||
GET {{url}}/api/crm/entities/{{entityTypeId}}/search?value=book
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Search entities by name or field value
|
||||
|
||||
GET {{url}}/api/crm/entities/{{entityTypeId}}/search/fields?name=book&field[42022001]=4&field[42022003]=com
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
15
backend/artifacts/extension.http
Normal file
15
backend/artifacts/extension.http
Normal file
@@ -0,0 +1,15 @@
|
||||
### Create external link
|
||||
|
||||
POST {{url}}/api/extension/external-link
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"url": "https://salesforce.com",
|
||||
"name": "Tesla",
|
||||
"responsibleUserId": {{userId}},
|
||||
"entityTypeId": {{entityTypeId}},
|
||||
"stageId": {{stageId}},
|
||||
"fieldValues": [],
|
||||
"entityLinks": []
|
||||
}
|
||||
5
backend/artifacts/feed-items.http
Normal file
5
backend/artifacts/feed-items.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Get feed items for entity with paging
|
||||
|
||||
GET {{url}}/api/crm/feed-items?entityId={{entityId}}&offset=0&limit=10
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
17
backend/artifacts/feedback.http
Normal file
17
backend/artifacts/feedback.http
Normal file
@@ -0,0 +1,17 @@
|
||||
### Send feedback
|
||||
|
||||
POST {{url}}/api/mailing/feedback
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"type": "trial_expired",
|
||||
"payload": {
|
||||
"name": "John Dow",
|
||||
"phone": "+1234567890",
|
||||
"email": "john.dow@company.com",
|
||||
"userNumber": 10,
|
||||
"subscribe": "yearly",
|
||||
"plan": "basic"
|
||||
}
|
||||
}
|
||||
18
backend/artifacts/field-settings.http
Normal file
18
backend/artifacts/field-settings.http
Normal file
@@ -0,0 +1,18 @@
|
||||
### Get fields settings
|
||||
|
||||
GET {{url}}/api/crm/entity-types/13022735/fields-settings
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Update fields settings
|
||||
|
||||
PUT {{url}}/api/crm/entity-types/13022735/fields-settings
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"activeFieldCodes": [
|
||||
"participants",
|
||||
"description"
|
||||
]
|
||||
}
|
||||
14
backend/artifacts/field-value.http
Normal file
14
backend/artifacts/field-value.http
Normal file
@@ -0,0 +1,14 @@
|
||||
### Save field value
|
||||
|
||||
POST {{url}}/api/crm/entities/{{entityId}}/field-values/{{budgetFieldId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"fieldId": {{budgetFieldId}},
|
||||
"fieldType": "value",
|
||||
"payload": {
|
||||
"value": 500
|
||||
},
|
||||
"state": "updated"
|
||||
}
|
||||
48
backend/artifacts/fields.http
Normal file
48
backend/artifacts/fields.http
Normal file
@@ -0,0 +1,48 @@
|
||||
### Update entity type fields and groups
|
||||
|
||||
PUT {{url}}/api/crm/entity-types/{{entityTypeId}}/fields-and-groups
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"fieldGroups": [
|
||||
{
|
||||
"id": {{fieldGroupId}},
|
||||
"name": "Details",
|
||||
"sortOrder": 0,
|
||||
"state": "created"
|
||||
}
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"id": 4201,
|
||||
"name": "Field name",
|
||||
"type": "text",
|
||||
"sortOrder": 1,
|
||||
"fieldGroupId": {{fieldGroupId}},
|
||||
"state": "updated"
|
||||
},
|
||||
{
|
||||
"id": 4202,
|
||||
"name": "Field name",
|
||||
"type": "select",
|
||||
"sortOrder": 1,
|
||||
"fieldGroupId": {{fieldGroupId}},
|
||||
"options": [
|
||||
{
|
||||
"id": 1,
|
||||
"label": "Option 1",
|
||||
"sortOrder": 0,
|
||||
"state": "created"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"label": "Option 2",
|
||||
"sortOrder": 1,
|
||||
"state": "created"
|
||||
}
|
||||
],
|
||||
"state": "created"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
backend/artifacts/file-link.http
Normal file
5
backend/artifacts/file-link.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Delete file
|
||||
|
||||
DELETE {{url}}/api/crm/file-link/1
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
31
backend/artifacts/forms.http
Normal file
31
backend/artifacts/forms.http
Normal file
@@ -0,0 +1,31 @@
|
||||
### Send contact us form
|
||||
|
||||
POST {{url}}/api/forms/contact-us
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "test 10",
|
||||
"phone": "+7999888776633",
|
||||
"email": "test@test.com",
|
||||
"comment": "some comment"
|
||||
}
|
||||
|
||||
### Send partner form
|
||||
|
||||
POST {{url}}/api/forms/partner
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"phone": "+7999888776633",
|
||||
"email": "test@test.com",
|
||||
"company": "Tesla",
|
||||
"country": "USA",
|
||||
"website": "tesla.com",
|
||||
"employees": "10000",
|
||||
"comment": "some comment"
|
||||
}
|
||||
|
||||
17
backend/artifacts/identity.http
Normal file
17
backend/artifacts/identity.http
Normal file
@@ -0,0 +1,17 @@
|
||||
### Get next identity for sequence
|
||||
|
||||
GET {{url}}/api/crm/identity/board_id_seq
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get all identities pool
|
||||
|
||||
GET {{url}}/api/crm/identities/all
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get identities pool
|
||||
|
||||
GET {{url}}/api/crm/identities/feed_item_id_seq
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
5
backend/artifacts/import.http
Normal file
5
backend/artifacts/import.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Get import template for entityType
|
||||
|
||||
GET {{url}}/api/crm/entity-types/{{entityTypeId}}/template
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
30
backend/artifacts/mail-messages.http
Normal file
30
backend/artifacts/mail-messages.http
Normal file
@@ -0,0 +1,30 @@
|
||||
### Get mails for mailbox
|
||||
|
||||
GET {{url}}/api/mailing/mailboxes/{{mailboxId}}/messages?folderId={{folderId}}&offset=0&limit=50
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get mails for section
|
||||
|
||||
GET {{url}}/api/mailing/section/inbox/messages?mailboxId={{mailboxId}}&offset=0&limit=50
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get mail thread
|
||||
|
||||
GET {{url}}/api/mailing/mailboxes/{{mailboxId}}/threads/1234567890
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get mail message
|
||||
|
||||
GET {{url}}/api/mailing/mailboxes/{{mailboxId}}/messages/{{messageId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get mail attachment
|
||||
|
||||
GET {{url}}'/api/mailing/mailboxes/{{mailboxId}}/messages/{{messageId}}/attachments/{{payloadId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
76
backend/artifacts/mailbox-settings.http
Normal file
76
backend/artifacts/mailbox-settings.http
Normal file
@@ -0,0 +1,76 @@
|
||||
### Create mailbox
|
||||
|
||||
POST {{url}}/api/mailing/settings/mailboxes
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"email": "test@company.com"
|
||||
}
|
||||
|
||||
|
||||
### Update mailbox
|
||||
|
||||
PUT {{url}}/api/mailing/settings/mailboxes/{{mailboxId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"email": "test2@company.com",
|
||||
"ownerId": {{userid}},
|
||||
"accessibleUserIds": [{{userid}}],
|
||||
"createContact": true,
|
||||
"syncDays": 7
|
||||
}
|
||||
|
||||
### Delete mailbox
|
||||
|
||||
DELETE {{url}}/api/mailing/settings/mailboxes/{{mailboxId}}?save=true
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get mailboxes for settings
|
||||
|
||||
GET {{url}}/api/mailing/settings/mailboxes
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get mailbox for settings
|
||||
|
||||
GET {{url}}/api/mailing/settings/mailboxes/{{mailboxId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get mailbox manual settings
|
||||
|
||||
GET {{url}}/api/mailing/settings/mailboxes/{{mailboxId}}/manual
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Update mailbox manual settings
|
||||
|
||||
POST {{url}}/api/mailing/settings/mailboxes/{{mailboxId}}/manual
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"password": "12345678",
|
||||
"imapServer": "imap.company.com",
|
||||
"imapPort": 993,
|
||||
"imapSecure": true,
|
||||
"smtpServer": "smtp.company.com",
|
||||
"smtpPort": 465,
|
||||
"smtpSecure": true
|
||||
}
|
||||
|
||||
### Get Gmail connection string for redirect
|
||||
|
||||
GET {{url}}/api/mailing/settings/mailboxes/gmail/connect/{{mailboxId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Gmail callback endpoint
|
||||
|
||||
GET {{url}}/api/mailing/settings/mailboxes/gmail/callback?state={{mailboxId}}&code=1234567890
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
5
backend/artifacts/mailbox.http
Normal file
5
backend/artifacts/mailbox.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Get mailboxes
|
||||
|
||||
GET {{url}}/api/mailing/mailboxes
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
5
backend/artifacts/migration.http
Normal file
5
backend/artifacts/migration.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Run migration
|
||||
|
||||
POST {{url}}/api/crm/run-migration
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
17
backend/artifacts/module/module.http
Normal file
17
backend/artifacts/module/module.http
Normal file
@@ -0,0 +1,17 @@
|
||||
### Get modules
|
||||
|
||||
GET {{url}}/api/crm/modules
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Activate module
|
||||
|
||||
POST {{url}}/api/crm/modules/{{moduleId}}/activate
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Deactivate module
|
||||
|
||||
POST {{url}}/api/crm/modules/{{moduleId}}/deactivate
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
27
backend/artifacts/note.http
Normal file
27
backend/artifacts/note.http
Normal file
@@ -0,0 +1,27 @@
|
||||
### Create note
|
||||
|
||||
POST {{url}}/api/crm/notes
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"entityId": {{entityId}},
|
||||
"text": "Hello world!!!"
|
||||
}
|
||||
|
||||
### Update note
|
||||
|
||||
PUT {{url}}/api/crm/notes/{{noteId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"entityId": {{entityId}},
|
||||
"text": "Updated note"
|
||||
}
|
||||
|
||||
### Delete note
|
||||
|
||||
DELETE {{url}}/api/crm/notes/321
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
23
backend/artifacts/notification.http
Normal file
23
backend/artifacts/notification.http
Normal file
@@ -0,0 +1,23 @@
|
||||
### Get notifications
|
||||
|
||||
GET {{url}}/api/notifications
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get unseen count
|
||||
|
||||
GET {{url}}/api/notifications/unseen-count
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Mark seen all
|
||||
|
||||
PUT {{url}}/api/notifications/seen
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Mark seen notification
|
||||
|
||||
PUT {{url}}/api/notifications/{{notificationId}}/seen
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
11
backend/artifacts/partner.http
Normal file
11
backend/artifacts/partner.http
Normal file
@@ -0,0 +1,11 @@
|
||||
### Get partner summary
|
||||
|
||||
GET {{url}}/api/partners/{{partnerId}}/summary
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get partner leads
|
||||
|
||||
GET {{url}}/api/partners/{{partnerId}}/leads
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
5
backend/artifacts/products/order-status.http
Normal file
5
backend/artifacts/products/order-status.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Get order statuses
|
||||
|
||||
GET {{url}}/api/products/order-statuses
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
92
backend/artifacts/products/order.http
Normal file
92
backend/artifacts/products/order.http
Normal file
@@ -0,0 +1,92 @@
|
||||
### Get entity order
|
||||
|
||||
GET {{url}}/api/products/orders/entity/{{entityId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get entity order products count
|
||||
|
||||
GET {{url}}/api/products/orders/entity/{{entityId}}/products-count
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create order
|
||||
|
||||
POST {{url}}/api/products/orders
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"entityId": {{entityId}},
|
||||
"currency": "USD",
|
||||
"taxIncluded": true,
|
||||
"statusId": {{orderStatusId}},
|
||||
"warehouseId": {{warehouseId}},
|
||||
"items": [
|
||||
{
|
||||
"productId": {{productId}},
|
||||
"quantity": 5,
|
||||
"unitPrice": 100,
|
||||
"tax": 10,
|
||||
"discount": 0,
|
||||
"sortOrder": 0,
|
||||
"reservations": [
|
||||
{
|
||||
"warehouseId": {{warehouseId}},
|
||||
"quantity": 5
|
||||
},
|
||||
{
|
||||
"warehouseId": {{secondWarehouseId}},
|
||||
"quantity": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### Update order
|
||||
|
||||
PUT {{url}}/api/products/orders/{{orderId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"entityId": {{entityId}},
|
||||
"currency": "USD",
|
||||
"taxIncluded": true,
|
||||
"statusId": {{orderStatusId}},
|
||||
"warehouseId": {{secondWarehouseId}},
|
||||
"items": [
|
||||
{
|
||||
"id": 14,
|
||||
"productId": {{productId}},
|
||||
"quantity": 10,
|
||||
"unitPrice": 200,
|
||||
"tax": 10,
|
||||
"discount": 30,
|
||||
"sortOrder": 2,
|
||||
"reservations": [
|
||||
{
|
||||
"warehouseId": {{warehouseId}},
|
||||
"quantity": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": -1,
|
||||
"productId": {{productId}},
|
||||
"quantity": 20,
|
||||
"unitPrice": 100,
|
||||
"tax": 20,
|
||||
"discount": 30,
|
||||
"sortOrder": 3,
|
||||
"reservations": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### Change order status
|
||||
|
||||
PUT {{url}}/api/products/orders/{{orderId}}/status/{{orderStatusId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
32
backend/artifacts/products/product-category.http
Normal file
32
backend/artifacts/products/product-category.http
Normal file
@@ -0,0 +1,32 @@
|
||||
### Get categories
|
||||
|
||||
GET {{url}}/api/products/categories
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create category
|
||||
|
||||
POST {{url}}/api/products/categories
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "Category 1",
|
||||
"parentId": null
|
||||
}
|
||||
|
||||
### Update category
|
||||
|
||||
PUT {{url}}/api/products/categories/{{productCategoryId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "Category new name"
|
||||
}
|
||||
|
||||
### Delete category
|
||||
|
||||
DELETE {{url}}/api/products/categories/123
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
29
backend/artifacts/products/product-price.http
Normal file
29
backend/artifacts/products/product-price.http
Normal file
@@ -0,0 +1,29 @@
|
||||
### Create product price
|
||||
|
||||
POST {{url}}/api/products/{{productId}}/prices
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": null,
|
||||
"unitPrice": 100,
|
||||
"currency": "EUR"
|
||||
}
|
||||
|
||||
### Update product price
|
||||
|
||||
PUT {{url}}/api/products/{{productId}}/prices/{{productPriceId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "Updated price",
|
||||
"unitPrice": 200,
|
||||
"currency": "USD"
|
||||
}
|
||||
|
||||
### Delete product price
|
||||
|
||||
DELETE {{url}}/api/products/{{productId}}/prices/67
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
86
backend/artifacts/products/product.http
Normal file
86
backend/artifacts/products/product.http
Normal file
@@ -0,0 +1,86 @@
|
||||
### Get products
|
||||
|
||||
GET {{url}}/api/products?categoryId={{productCategoryId}}&search=some&offset=0&limit=10
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get products by ids
|
||||
|
||||
GET {{url}}/api/products?ids=1,2,3
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get product
|
||||
|
||||
GET {{url}}/api/products/{{productId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create product
|
||||
|
||||
POST {{url}}/api/products
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "Some product",
|
||||
"type": "service",
|
||||
"description": "Some description",
|
||||
"sku": "some-product",
|
||||
"unit": "some-unit",
|
||||
"tax": 10,
|
||||
"categoryId": {{productCategoryId}},
|
||||
"prices": [
|
||||
{
|
||||
"name": "Price in USD",
|
||||
"unitPrice": 100,
|
||||
"currency": "USD"
|
||||
},
|
||||
{
|
||||
"name": "Price in KZT",
|
||||
"unitPrice": 200,
|
||||
"currency": "KZT"
|
||||
}
|
||||
],
|
||||
"photoFileIds": ["c7d48430-a2b7-4ea5-96a2-58bc40d90574"],
|
||||
"stocks": [
|
||||
{
|
||||
"warehouseId": {{warehouseId}},
|
||||
"stockQuantity": 100
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
### Update product
|
||||
|
||||
PUT {{url}}/api/products/{{productId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "New product name",
|
||||
"description": "New description",
|
||||
"sku": "new-product",
|
||||
"unit": "new-unit",
|
||||
"tax": 20,
|
||||
"categoryId": {{productCategoryId}}
|
||||
}
|
||||
|
||||
### Delete product
|
||||
|
||||
DELETE {{url}}/api/products/123
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Upload product photos
|
||||
|
||||
POST {{url}}/api/products/{{productId}}/photos
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: multipart/form-data; boundary="abcd"
|
||||
|
||||
--abcd
|
||||
Content-Disposition: form-data; name="test"; filename="test.png"
|
||||
Content-Type: image/png
|
||||
|
||||
< ../_resources/test.png
|
||||
--abcd--
|
||||
5
backend/artifacts/products/shipment-status.http
Normal file
5
backend/artifacts/products/shipment-status.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Get shipment statuses
|
||||
|
||||
GET {{url}}/api/products/shipment-statuses
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
17
backend/artifacts/products/shipment.http
Normal file
17
backend/artifacts/products/shipment.http
Normal file
@@ -0,0 +1,17 @@
|
||||
### Get shipments
|
||||
|
||||
GET {{url}}/api/products/shipments?offset=0&limit=10
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get shipment by id
|
||||
|
||||
GET {{url}}/api/products/shipments/{{shipmentId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Change shipment status
|
||||
|
||||
PUT {{url}}/api/products/shipments/{{shipmentId}}/status/{{shipmentStatusId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
18
backend/artifacts/products/stock.http
Normal file
18
backend/artifacts/products/stock.http
Normal file
@@ -0,0 +1,18 @@
|
||||
### Update product stocks
|
||||
|
||||
PUT {{url}}/api/products/{{productId}}/stocks
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"stocks": [
|
||||
{
|
||||
"warehouseId": {{warehouseId}},
|
||||
"stockQuantity": 100
|
||||
},
|
||||
{
|
||||
"warehouseId": {{secondWarehouseId}},
|
||||
"stockQuantity": 200
|
||||
}
|
||||
]
|
||||
}
|
||||
31
backend/artifacts/products/warehouse.http
Normal file
31
backend/artifacts/products/warehouse.http
Normal file
@@ -0,0 +1,31 @@
|
||||
### Get warehouses
|
||||
|
||||
GET {{url}}/api/products/warehouses
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create warehouse
|
||||
|
||||
POST {{url}}/api/products/warehouses
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "Some warehouse"
|
||||
}
|
||||
|
||||
### Update warehouse
|
||||
|
||||
PUT {{url}}/api/products/warehouses/{{warehouseId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "New warehouse name"
|
||||
}
|
||||
|
||||
### Delete warehouse
|
||||
|
||||
DELETE {{url}}/api/products/warehouses/123
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
5
backend/artifacts/rabbit.http
Normal file
5
backend/artifacts/rabbit.http
Normal file
@@ -0,0 +1,5 @@
|
||||
### Send event to rabbit
|
||||
|
||||
POST {{url}}/api/rabbit
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
10
backend/artifacts/rms.http
Normal file
10
backend/artifacts/rms.http
Normal file
@@ -0,0 +1,10 @@
|
||||
### Get industries
|
||||
|
||||
GET {{url}}/api/crm/rms/industries
|
||||
Content-Type: application/json
|
||||
|
||||
### Delete demo data
|
||||
|
||||
DELETE {{url}}/api/crm/rms/demo-data
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
47
backend/artifacts/stage.http
Normal file
47
backend/artifacts/stage.http
Normal file
@@ -0,0 +1,47 @@
|
||||
### Get all stages or by boardId
|
||||
|
||||
GET {{url}}/api/crm/stages
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Save stages batch
|
||||
|
||||
POST {{url}}/api/crm/stages/batch
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"stages": [
|
||||
{
|
||||
"id": "172",
|
||||
"name": "Stage 1",
|
||||
"color": "#fff",
|
||||
"code": null,
|
||||
"isSystem": false,
|
||||
"sortOrder": 1,
|
||||
"boardId": {{boardId}},
|
||||
"state": "unchanged"
|
||||
},
|
||||
{
|
||||
"id": "298",
|
||||
"name": "Stage 2",
|
||||
"color": "#fff",
|
||||
"code": null,
|
||||
"isSystem": false,
|
||||
"sortOrder": 2,
|
||||
"boardId": {{boardId}},
|
||||
"state": "updated"
|
||||
},
|
||||
{
|
||||
"id": "{{$randomInt}}",
|
||||
"name": "Stage 4",
|
||||
"color": "#fff",
|
||||
"code": null,
|
||||
"isSystem": false,
|
||||
"sortOrder": 1,
|
||||
"boardId": {{boardId}},
|
||||
"state": "added"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
12
backend/artifacts/storage/file-link.http
Normal file
12
backend/artifacts/storage/file-link.http
Normal file
@@ -0,0 +1,12 @@
|
||||
### Delete file link by id
|
||||
|
||||
DELETE {{url}}/api/crm/file-links/123
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Delete file links by ids
|
||||
|
||||
DELETE {{url}}/api/crm/file-links?ids=72,73
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
24
backend/artifacts/storage/file.http
Normal file
24
backend/artifacts/storage/file.http
Normal file
@@ -0,0 +1,24 @@
|
||||
### Upload file
|
||||
|
||||
POST {{url}}/api/storage/upload
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: multipart/form-data; boundary="abcd"
|
||||
|
||||
--abcd
|
||||
Content-Disposition: form-data; name="test"; filename="test.png"
|
||||
Content-Type: image/png
|
||||
|
||||
< ../_resources/test.png
|
||||
--abcd--
|
||||
|
||||
### Delete file
|
||||
|
||||
DELETE {{url}}/api/storage/file/{{fileId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get file
|
||||
|
||||
GET {{url}}/api/storage/file/{{fileId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
27
backend/artifacts/subtasks.http
Normal file
27
backend/artifacts/subtasks.http
Normal file
@@ -0,0 +1,27 @@
|
||||
### Create subtask
|
||||
|
||||
POST {{url}}/api/crm/tasks/{{taskId}}/subtasks
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"text": "new subtask",
|
||||
"resolved": false
|
||||
}
|
||||
|
||||
### Update subtask
|
||||
|
||||
PUT {{url}}/api/crm/tasks/{{taskId}}/subtasks/{{subtaskId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"text": "updated subtask",
|
||||
"resolved": false
|
||||
}
|
||||
|
||||
### Delete subtask
|
||||
|
||||
DELETE {{url}}/api/crm/tasks/{{taskId}}/subtasks/46022010
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
11
backend/artifacts/task-comment-like.http
Normal file
11
backend/artifacts/task-comment-like.http
Normal file
@@ -0,0 +1,11 @@
|
||||
### Like task comment
|
||||
|
||||
POST {{url}}/api/crm/tasks/{{taskId}}/comments/{{taskCommentId}}/like
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Unlike task comment
|
||||
|
||||
POST {{url}}/api/crm/tasks/{{taskId}}/comments/{{taskCommentId}}/unlike
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
33
backend/artifacts/task-comment.http
Normal file
33
backend/artifacts/task-comment.http
Normal file
@@ -0,0 +1,33 @@
|
||||
### Get task comments
|
||||
|
||||
GET {{url}}/api/crm/tasks/{{taskId}}/comments?offset=0&limit=10
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create task comment
|
||||
|
||||
POST {{url}}/api/crm/tasks/{{taskId}}/comments
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"text": "Hello world!!!",
|
||||
"fileIds": []
|
||||
}
|
||||
|
||||
### Update task comment
|
||||
|
||||
PUT {{url}}/api/crm/tasks/{{taskId}}/comments/{{taskCommentId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"text": "New text"
|
||||
}
|
||||
|
||||
### Delete task comment
|
||||
|
||||
DELETE {{url}}/api/crm/tasks/{{taskId}}/comments/47022018
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
39
backend/artifacts/task-settings.http
Normal file
39
backend/artifacts/task-settings.http
Normal file
@@ -0,0 +1,39 @@
|
||||
### Get task settings
|
||||
|
||||
GET {{url}}/api/crm/task-settings
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create task settings
|
||||
|
||||
POST {{url}}/api/crm/task-settings
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"type": "task_board",
|
||||
"recordId": 123,
|
||||
"activeFields": [
|
||||
"planned_time",
|
||||
"board_name",
|
||||
"start_date",
|
||||
"end_date"
|
||||
]
|
||||
}
|
||||
|
||||
### Update task settings
|
||||
|
||||
PUT {{url}}/api/crm/task-settings/{{taskSettingsId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"activeFields": [
|
||||
"planned_time",
|
||||
"board_name",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"description",
|
||||
"subtasks"
|
||||
]
|
||||
}
|
||||
21
backend/artifacts/task-type.http
Normal file
21
backend/artifacts/task-type.http
Normal file
@@ -0,0 +1,21 @@
|
||||
### Get task types
|
||||
|
||||
GET {{url}}/api/crm/task-types
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create task type
|
||||
|
||||
POST {{url}}/api/crm/task-types
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"name": "Call"
|
||||
}
|
||||
|
||||
### Delete task type
|
||||
|
||||
DELETE {{url}}/api/crm/task-types/321
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
134
backend/artifacts/task.http
Normal file
134
backend/artifacts/task.http
Normal file
@@ -0,0 +1,134 @@
|
||||
### Get task by id
|
||||
|
||||
GET {{url}}/api/crm/tasks/{{taskId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create task
|
||||
|
||||
POST {{url}}/api/crm/tasks
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"responsibleUserId": {{userId}},
|
||||
"startDate": "2022-11-21T17:37:03",
|
||||
"endDate": "2022-11-22T17:37:03",
|
||||
"text": "Task with start and end time",
|
||||
"isResolved": false,
|
||||
"result": null,
|
||||
"entityId": {{entityId}},
|
||||
"title": "Task 1",
|
||||
"plannedTime": 3600,
|
||||
"stageId": {{taskStageId}},
|
||||
"settingsId": {{taskSettingsId}},
|
||||
"subtasks": [
|
||||
{"text": "subtask 1", "resolved": true},
|
||||
{"text": "subtask 2", "resolved": false}
|
||||
]
|
||||
}
|
||||
|
||||
### Update task
|
||||
|
||||
PUT {{url}}/api/crm/tasks/{{taskId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"responsibleUserId": {{userId}},
|
||||
"startDate": "2022-11-23T17:37:03",
|
||||
"endDate": "2022-11-24T17:37:03",
|
||||
"text": "Updated Task 1 with start and end time",
|
||||
"isResolved": true,
|
||||
"result": "Result",
|
||||
"entityId": {{entityId}},
|
||||
"title": "Updated Task 1"
|
||||
}
|
||||
|
||||
### Delete task
|
||||
|
||||
DELETE {{url}}/api/crm/tasks/321
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Create activity
|
||||
|
||||
POST {{url}}/api/crm/activities
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"responsibleUserId": {{userId}},
|
||||
"startDate": "2022-11-21T17:37:03",
|
||||
"endDate": "2022-11-22T17:37:03",
|
||||
"text": "Activity with start and end time",
|
||||
"isResolved": false,
|
||||
"result": null,
|
||||
"entityId": {{entityId}},
|
||||
"activityTypeId": {{activityTypeId}}
|
||||
}
|
||||
|
||||
### Update activity
|
||||
|
||||
PUT {{url}}/api/crm/activities/{{activityId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"responsibleUserId": {{userId}},
|
||||
"startDate": "2022-11-23T17:37:03",
|
||||
"endDate": "2022-11-24T17:37:03",
|
||||
"text": "Updated Activity 1 with start and end time",
|
||||
"isResolved": true,
|
||||
"result": "Result",
|
||||
"entityId": {{entityId}},
|
||||
"activityTypeId": {{activityTypeId}}
|
||||
}
|
||||
|
||||
### Delete activity
|
||||
|
||||
DELETE {{url}}/api/crm/activities/321
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get activities
|
||||
|
||||
GET {{url}}/api/crm/activities/cards?responsibleUserId={{userId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get tasks by time
|
||||
|
||||
POST {{url}}/api/crm/tasks/by_time
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get time board meta
|
||||
|
||||
POST {{url}}/api/crm/tasks/by_time/meta
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"stageIds": [{{taskStageId}}]
|
||||
}
|
||||
|
||||
### Get tasks by board
|
||||
|
||||
POST {{url}}/api/crm/tasks/boards/{{taskBoardId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"ownerIds": [{{userId}}]
|
||||
}
|
||||
|
||||
### Get tasks board meta
|
||||
|
||||
POST {{url}}/api/crm/tasks/boards/{{taskBoardId}}/meta
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"stageIds": [{{taskStageId}}]
|
||||
}
|
||||
73
backend/artifacts/user.http
Normal file
73
backend/artifacts/user.http
Normal file
@@ -0,0 +1,73 @@
|
||||
### Get user by id
|
||||
|
||||
GET {{url}}/api/users/{{userId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
|
||||
### Create user
|
||||
|
||||
POST {{url}}/api/settings/users
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"firstName": "Genadiy",
|
||||
"lastName": "Genadiyev",
|
||||
"email": "genadiy.genadiyev@test1.amwork.com",
|
||||
"password": "123",
|
||||
"phone": "+79998887766",
|
||||
"role": "user"
|
||||
}
|
||||
|
||||
### Update user
|
||||
|
||||
PUT {{url}}/api/settings/users/{{userId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"firstName": "Genadiy!",
|
||||
"lastName": "Genadiyev!",
|
||||
"email": "genadiy.genadiyev@test1.amwork.com",
|
||||
"password": "123",
|
||||
"phone": "+79998887766",
|
||||
"role": "admin"
|
||||
}
|
||||
|
||||
### Delete activity
|
||||
|
||||
DELETE {{url}}/api/settings/users/{{userId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### Get user list
|
||||
|
||||
GET {{url}}/api/settings/users
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
|
||||
### Get user by id
|
||||
|
||||
GET {{url}}/api/settings/users/{{userId}}
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
|
||||
### Update user profile
|
||||
|
||||
PUT {{url}}/api/user/{{userId}}/profile
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"birthDate": "1996-11-25T14:36:45",
|
||||
"phone": "+79998887766"
|
||||
}
|
||||
|
||||
### Get user profile by user id
|
||||
|
||||
GET {{url}}/api/user/{{userId}}/profile
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
32
backend/doc/camunda.md
Normal file
32
backend/doc/camunda.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# camunda platform
|
||||
|
||||
## configuration
|
||||
|
||||
github: https://github.com/camunda/camunda-platform
|
||||
vps: **/home/devops/lvluu/camunda-platform/docker-compose/camunda-8.6**
|
||||
|
||||
## start all services
|
||||
|
||||
please note that you HAVE to cd to `/home/devops/lvluu/camunda-platform/docker-compose/camunda-8.6` before executing any command with docker compose:
|
||||
|
||||
```bash
|
||||
docker compose --profile full up -d
|
||||
```
|
||||
|
||||
## stop all services
|
||||
|
||||
```bash
|
||||
docker compose --profile full down -d
|
||||
```
|
||||
|
||||
## restart a container
|
||||
|
||||
you can press tab to auto suggest the [service_name]
|
||||
|
||||
```bash
|
||||
docker compose --profile full restart [service_name]
|
||||
```
|
||||
|
||||
## change version of a service
|
||||
|
||||
edit the `/home/devops/lvluu/camunda-platform/docker-compose/camunda-8.6/.env`
|
||||
11
backend/doc/commands.md
Normal file
11
backend/doc/commands.md
Normal file
@@ -0,0 +1,11 @@
|
||||
### Create migration
|
||||
|
||||
```bash
|
||||
yarn typeorm:create-migration AddAccount
|
||||
```
|
||||
|
||||
### Run migrations
|
||||
|
||||
```bash
|
||||
yarn typeorm:run-migrations
|
||||
```
|
||||
56
backend/doc/setup-local.md
Normal file
56
backend/doc/setup-local.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Setup local development environment
|
||||
|
||||
## Start docker services
|
||||
|
||||
```
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Setup database
|
||||
|
||||
- Add new postgres connection in PHP Storm
|
||||
|
||||
If you have different psql version on your host, you can manually restore dump inside container:
|
||||
- Put dump to `./dumps` directory
|
||||
- Connect to postgres container
|
||||
- Restore database: `psql -h localhost --set ON_ERROR_STOP=on -U root -d rifeberry -1 -f /dumps/rifeberry.sql`
|
||||
|
||||
## Connect to node service and run other commands inside container
|
||||
|
||||
```
|
||||
docker exec -it nest-backend_node_1 sh
|
||||
```
|
||||
|
||||
### Install packages
|
||||
|
||||
```
|
||||
yarn
|
||||
```
|
||||
|
||||
### Generate JWT keys if not exists
|
||||
|
||||
```
|
||||
openssl rsa -pubout -in var/jwt/private.pem -out var/jwt/public.pem
|
||||
```
|
||||
|
||||
### Migrate database
|
||||
|
||||
```
|
||||
yarn typeorm:run-migrations
|
||||
```
|
||||
|
||||
### Add host to /etc/hosts
|
||||
|
||||
```
|
||||
127.0.0.1 test.rifeberry.loc
|
||||
```
|
||||
|
||||
### Setup node debug
|
||||
|
||||
[Настройка node debug](https://olivergrand.atlassian.net/wiki/spaces/BACK/pages/14319617/Node+debug)
|
||||
|
||||
### Send test request to test.rifeberry.loc/api
|
||||
|
||||
### Optional: Setup wildcard subdomains using dnsmasq
|
||||
|
||||
https://askubuntu.com/questions/1029882/how-can-i-set-up-local-wildcard-127-0-0-1-domain-resolution-on-18-04-20-04
|
||||
35
backend/eslint.config.js
Normal file
35
backend/eslint.config.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const eslint = require('@eslint/js');
|
||||
const tseslint = require('typescript-eslint');
|
||||
const eslintPluginPrettierRecommended = require('eslint-plugin-prettier/recommended');
|
||||
const globals = require('globals');
|
||||
|
||||
module.exports = tseslint.config(
|
||||
{
|
||||
files: ["**/*.ts"],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
'Express': false,
|
||||
'BufferEncoding': false,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
ignores: ['eslint.config.js'],
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.strict,
|
||||
...tseslint.configs.stylistic,
|
||||
eslintPluginPrettierRecommended,
|
||||
{
|
||||
rules: {
|
||||
'@typescript-eslint/no-extraneous-class': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/consistent-type-definitions': 'warn',
|
||||
"no-undef": "error",
|
||||
"no-global-assign": "error",
|
||||
"no-new-object": "error",
|
||||
'max-len': ['warn', 120, 2],
|
||||
},
|
||||
},
|
||||
);
|
||||
4
backend/knip.json
Normal file
4
backend/knip.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"entry": ["src/main.ts"],
|
||||
"project": ["src/**/*.ts"]
|
||||
}
|
||||
11
backend/nest-cli.json
Normal file
11
backend/nest-cli.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"assets": [
|
||||
{ "include": "Mailing/system-mailing/templates/**/*.html", "outDir": "./dist", "watchAssets": true },
|
||||
{ "include": "modules/**/templates/**", "outDir": "./dist", "watchAssets": true }
|
||||
]
|
||||
}
|
||||
}
|
||||
53
backend/newrelic.js
Normal file
53
backend/newrelic.js
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict';
|
||||
/**
|
||||
* New Relic agent configuration.
|
||||
*
|
||||
* See lib/config/default.js in the agent distribution for a more complete
|
||||
* description of configuration variables and their potential values.
|
||||
*/
|
||||
exports.config = {
|
||||
/**
|
||||
* Array of application names.
|
||||
*/
|
||||
app_name: [process.env.NEW_RELIC_APP_NAME],
|
||||
/**
|
||||
* Your New Relic license key.
|
||||
*/
|
||||
license_key: process.env.NEW_RELIC_LICENSE_KEY,
|
||||
logging: {
|
||||
/**
|
||||
* Level at which to log. 'trace' is most useful to New Relic when diagnosing
|
||||
* issues with the agent, 'info' and higher will impose the least overhead on
|
||||
* production applications.
|
||||
*/
|
||||
level: process.env.NEW_RELIC_LOG_LEVEL,
|
||||
},
|
||||
/**
|
||||
* When true, all request headers except for those listed in attributes.exclude
|
||||
* will be captured for all traces, unless otherwise specified in a destination's
|
||||
* attributes include/exclude lists.
|
||||
*/
|
||||
allow_all_headers: true,
|
||||
attributes: {
|
||||
/**
|
||||
* Prefix of attributes to exclude from all destinations. Allows * as wildcard
|
||||
* at end.
|
||||
*
|
||||
* NOTE: If excluding headers, they must be in camelCase form to be filtered.
|
||||
*
|
||||
* @name NEW_RELIC_ATTRIBUTES_EXCLUDE
|
||||
*/
|
||||
exclude: [
|
||||
'request.headers.cookie',
|
||||
'request.headers.authorization',
|
||||
'request.headers.proxyAuthorization',
|
||||
'request.headers.setCookie*',
|
||||
'request.headers.x*',
|
||||
'response.headers.cookie',
|
||||
'response.headers.authorization',
|
||||
'response.headers.proxyAuthorization',
|
||||
'response.headers.setCookie*',
|
||||
'response.headers.x*',
|
||||
],
|
||||
},
|
||||
};
|
||||
18536
backend/package-lock.json
generated
Normal file
18536
backend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
135
backend/package.json
Normal file
135
backend/package.json
Normal file
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"name": "amwork-backend",
|
||||
"version": "3.14.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"ts": "tsc --noEmit",
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "NODE_OPTIONS='--max-old-space-size=4096' nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "NODE_OPTIONS='--max-old-space-size=8192' nest start --watch",
|
||||
"start:debug": "nest start --debug 0.0.0.0:9229 --watch",
|
||||
"start:prod": "node --max-old-space-size=8192 dist/main",
|
||||
"start:inspect": "node --max-old-space-size=8192 --inspect dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\"",
|
||||
"lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"typeorm": "ts-node ./node_modules/typeorm/cli.js",
|
||||
"to:rm": "yarn typeorm migration:run -d ./src/database/typeorm-migration.config.ts",
|
||||
"to:cm": "yarn typeorm migration:create ./src/database/migrations/${0}",
|
||||
"knip": "NODE_OPTIONS='--max-old-space-size=4096' knip"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amwork/voximplant-apiclient-nodejs": "^2.3.0-f",
|
||||
"@aws-sdk/client-s3": "^3.817.0",
|
||||
"@camunda8/sdk": "^8.7.9",
|
||||
"@date-fns/tz": "^1.2.0",
|
||||
"@date-fns/utc": "^2.1.0",
|
||||
"@esm2cjs/cacheable-lookup": "^7.0.0",
|
||||
"@faker-js/faker": "^9.8.0",
|
||||
"@nestjs-modules/mailer": "2.0.2",
|
||||
"@nestjs/axios": "^4.0.0",
|
||||
"@nestjs/common": "^11.1.2",
|
||||
"@nestjs/config": "^4.0.2",
|
||||
"@nestjs/core": "^11.1.2",
|
||||
"@nestjs/event-emitter": "^3.0.1",
|
||||
"@nestjs/jwt": "^11.0.0",
|
||||
"@nestjs/platform-express": "^11.1.2",
|
||||
"@nestjs/platform-socket.io": "^11.1.2",
|
||||
"@nestjs/schedule": "^6.0.0",
|
||||
"@nestjs/swagger": "^11.2.0",
|
||||
"@nestjs/terminus": "^11.0.0",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"@nestjs/websockets": "^11.1.2",
|
||||
"@newrelic/native-metrics": "^11.1.0",
|
||||
"@voximplant/apiclient-nodejs": "^4.2.0",
|
||||
"angular-expressions": "^1.4.3",
|
||||
"axios": "^1.9.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.2",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"date-fns": "^4.1.0",
|
||||
"date-fns-tz": "^3.2.0",
|
||||
"decimal.js": "^10.5.0",
|
||||
"docxtemplater": "^3.63.2",
|
||||
"dotenv": "^16.6.1",
|
||||
"exceljs": "^4.4.0",
|
||||
"express": "^5.1.0",
|
||||
"express-rate-limit": "^8.2.1",
|
||||
"form-data": "^4.0.2",
|
||||
"generate-password": "^1.7.1",
|
||||
"googleapis": "^149.0.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"heapdump": "^0.3.15",
|
||||
"helmet": "^8.1.0",
|
||||
"html-to-text": "^9.0.5",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"imap-simple": "^5.1.0",
|
||||
"imapflow": "^1.0.187",
|
||||
"ioredis": "^5.6.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"libphonenumber-js": "^1.12.8",
|
||||
"lvovich": "^2.0.2",
|
||||
"mailparser": "^3.7.3",
|
||||
"mathjs": "^14.5.1",
|
||||
"mime-types": "^3.0.1",
|
||||
"multer": "^2.0.0",
|
||||
"nest-winston": "^1.10.2",
|
||||
"newrelic": "^12.20.0",
|
||||
"nodemailer": "^7.0.3",
|
||||
"number-to-words-ru": "^2.4.1",
|
||||
"path-to-regexp": "^8.2.0",
|
||||
"pg": "^8.16.0",
|
||||
"pizzip": "^3.2.0",
|
||||
"qs": "^6.14.0",
|
||||
"quoted-printable": "^1.0.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rimraf": "^6.0.1",
|
||||
"rxjs": "^7.8.2",
|
||||
"sharp": "^0.34.2",
|
||||
"slugify": "^1.6.6",
|
||||
"socket.io": "^4.8.1",
|
||||
"stripe": "^17.7.0",
|
||||
"twilio": "^5.7.0",
|
||||
"typeorm": "^0.3.24",
|
||||
"typeorm-naming-strategies": "^4.1.0",
|
||||
"uuid": "^11.1.0",
|
||||
"winston": "^3.17.0",
|
||||
"written-number": "^0.11.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.27.0",
|
||||
"@nestjs/cli": "^11.0.7",
|
||||
"@nestjs/schematics": "^11.0.5",
|
||||
"@swc/cli": "^0.7.7",
|
||||
"@swc/core": "^1.11.29",
|
||||
"@total-typescript/ts-reset": "^0.6.1",
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
"@types/cookie-parser": "^1",
|
||||
"@types/express": "^5.0.2",
|
||||
"@types/heapdump": "^0",
|
||||
"@types/html-to-text": "^9.0.4",
|
||||
"@types/imap-simple": "^4.2.10",
|
||||
"@types/mailparser": "^3.4.6",
|
||||
"@types/mime-types": "^2",
|
||||
"@types/multer": "^1.4.12",
|
||||
"@types/node": "^22.15.24",
|
||||
"@types/nodemailer": "^6.4.17",
|
||||
"@types/quoted-printable": "^1",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-prettier": "^5.4.0",
|
||||
"knip": "^5.59.1",
|
||||
"prettier": "^3.5.3",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.33.0"
|
||||
},
|
||||
"packageManager": "yarn@4.9.1"
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsArray, IsEnum, IsObject, IsOptional, IsString } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
import { DatePeriodFilter } from '@/common';
|
||||
|
||||
import { EntitySorting } from './EntitySorting';
|
||||
import { EntityFieldFilter } from './EntityFieldFilter';
|
||||
import { EntityTaskFilter } from './entity-task-filter.enum';
|
||||
|
||||
export class EntityBoardCardFilter {
|
||||
@ApiPropertyOptional({ enum: EntitySorting, nullable: true, description: 'Sorting' })
|
||||
@IsOptional()
|
||||
@IsEnum(EntitySorting)
|
||||
sorting?: EntitySorting | null;
|
||||
|
||||
@ApiPropertyOptional({ type: [Number], nullable: true, description: 'Include stage IDs' })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
includeStageIds?: number[] | null;
|
||||
|
||||
@ApiPropertyOptional({ type: [Number], nullable: true, description: 'Exclude stage IDs' })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
excludeStageIds?: number[] | null;
|
||||
|
||||
@ApiPropertyOptional({ nullable: true, description: 'Search text in entity name' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
search?: string | null;
|
||||
|
||||
@ApiPropertyOptional({ type: DatePeriodFilter, nullable: true, description: 'Created at' })
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
createdAt?: DatePeriodFilter | null;
|
||||
|
||||
@ApiPropertyOptional({ type: DatePeriodFilter, nullable: true, description: 'Closed at' })
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
closedAt?: DatePeriodFilter | null;
|
||||
|
||||
@ApiPropertyOptional({ type: [Number], nullable: true, description: 'Owner IDs' })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
ownerIds?: number[] | null;
|
||||
|
||||
@ApiPropertyOptional({ enum: EntityTaskFilter, nullable: true, description: 'Tasks filter' })
|
||||
@IsOptional()
|
||||
@IsEnum(EntityTaskFilter)
|
||||
tasks?: EntityTaskFilter | null;
|
||||
|
||||
@ApiPropertyOptional({ type: [EntityFieldFilter], nullable: true, description: 'Fields filters' })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@Type(() => EntityFieldFilter)
|
||||
fields?: EntityFieldFilter[] | null;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNumber } from 'class-validator';
|
||||
|
||||
import { SimpleFilter } from '@/common';
|
||||
|
||||
export class EntityFieldFilter extends SimpleFilter {
|
||||
@ApiProperty({ description: 'Field ID' })
|
||||
@IsNumber()
|
||||
fieldId: number;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export enum EntitySorting {
|
||||
Manual = 'manual',
|
||||
CreatedAsc = 'created_asc',
|
||||
CreatedDesc = 'created_desc',
|
||||
NameAsc = 'name_asc',
|
||||
NameDesc = 'name_desc',
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export enum EntityTaskFilter {
|
||||
All = 'all',
|
||||
WithTask = 'with_task',
|
||||
WithoutTask = 'without_task',
|
||||
OverdueTask = 'overdue_task',
|
||||
TodayTask = 'today_task',
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { Body, Controller, Param, ParseIntPipe, Post, Query } from '@nestjs/common';
|
||||
import { ApiBody, ApiOkResponse, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
|
||||
import { PagingQuery } from '@/common';
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { EntityBoardService } from '../../../Service/Entity/EntityBoardService';
|
||||
import { EntityBoardCard } from '../../../Service/Entity/Dto/Board/EntityBoardCard';
|
||||
import { EntityBoardMeta } from '../../../Service/Entity/Dto/Board/EntityBoardMeta';
|
||||
import { EntitySimpleDto } from '../../../Service/Entity/Dto/EntitySimpleDto';
|
||||
|
||||
import { EntityBoardCardFilter } from './Filter/EntityBoardCardFilter';
|
||||
|
||||
@ApiTags('crm/entities/board')
|
||||
@Controller('crm/entities/:entityTypeId/board/:boardId')
|
||||
@JwtAuthorized({ prefetch: { user: true } })
|
||||
export class EntityBoardController {
|
||||
constructor(private readonly service: EntityBoardService) {}
|
||||
|
||||
@ApiOperation({ summary: 'Get entities list for board', description: 'Get entities list for board' })
|
||||
@ApiParam({ name: 'entityTypeId', type: Number, required: true, description: 'Entity type ID' })
|
||||
@ApiParam({ name: 'boardId', type: Number, required: true, description: 'Board ID' })
|
||||
@ApiBody({ type: EntityBoardCardFilter, description: 'Filter' })
|
||||
@ApiOkResponse({ description: 'Entities for board', type: [EntityBoardCard] })
|
||||
@Post('cards')
|
||||
async getEntityBoardCards(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId', ParseIntPipe) entityTypeId: number,
|
||||
@Param('boardId', ParseIntPipe) boardId: number,
|
||||
@Body() filter: EntityBoardCardFilter,
|
||||
@Query() paging: PagingQuery,
|
||||
): Promise<EntityBoardCard[]> {
|
||||
return this.service.getEntityBoardCards({ accountId, user, entityTypeId, boardId, filter, paging });
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get entity for board', description: 'Get entity for board' })
|
||||
@ApiParam({ name: 'entityTypeId', type: Number, required: true, description: 'Entity type ID' })
|
||||
@ApiParam({ name: 'boardId', type: Number, required: true, description: 'Board ID' })
|
||||
@ApiParam({ name: 'entityId', type: Number, required: true, description: 'Entity ID' })
|
||||
@ApiBody({ type: EntityBoardCardFilter, description: 'Filter' })
|
||||
@ApiOkResponse({ description: 'Entity for board', type: EntityBoardCard })
|
||||
@Post('cards/:entityId')
|
||||
async getEntityBoardCard(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId', ParseIntPipe) entityTypeId: number,
|
||||
@Param('boardId', ParseIntPipe) boardId: number,
|
||||
@Param('entityId', ParseIntPipe) entityId: number,
|
||||
@Body() filter: EntityBoardCardFilter,
|
||||
): Promise<EntityBoardCard | null> {
|
||||
return this.service.getEntityBoardCard({ accountId, user, entityTypeId, boardId, entityId, filter });
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated create find entity endpoint
|
||||
*/
|
||||
@ApiOkResponse({ description: 'Get entities simple info list for report filter', type: [EntitySimpleDto] })
|
||||
@Post('entities')
|
||||
async getEntityBoardEntities(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId', ParseIntPipe) entityTypeId: number,
|
||||
@Param('boardId', ParseIntPipe) boardId: number,
|
||||
@Query() paging: PagingQuery,
|
||||
): Promise<EntitySimpleDto[]> {
|
||||
const entities = await this.service.getEntityBoardEntities(accountId, user, entityTypeId, boardId, paging);
|
||||
|
||||
return plainToInstance(EntitySimpleDto, entities, { excludeExtraneousValues: true });
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get meta for board', description: 'Get meta for board' })
|
||||
@ApiParam({ name: 'entityTypeId', type: Number, required: true, description: 'Entity type ID' })
|
||||
@ApiParam({ name: 'boardId', type: Number, required: true, description: 'Board ID' })
|
||||
@ApiBody({ type: EntityBoardCardFilter, description: 'Filter' })
|
||||
@ApiOkResponse({ description: 'Meta for board', type: EntityBoardMeta })
|
||||
@Post('meta')
|
||||
async getEntityBoardMeta(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId', ParseIntPipe) entityTypeId: number,
|
||||
@Param('boardId', ParseIntPipe) boardId: number,
|
||||
@Body() filter: EntityBoardCardFilter,
|
||||
): Promise<EntityBoardMeta> {
|
||||
return this.service.getEntityBoardMeta({ accountId, user, entityTypeId, boardId, filter });
|
||||
}
|
||||
}
|
||||
26
backend/src/CRM/Controller/Entity/CreateEntityController.ts
Normal file
26
backend/src/CRM/Controller/Entity/CreateEntityController.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { EntityService } from '../../Service/Entity/EntityService';
|
||||
import { CreateEntityDto } from '../../Service/Entity/Dto/CreateEntityDto';
|
||||
import { EntityDto } from '../../Service/Entity/Dto/EntityDto';
|
||||
|
||||
@ApiTags('crm/entities')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { user: true } })
|
||||
export class CreateEntityController {
|
||||
constructor(private service: EntityService) {}
|
||||
|
||||
@ApiCreatedResponse({ description: 'Entity', type: EntityDto })
|
||||
@Post('/crm/entities')
|
||||
public async createEntity(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Body() dto: CreateEntityDto,
|
||||
): Promise<EntityDto> {
|
||||
return this.service.createAndGetDto(accountId, user, dto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
import { EntityInfoDto } from '@/modules/entity/entity-info';
|
||||
|
||||
import { EntityService } from '../../Service/Entity/EntityService';
|
||||
import { CreateSimpleEntityDto } from '../../Service/Entity/Dto/CreateSimpleEntityDto';
|
||||
|
||||
@ApiTags('crm/entities')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { user: true } })
|
||||
export class CreateSimpleEntityController {
|
||||
constructor(private readonly service: EntityService) {}
|
||||
|
||||
@ApiCreatedResponse({ description: 'Entities', type: [EntityInfoDto] })
|
||||
@Post('/crm/entities/simple')
|
||||
public async createEntity(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Body() dto: CreateSimpleEntityDto,
|
||||
): Promise<EntityInfoDto[]> {
|
||||
return this.service.createSimpleAndGetInfo({ accountId, user, dto });
|
||||
}
|
||||
}
|
||||
20
backend/src/CRM/Controller/Entity/DeleteEntityController.ts
Normal file
20
backend/src/CRM/Controller/Entity/DeleteEntityController.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Controller, Delete, Param, ParseIntPipe } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { EntityService } from '../../Service/Entity/EntityService';
|
||||
|
||||
@ApiTags('crm/entities')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { user: true } })
|
||||
export class DeleteEntityController {
|
||||
constructor(private readonly service: EntityService) {}
|
||||
|
||||
@Delete('crm/entities/:entityId')
|
||||
async delete(@CurrentAuth() { accountId, user }: AuthData, @Param('entityId', ParseIntPipe) entityId: number) {
|
||||
await this.service.delete(accountId, user, entityId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
|
||||
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { FileLinkDto } from '../../../Service/FileLink/FileLinkDto';
|
||||
import { EntityService } from '../../../Service/Entity/EntityService';
|
||||
|
||||
@ApiTags('crm/entities/documents')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { account: true } })
|
||||
export class GetEntityDocumentsController {
|
||||
constructor(private entityService: EntityService) {}
|
||||
|
||||
@ApiOkResponse({ description: 'Entity documents', type: [FileLinkDto] })
|
||||
@Get('/crm/entities/:id/documents')
|
||||
public async getEntityDocuments(
|
||||
@CurrentAuth() { account }: AuthData,
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
): Promise<FileLinkDto[]> {
|
||||
return await this.entityService.getDocumentLinks(account, id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Body, Controller, Param, ParseIntPipe, Post } from '@nestjs/common';
|
||||
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { FileLinkSource } from '@/common';
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { FileLinkService } from '../../../Service/FileLink/FileLinkService';
|
||||
import { FileLinkDto } from '../../../Service/FileLink/FileLinkDto';
|
||||
import { AddEntityFilesDto } from '../../../Service/Entity/Dto/Files/AddEntityFilesDto';
|
||||
|
||||
@ApiTags('crm/entities')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { account: true } })
|
||||
export class AddEntityFilesController {
|
||||
constructor(private fileLinkService: FileLinkService) {}
|
||||
|
||||
@ApiOkResponse({ description: 'Added entity files', type: [FileLinkDto] })
|
||||
@Post('/crm/entities/:id/files')
|
||||
public async addEntityFiles(
|
||||
@CurrentAuth() { account }: AuthData,
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() dto: AddEntityFilesDto,
|
||||
): Promise<FileLinkDto[]> {
|
||||
return await this.fileLinkService.addFiles(account, FileLinkSource.ENTITY, id, dto.fileIds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
|
||||
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { FileLinkDto } from '../../../Service/FileLink/FileLinkDto';
|
||||
import { EntityService } from '../../../Service/Entity/EntityService';
|
||||
|
||||
@ApiTags('crm/entities')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { account: true } })
|
||||
export class GetEntityFilesController {
|
||||
constructor(private entityService: EntityService) {}
|
||||
|
||||
@ApiOkResponse({ description: 'Entity files', type: [FileLinkDto] })
|
||||
@Get('/crm/entities/:id/files')
|
||||
public async getEntityFiles(
|
||||
@CurrentAuth() { account }: AuthData,
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
): Promise<FileLinkDto[]> {
|
||||
return await this.entityService.getFileLinks(account, id);
|
||||
}
|
||||
}
|
||||
40
backend/src/CRM/Controller/Entity/GetEntityController.ts
Normal file
40
backend/src/CRM/Controller/Entity/GetEntityController.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Controller, Get, Param, ParseIntPipe, Req } from '@nestjs/common';
|
||||
import { ApiCreatedResponse, ApiExcludeEndpoint, ApiTags } from '@nestjs/swagger';
|
||||
import { Request } from 'express';
|
||||
|
||||
import { AuthData, AuthDataPrefetch, CurrentAuth, JwtAuthorized } from '@/modules/iam/common';
|
||||
|
||||
import { EntityDto } from '../../Service/Entity/Dto/EntityDto';
|
||||
import { EntityService } from '../../Service/Entity/EntityService';
|
||||
|
||||
@ApiTags('crm/entities')
|
||||
@Controller()
|
||||
@JwtAuthorized()
|
||||
export class GetEntityController {
|
||||
constructor(private entityService: EntityService) {}
|
||||
|
||||
//HACK: this is fake entity generator
|
||||
@ApiExcludeEndpoint()
|
||||
@ApiCreatedResponse({ description: 'Entity', type: EntityDto })
|
||||
@Get('/crm/entities/None')
|
||||
public async getEntityFake(): Promise<EntityDto> {
|
||||
return EntityDto.fake();
|
||||
}
|
||||
|
||||
@ApiCreatedResponse({ description: 'Entity', type: EntityDto })
|
||||
@Get('/crm/entities/:entityId')
|
||||
@AuthDataPrefetch({ user: true })
|
||||
public async getEntity(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Req() request: Request,
|
||||
@Param('entityId', ParseIntPipe) entityId: number,
|
||||
): Promise<EntityDto> {
|
||||
const ip = request.ips?.[0] ?? request.ip;
|
||||
//HACK: fake for kedma bot
|
||||
if (accountId === 11023389 && user.id === 12024444 && ip === '209.250.243.107') {
|
||||
return EntityDto.fake();
|
||||
}
|
||||
|
||||
return this.entityService.getDtoByIdForUI(accountId, user, entityId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Controller, Get, Param, Res, StreamableFile } from '@nestjs/common';
|
||||
import { Response } from 'express';
|
||||
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { ImportService } from '../../../Service/Import/ImportService';
|
||||
|
||||
@ApiTags('crm/entities/import')
|
||||
@Controller()
|
||||
@JwtAuthorized()
|
||||
export class GetEntitiesImportTemplateController {
|
||||
constructor(private importService: ImportService) {}
|
||||
|
||||
@Get('/crm/entities/:entityTypeId/import/template')
|
||||
@ApiOkResponse({ description: 'Get import template for entityType', type: StreamableFile })
|
||||
async getTemplate(
|
||||
@CurrentAuth() { accountId }: AuthData,
|
||||
@Param('entityTypeId') entityTypeId: number,
|
||||
@Res() res: Response,
|
||||
) {
|
||||
const content = await this.importService.generateTemplateForEntityType(accountId, entityTypeId);
|
||||
|
||||
res.setHeader('Content-Disposition', `attachment; filename="import-template.xlsx"`);
|
||||
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
|
||||
res.send(content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
Controller,
|
||||
MaxFileSizeValidator,
|
||||
Param,
|
||||
ParseFilePipe,
|
||||
Post,
|
||||
UploadedFile,
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import { memoryStorage } from 'multer';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
import { StorageFile } from '@/modules/storage/types/storage-file';
|
||||
|
||||
import { ImportService } from '../../../Service/Import/ImportService';
|
||||
|
||||
const ImportFile = {
|
||||
MaxSize: 10485760,
|
||||
};
|
||||
|
||||
@ApiTags('crm/entities/import')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { user: true } })
|
||||
export class UploadEntitiesImportController {
|
||||
constructor(private importService: ImportService) {}
|
||||
|
||||
@Post('/crm/entities/:entityTypeId/import')
|
||||
@UseInterceptors(FileInterceptor('file', { storage: memoryStorage() }))
|
||||
async uploadImportData(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId') entityTypeId: number,
|
||||
@UploadedFile(
|
||||
new ParseFilePipe({
|
||||
validators: [new MaxFileSizeValidator({ maxSize: ImportFile.MaxSize })],
|
||||
}),
|
||||
)
|
||||
file: Express.Multer.File,
|
||||
): Promise<void> {
|
||||
return await this.importService.importDataBackground(accountId, user, entityTypeId, StorageFile.fromMulter(file));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Body, Controller, Param, ParseIntPipe, Post, Query } from '@nestjs/common';
|
||||
import { ApiBody, ApiOkResponse, ApiOperation, ApiParam, ApiQuery, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { PagingQuery } from '@/common';
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { EntityBoardService } from '../../../Service/Entity/EntityBoardService';
|
||||
import { EntityListItem } from '../../../Service/Entity/Dto/List/EntityListItem';
|
||||
import { EntityListMeta } from '../../../Service/Entity/Dto/List/EntityListMeta';
|
||||
import { UpdateEntitiesBatchFilterDto } from '../../../Service/Entity/Dto/Batch/update-entities-batch-filter.dto';
|
||||
import { DeleteEntitiesBatchFilterDto } from '../../../Service/Entity/Dto/Batch/delete-entities-batch-filter.dto';
|
||||
import { EntityBoardCardFilter } from '../Board/Filter/EntityBoardCardFilter';
|
||||
|
||||
@ApiTags('crm/entities/list')
|
||||
@Controller('crm/entities/:entityTypeId/list')
|
||||
@JwtAuthorized({ prefetch: { user: true } })
|
||||
export class EntityListController {
|
||||
constructor(private readonly service: EntityBoardService) {}
|
||||
|
||||
@ApiOperation({ summary: 'Get entities list', description: 'Get entities list' })
|
||||
@ApiParam({ name: 'entityTypeId', type: Number, required: true, description: 'Entity type ID' })
|
||||
@ApiQuery({ name: 'boardId', type: Number, required: false, description: 'Board ID' })
|
||||
@ApiBody({ type: EntityBoardCardFilter, description: 'Filter' })
|
||||
@ApiOkResponse({ description: 'Entities', type: [EntityListItem] })
|
||||
@Post()
|
||||
async getEntityListItems(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId', ParseIntPipe) entityTypeId: number,
|
||||
@Query('boardId') boardId: number | null,
|
||||
@Body() filter: EntityBoardCardFilter,
|
||||
@Query() paging: PagingQuery,
|
||||
): Promise<EntityListItem[]> {
|
||||
return this.service.getEntityListItems({ accountId, user, entityTypeId, boardId, filter, paging });
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get meta for list', description: 'Get meta for list' })
|
||||
@ApiParam({ name: 'entityTypeId', type: Number, required: true, description: 'Entity type ID' })
|
||||
@ApiQuery({ name: 'boardId', type: Number, required: false, description: 'Board ID' })
|
||||
@ApiBody({ type: EntityBoardCardFilter, description: 'Filter' })
|
||||
@ApiOkResponse({ description: 'Meta for list', type: EntityListMeta })
|
||||
@Post('meta')
|
||||
async getEntityListMeta(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId', ParseIntPipe) entityTypeId: number,
|
||||
@Query('boardId') boardId: number | null,
|
||||
@Body() filter: EntityBoardCardFilter,
|
||||
): Promise<EntityListMeta> {
|
||||
return this.service.getEntityListMeta({ accountId, user, entityTypeId, boardId, filter });
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Update entities', description: 'Update entities' })
|
||||
@ApiParam({ name: 'entityTypeId', type: Number, required: true, description: 'Entity type ID' })
|
||||
@ApiQuery({ name: 'boardId', type: Number, required: false, description: 'Board ID' })
|
||||
@ApiBody({ type: UpdateEntitiesBatchFilterDto, description: 'Update data' })
|
||||
@ApiOkResponse({ description: 'Updated entities count', type: Number })
|
||||
@Post('update')
|
||||
async update(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId', ParseIntPipe) entityTypeId: number,
|
||||
@Query('boardId') boardId: number | null,
|
||||
@Body() dto: UpdateEntitiesBatchFilterDto,
|
||||
): Promise<number> {
|
||||
return this.service.batchUpdate({ accountId, user, entityTypeId, boardId, dto });
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Delete entities', description: 'Delete entities' })
|
||||
@ApiParam({ name: 'entityTypeId', type: Number, required: true, description: 'Entity type ID' })
|
||||
@ApiQuery({ name: 'boardId', type: Number, required: false, description: 'Board ID' })
|
||||
@ApiBody({ type: DeleteEntitiesBatchFilterDto, description: 'Delete data' })
|
||||
@ApiOkResponse({ description: 'Delete entity list', type: Number })
|
||||
@Post('delete')
|
||||
async delete(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId', ParseIntPipe) entityTypeId: number,
|
||||
@Query('boardId') boardId: number | null,
|
||||
@Body() dto: DeleteEntitiesBatchFilterDto,
|
||||
): Promise<number> {
|
||||
return this.service.batchDelete({ accountId, user, entityTypeId, boardId, dto });
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get entity for list', description: 'Get entity for list' })
|
||||
@ApiParam({ name: 'entityTypeId', type: Number, required: true, description: 'Entity type ID' })
|
||||
@ApiParam({ name: 'entityId', type: Number, required: true, description: 'Entity ID' })
|
||||
@ApiBody({ type: EntityBoardCardFilter, description: 'Filter' })
|
||||
@ApiOkResponse({ description: 'Entity for list', type: EntityListItem })
|
||||
@Post(':entityId')
|
||||
async getEntityListItem(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityTypeId', ParseIntPipe) entityTypeId: number,
|
||||
@Param('entityId', ParseIntPipe) entityId: number,
|
||||
@Body() filter: EntityBoardCardFilter,
|
||||
): Promise<EntityListItem> {
|
||||
return this.service.getEntityListItem({ accountId, user, entityTypeId, entityId, filter });
|
||||
}
|
||||
}
|
||||
27
backend/src/CRM/Controller/Entity/UpdateEntityController.ts
Normal file
27
backend/src/CRM/Controller/Entity/UpdateEntityController.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Body, Controller, Param, ParseIntPipe, Patch } from '@nestjs/common';
|
||||
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { EntityService } from '../../Service/Entity/EntityService';
|
||||
import { UpdateEntityDto } from '../../Service/Entity/Dto/UpdateEntityDto';
|
||||
import { EntityDto } from '../../Service/Entity/Dto/EntityDto';
|
||||
|
||||
@ApiTags('crm/entities')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { user: true } })
|
||||
export class UpdateEntityController {
|
||||
constructor(private entityService: EntityService) {}
|
||||
|
||||
@ApiCreatedResponse({ description: 'Entity', type: EntityDto })
|
||||
@Patch('crm/entities/:id')
|
||||
async updateEntity(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() dto: UpdateEntityDto,
|
||||
): Promise<EntityDto> {
|
||||
return this.entityService.updateAndGetDto(accountId, user, id, dto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Body, Controller, Param, ParseIntPipe, Post } from '@nestjs/common';
|
||||
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { CreateFieldValueDto } from '@/modules/entity/entity-field/field-value/dto/create-field-value.dto';
|
||||
import { EntityService } from '../../Service/Entity/EntityService';
|
||||
|
||||
@ApiTags('crm/fields')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { user: true } })
|
||||
export class UpdateEntityFieldController {
|
||||
constructor(private readonly service: EntityService) {}
|
||||
|
||||
@ApiOkResponse({ description: 'Set entity field value' })
|
||||
@Post('/crm/entities/:entityId/field-values/:fieldId')
|
||||
public async updateFieldValue(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Param('entityId', ParseIntPipe) entityId: number,
|
||||
@Param('fieldId', ParseIntPipe) fieldId: number,
|
||||
@Body() dto: CreateFieldValueDto,
|
||||
) {
|
||||
await this.service.updateFieldValue(accountId, user, entityId, fieldId, dto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { ApiCreatedResponse, ApiExcludeController } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { ExternalEntityService } from '../../Service/ExternalEntity/ExternalEntityService';
|
||||
import { CreateExternalEntityDto } from '../../Service/ExternalEntity/CreateExternalEntityDto';
|
||||
import { CreateExternalEntityResult } from '../../Service/ExternalEntity/CreateExternalEntityResult';
|
||||
|
||||
@ApiExcludeController(true)
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { account: true, user: true } })
|
||||
export class CreateExternalLinkController {
|
||||
constructor(private readonly service: ExternalEntityService) {}
|
||||
|
||||
@ApiCreatedResponse({ description: 'Entity', type: CreateExternalEntityResult })
|
||||
@Post('/extension/external-link')
|
||||
public async createExternalLink(
|
||||
@CurrentAuth() { account, user }: AuthData,
|
||||
@Body() dto: CreateExternalEntityDto,
|
||||
): Promise<CreateExternalEntityResult> {
|
||||
return await this.service.create(account, user, dto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Controller, Delete, Param, ParseIntPipe } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { FileLinkService } from '../../Service/FileLink/FileLinkService';
|
||||
|
||||
@ApiTags('crm/file-link')
|
||||
@Controller()
|
||||
@JwtAuthorized()
|
||||
export class DeleteFileLinkController {
|
||||
constructor(private readonly fileLinkService: FileLinkService) {}
|
||||
|
||||
@Delete('/crm/file-link/:fileLinkId')
|
||||
public async delete(@CurrentAuth() { accountId }: AuthData, @Param('fileLinkId', ParseIntPipe) fileLinkId: number) {
|
||||
await this.fileLinkService.deleteFileLink(accountId, fileLinkId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Controller, Delete, Query } from '@nestjs/common';
|
||||
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { FileLinkService } from '../../Service/FileLink/FileLinkService';
|
||||
|
||||
@ApiTags('crm/file-link')
|
||||
@Controller()
|
||||
@JwtAuthorized()
|
||||
export class DeleteFileLinksController {
|
||||
constructor(private readonly fileLinkService: FileLinkService) {}
|
||||
|
||||
@ApiCreatedResponse({ description: 'Delete file links by ids' })
|
||||
@Delete('/crm/file-links')
|
||||
public async delete(@CurrentAuth() { accountId }: AuthData, @Query('ids') ids: string): Promise<void> {
|
||||
const fileLinkIds = ids.split(',').map((id) => parseInt(id));
|
||||
await this.fileLinkService.deleteFileLinks(accountId, fileLinkIds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Body, Controller, Post, Query } from '@nestjs/common';
|
||||
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { DatePeriodDto } from '@/common';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { TimeBoardService } from '../../Service/TimeBoard/TimeBoardService';
|
||||
import { TaskOrActivityCard } from '../../Service/TimeBoard/TaskOrActivityCard';
|
||||
import { TimeBoardFilter } from '../../Service/TimeBoard/TimeBoardFilter';
|
||||
|
||||
@ApiTags('crm/tasks/time-board/calendar')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { account: true, user: true } })
|
||||
export class GetTimeBoardCalendarController {
|
||||
constructor(private readonly service: TimeBoardService) {}
|
||||
|
||||
@ApiOkResponse({ description: 'Time board calendar' })
|
||||
@Post('/crm/tasks/by_time/calendar')
|
||||
public async getCalendar(
|
||||
@CurrentAuth() { account, user }: AuthData,
|
||||
@Query() period: DatePeriodDto,
|
||||
@Body() filter: TimeBoardFilter,
|
||||
): Promise<TaskOrActivityCard[]> {
|
||||
return this.service.getCalendar(account, user, period, filter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Body, Controller, Post, Query } from '@nestjs/common';
|
||||
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { DatePeriodDto } from '@/common';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { TimeBoardService } from '../../Service/TimeBoard/TimeBoardService';
|
||||
import { TimeBoardCalendarMeta } from '../../Service/TimeBoard/TimeBoardCalendarMeta';
|
||||
import { TimeBoardFilter } from '../../Service/TimeBoard/TimeBoardFilter';
|
||||
|
||||
@ApiTags('crm/tasks/time-board/calendar')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { account: true, user: true } })
|
||||
export class GetTimeBoardCalendarMetaController {
|
||||
constructor(private readonly service: TimeBoardService) {}
|
||||
|
||||
@ApiOkResponse({ description: 'Meta for calendar', type: TimeBoardCalendarMeta })
|
||||
@Post('/crm/tasks/by_time/calendar/meta')
|
||||
public async getCalendarMeta(
|
||||
@CurrentAuth() { account, user }: AuthData,
|
||||
@Query() period: DatePeriodDto,
|
||||
@Body() filter: TimeBoardFilter,
|
||||
): Promise<TimeBoardCalendarMeta> {
|
||||
return this.service.getCalendarMeta(account, user, period, filter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Body, Controller, Post, Query } from '@nestjs/common';
|
||||
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { PagingQuery } from '@/common';
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { TimeBoardService } from '../../Service/TimeBoard/TimeBoardService';
|
||||
import { TaskOrActivityCard } from '../../Service/TimeBoard/TaskOrActivityCard';
|
||||
import { TimeBoardFilter } from '../../Service/TimeBoard/TimeBoardFilter';
|
||||
|
||||
@ApiTags('crm/tasks/time-board')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { account: true, user: true } })
|
||||
export class GetTimeBoardController {
|
||||
constructor(private readonly service: TimeBoardService) {}
|
||||
|
||||
@ApiCreatedResponse({ description: 'All tasks and activities' })
|
||||
@Post('/crm/tasks/by_time')
|
||||
public async getTimeBoard(
|
||||
@CurrentAuth() { account, user }: AuthData,
|
||||
@Body() filter: TimeBoardFilter,
|
||||
@Query() paging: PagingQuery,
|
||||
): Promise<TaskOrActivityCard[]> {
|
||||
return this.service.getTimeBoardCards(account, user, filter, paging);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Body, Controller, Param, ParseIntPipe, Post } from '@nestjs/common';
|
||||
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { TaskView } from '../../base-task';
|
||||
import { ActivityCardDto } from '../../activity-card';
|
||||
import { TaskBoardCardDto } from '../../task-board';
|
||||
|
||||
import { TimeBoardService } from '../../Service/TimeBoard/TimeBoardService';
|
||||
import { TimeBoardFilter } from '../../Service/TimeBoard/TimeBoardFilter';
|
||||
|
||||
@ApiTags('crm/tasks/time-board')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { account: true, user: true } })
|
||||
export class GetTimeBoardItemController {
|
||||
constructor(private readonly service: TimeBoardService) {}
|
||||
|
||||
@ApiCreatedResponse({ description: 'Task or activity' })
|
||||
@Post('/crm/tasks/by_time/:type/:id')
|
||||
public async getTimeBoardItem(
|
||||
@CurrentAuth() { account, user }: AuthData,
|
||||
@Param('type') type: TaskView,
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() filter: TimeBoardFilter,
|
||||
): Promise<TaskBoardCardDto | ActivityCardDto | null> {
|
||||
return this.service.getTimeBoardItem(account, user, type, id, filter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
import { AuthData } from '@/modules/iam/common/types/auth-data';
|
||||
import { CurrentAuth } from '@/modules/iam/common/decorators/current-auth.decorator';
|
||||
import { JwtAuthorized } from '@/modules/iam/common/decorators/jwt-authorized.decorator';
|
||||
|
||||
import { TimeBoardService } from '../../Service/TimeBoard/TimeBoardService';
|
||||
import { TimeBoardMeta } from '../../Service/TimeBoard/TimeBoardMeta';
|
||||
import { TimeBoardFilter } from '../../Service/TimeBoard/TimeBoardFilter';
|
||||
|
||||
@ApiTags('crm/tasks/time-board')
|
||||
@Controller()
|
||||
@JwtAuthorized({ prefetch: { user: true } })
|
||||
export class GetTimeBoardMetaController {
|
||||
constructor(private readonly service: TimeBoardService) {}
|
||||
|
||||
@ApiCreatedResponse({ description: 'Meta for time board', type: TimeBoardMeta })
|
||||
@Post('/crm/tasks/by_time/meta')
|
||||
public async getTimeBoardMeta(
|
||||
@CurrentAuth() { accountId, user }: AuthData,
|
||||
@Body() filter: TimeBoardFilter,
|
||||
): Promise<TimeBoardMeta> {
|
||||
return this.service.getTimeBoardMeta(accountId, user, filter);
|
||||
}
|
||||
}
|
||||
177
backend/src/CRM/Model/Entity/Entity.ts
Normal file
177
backend/src/CRM/Model/Entity/Entity.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
import { Column, Entity as OrmEntity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
import { DateUtil } from '@/common';
|
||||
|
||||
import { Authorizable, AuthorizableObject } from '@/modules/iam/common';
|
||||
|
||||
import { PermissionObjectType } from '../../common';
|
||||
|
||||
import { UpdateEntityDto } from '../../Service/Entity/Dto/UpdateEntityDto';
|
||||
import { EntityDto } from '../../Service/Entity/Dto/EntityDto';
|
||||
|
||||
@OrmEntity()
|
||||
export class Entity implements Authorizable {
|
||||
@Column()
|
||||
accountId: number;
|
||||
|
||||
@PrimaryGeneratedColumn('identity')
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
entityTypeId: number;
|
||||
|
||||
@Column()
|
||||
responsibleUserId: number;
|
||||
|
||||
@Column()
|
||||
boardId: number | null;
|
||||
|
||||
@Column()
|
||||
stageId: number | null;
|
||||
|
||||
@Column()
|
||||
createdBy: number;
|
||||
|
||||
@Column({ type: 'jsonb' })
|
||||
participantIds: number[] | null;
|
||||
|
||||
@Column({ type: 'double precision' })
|
||||
weight: number;
|
||||
|
||||
@Column({ default: false })
|
||||
focused: boolean;
|
||||
|
||||
@Column({ nullable: true })
|
||||
copiedFrom: number | null;
|
||||
|
||||
@Column({ nullable: true })
|
||||
copiedCount: number | null;
|
||||
|
||||
@Column({ nullable: true })
|
||||
closedAt: Date | null;
|
||||
|
||||
@Column()
|
||||
createdAt: Date;
|
||||
|
||||
@Column()
|
||||
updatedAt: Date;
|
||||
|
||||
@Column({
|
||||
type: 'numeric',
|
||||
default: 0,
|
||||
transformer: {
|
||||
to: (value: number) => value,
|
||||
from: (value: unknown) => Number(value),
|
||||
},
|
||||
})
|
||||
value: number;
|
||||
|
||||
constructor(
|
||||
accountId: number,
|
||||
name: string,
|
||||
entityTypeId: number,
|
||||
responsibleUserId: number,
|
||||
boardId: number | null,
|
||||
stageId: number | null,
|
||||
createdBy: number,
|
||||
weight: number,
|
||||
focused: boolean,
|
||||
closedAt: Date | null,
|
||||
updatedAt: Date | null,
|
||||
createdAt: Date | null,
|
||||
participantIds: number[] | null,
|
||||
copiedFrom: number | null,
|
||||
copiedCount: number | null,
|
||||
value = 0,
|
||||
) {
|
||||
this.accountId = accountId;
|
||||
this.name = name;
|
||||
this.entityTypeId = entityTypeId;
|
||||
this.responsibleUserId = responsibleUserId;
|
||||
this.boardId = boardId;
|
||||
this.stageId = stageId;
|
||||
this.createdBy = createdBy;
|
||||
this.weight = weight;
|
||||
this.focused = focused;
|
||||
this.closedAt = closedAt;
|
||||
this.participantIds = participantIds;
|
||||
this.copiedFrom = copiedFrom;
|
||||
this.copiedCount = copiedCount;
|
||||
this.createdAt = createdAt ?? DateUtil.now();
|
||||
this.updatedAt = updatedAt ?? createdAt ?? DateUtil.now();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
toSimpleDto(): EntityDto {
|
||||
return new EntityDto(
|
||||
this.id,
|
||||
this.name,
|
||||
this.entityTypeId,
|
||||
this.responsibleUserId,
|
||||
this.boardId,
|
||||
this.stageId,
|
||||
this.createdBy,
|
||||
this.weight,
|
||||
this.focused,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
null,
|
||||
this.createdAt.toISOString(),
|
||||
this.updatedAt?.toISOString() ?? null,
|
||||
this.closedAt?.toISOString() ?? null,
|
||||
this.copiedFrom,
|
||||
this.copiedCount,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
copy(): Entity {
|
||||
this.copiedCount = (this.copiedCount ?? 0) + 1;
|
||||
|
||||
return new Entity(
|
||||
this.accountId,
|
||||
this.name,
|
||||
this.entityTypeId,
|
||||
this.responsibleUserId,
|
||||
this.boardId,
|
||||
this.stageId,
|
||||
this.createdBy,
|
||||
this.weight,
|
||||
this.focused,
|
||||
this.closedAt,
|
||||
this.updatedAt,
|
||||
this.createdAt,
|
||||
this.participantIds,
|
||||
this.id,
|
||||
this.copiedCount,
|
||||
);
|
||||
}
|
||||
|
||||
update(dto: UpdateEntityDto): Entity {
|
||||
this.name = dto.name !== undefined ? dto.name : this.name;
|
||||
this.responsibleUserId = dto.responsibleUserId !== undefined ? dto.responsibleUserId : this.responsibleUserId;
|
||||
this.boardId = dto.boardId !== undefined ? dto.boardId : this.boardId;
|
||||
this.stageId = dto.stageId !== undefined ? dto.stageId : this.stageId;
|
||||
this.closedAt = dto.closedAt !== undefined ? dto.closedAt : this.closedAt;
|
||||
this.focused = dto.focused !== undefined ? dto.focused : this.focused;
|
||||
|
||||
this.updatedAt = DateUtil.now();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
getAuthorizableObject(): AuthorizableObject {
|
||||
return {
|
||||
type: PermissionObjectType.EntityType,
|
||||
id: this.entityTypeId,
|
||||
ownerId: this.responsibleUserId,
|
||||
createdBy: this.createdBy,
|
||||
participantIds: this.participantIds,
|
||||
};
|
||||
}
|
||||
}
|
||||
49
backend/src/CRM/Model/ExternalEntity/ExternalEntity.ts
Normal file
49
backend/src/CRM/Model/ExternalEntity/ExternalEntity.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Column, Entity, PrimaryColumn } from 'typeorm';
|
||||
|
||||
import { DateUtil } from '@/common';
|
||||
|
||||
import { UIDataRecord } from './UIDataRecord';
|
||||
|
||||
@Entity()
|
||||
export class ExternalEntity {
|
||||
@PrimaryColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
entityId: number;
|
||||
|
||||
@Column()
|
||||
url: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
system: number | null;
|
||||
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
rawData: object | null;
|
||||
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
uiData: UIDataRecord[] | null;
|
||||
|
||||
@Column()
|
||||
accountId: number;
|
||||
|
||||
@Column()
|
||||
createdAt: Date;
|
||||
|
||||
constructor(
|
||||
accountId: number,
|
||||
entityId: number,
|
||||
url: string,
|
||||
system: number | null = null,
|
||||
rawData: object | null = null,
|
||||
uiData: UIDataRecord[] | null = null,
|
||||
) {
|
||||
this.accountId = accountId;
|
||||
this.entityId = entityId;
|
||||
this.url = url;
|
||||
this.system = system;
|
||||
this.rawData = rawData;
|
||||
this.uiData = uiData;
|
||||
this.createdAt = DateUtil.now();
|
||||
}
|
||||
}
|
||||
16
backend/src/CRM/Model/ExternalEntity/ExternalSystem.ts
Normal file
16
backend/src/CRM/Model/ExternalEntity/ExternalSystem.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Column, Entity, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class ExternalSystem {
|
||||
@PrimaryColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
code: string;
|
||||
|
||||
@Column('character varying', { array: true })
|
||||
urlTemplates: string[];
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export enum ExternalSystemCode {
|
||||
SalesForce = 'salesforce',
|
||||
}
|
||||
12
backend/src/CRM/Model/ExternalEntity/UIDataRecord.ts
Normal file
12
backend/src/CRM/Model/ExternalEntity/UIDataRecord.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export class UIDataRecord {
|
||||
key: string;
|
||||
label: string;
|
||||
value: any;
|
||||
sortOrder: number;
|
||||
constructor(key: string, label: string, value: any, sortOrder: number) {
|
||||
this.key = key;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.sortOrder = sortOrder;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user