Skip to content

Commit

Permalink
TSK-1015: Bitrix Create Vacancy/Application
Browse files Browse the repository at this point in the history
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
  • Loading branch information
haiodo committed Apr 6, 2023
1 parent b766ddf commit f57e565
Show file tree
Hide file tree
Showing 16 changed files with 381 additions and 30 deletions.
4 changes: 3 additions & 1 deletion plugins/bitrix-resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@
"qs": "~6.11.0",
"@hcengineering/tags": "^0.6.3",
"@hcengineering/tags-resources": "^0.6.0",
"fast-equals": "^2.0.3"
"fast-equals": "^2.0.3",
"@hcengineering/recruit": "^0.6.8",
"@hcengineering/task": "^0.6.3"
},
"repository": "https://github.com/hcengineering/anticrm",
"publishConfig": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@
action: (_: any, evt: MouseEvent) => {
addMapping(evt, MappingOperation.FindReference)
}
},
{
label: getEmbeddedLabel('Create Vacancy and application'),
action: (_: any, evt: MouseEvent) => {
addMapping(evt, MappingOperation.CreateHRApplication)
}
}
] as Action[]
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { Label } from '@hcengineering/ui'
import bitrix from '../plugin'
import CopyMapping from './mappings/CopyMapping.svelte'
import CreateAttachedDocMapping from './mappings/CreateHRApplicationMapping.svelte'
import CreateChannelMapping from './mappings/CreateChannelMapping.svelte'
import CreateTagMapping from './mappings/CreateTagMapping.svelte'
import DownloadAttachmentMapping from './mappings/DownloadAttachmentMapping.svelte'
Expand Down Expand Up @@ -45,5 +46,7 @@
<DownloadAttachmentMapping {mapping} {fields} {attribute} {field} bind:this={op} />
{:else if _kind === MappingOperation.FindReference}
<FindReferenceMapping {mapping} {fields} {attribute} {field} bind:this={op} />
{:else if _kind === MappingOperation.CreateHRApplication}
<CreateAttachedDocMapping {mapping} {fields} {attribute} {field} bind:this={op} />
{/if}
</Card>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { getClient } from '@hcengineering/presentation'
import { Button, Icon, IconArrowLeft, IconClose, Label } from '@hcengineering/ui'
import CopyMappingPresenter from './mappings/CopyMappingPresenter.svelte'
import CreateAttachedDocPresenter from './mappings/CreateHRApplicationPresenter.svelte'
import CreateChannelMappingPresenter from './mappings/CreateChannelMappingPresenter.svelte'
import CreateTagMappingPresenter from './mappings/CreateTagMappingPresenter.svelte'
import DownloadAttachmentPresenter from './mappings/DownloadAttachmentPresenter.svelte'
Expand Down Expand Up @@ -40,6 +41,8 @@
<DownloadAttachmentPresenter {mapping} {value} />
{:else if kind === MappingOperation.FindReference}
<FindReferencePresenter {mapping} {value} />
{:else if kind === MappingOperation.CreateHRApplication}
<CreateAttachedDocPresenter {mapping} {value} />
{/if}

<Button
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<script lang="ts">
import {
BitrixEntityMapping,
BitrixFieldMapping,
CreateHRApplication,
Fields,
MappingOperation
} from '@hcengineering/bitrix'
import { AnyAttribute } from '@hcengineering/core'
import { getEmbeddedLabel } from '@hcengineering/platform'
import { getClient } from '@hcengineering/presentation'
import task from '@hcengineering/task'
import { DropdownLabels, DropdownTextItem } from '@hcengineering/ui'
import { ObjectBox } from '@hcengineering/view-resources'
import bitrix from '../../plugin'
import recruit from '@hcengineering/recruit'
export let mapping: BitrixEntityMapping
export let fields: Fields = {}
export let attribute: AnyAttribute
export let field: BitrixFieldMapping | undefined
let stateField = (field?.operation as CreateHRApplication)?.stateField
let vacancyField = (field?.operation as CreateHRApplication)?.vacancyField
let defaultTemplate = (field?.operation as CreateHRApplication)?.defaultTemplate
const client = getClient()
export async function save (): Promise<void> {
if (field !== undefined) {
await client.update(field, {
operation: {
kind: MappingOperation.CreateHRApplication,
stateField,
vacancyField,
defaultTemplate
}
})
} else {
await client.addCollection(bitrix.class.FieldMapping, mapping.space, mapping._id, mapping._class, 'fields', {
ofClass: attribute.attributeOf,
attributeName: attribute.name,
operation: {
kind: MappingOperation.CreateHRApplication,
stateField,
vacancyField,
defaultTemplate
}
})
}
}
function getItems (fields: Fields): DropdownTextItem[] {
return Object.entries(fields).map((it) => ({
id: it[0],
label: `${it[1].formLabel ?? it[1].title}${it[0].startsWith('UF_') ? ' *' : ''}`
}))
}
$: items = getItems(fields)
</script>

<div class="flex-col flex-wrap">
<div class="flex-row-center gap-2">
<div class="flex-col w-120">
<DropdownLabels minW0={false} label={getEmbeddedLabel('Vacancy field')} {items} bind:selected={vacancyField} />
<DropdownLabels minW0={false} label={getEmbeddedLabel('State field')} {items} bind:selected={stateField} />
<ObjectBox
label={getEmbeddedLabel('Template')}
searchField={'title'}
_class={task.class.KanbanTemplate}
docQuery={{ space: recruit.space.VacancyTemplates }}
bind:value={defaultTemplate}
/>
</div>
</div>
</div>

<style lang="scss">
.pattern {
margin: 0.5rem;
padding: 0.5rem;
flex-shrink: 0;
border: 1px dashed var(--accent-color);
border-radius: 0.25rem;
font-weight: 500;
font-size: 0.75rem;
// text-transform: uppercase;
color: var(--accent-color);
&:hover {
color: var(--caption-color);
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script lang="ts">
import { BitrixEntityMapping, BitrixFieldMapping, CreateHRApplication } from '@hcengineering/bitrix'
import task from '@hcengineering/task'
import { ObjectPresenter } from '@hcengineering/view-resources'
export let mapping: BitrixEntityMapping
export let value: BitrixFieldMapping
$: op = value.operation as CreateHRApplication
</script>

<div class="flex flex-wrap">
<div class="pattern flex-row-center gap-2">
{mapping.bitrixFields[op.vacancyField]?.filterLabel} -> {mapping.bitrixFields[op.stateField]?.filterLabel}
<span class="p-1">-></span>
<ObjectPresenter objectId={op.defaultTemplate} _class={task.class.KanbanTemplate} />
</div>
</div>

<style lang="scss">
.pattern {
margin: 0.1rem;
padding: 0.3rem;
flex-shrink: 0;
border: 1px dashed var(--accent-color);
border-radius: 0.25rem;
font-weight: 500;
font-size: 0.75rem;
// text-transform: uppercase;
color: var(--accent-color);
&:hover {
color: var(--caption-color);
}
}
</style>
4 changes: 3 additions & 1 deletion plugins/bitrix/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
"@hcengineering/attachment": "^0.6.1",
"fast-equals": "^2.0.3",
"qs": "~6.11.0",
"@hcengineering/gmail": "^0.6.4"
"@hcengineering/gmail": "^0.6.4",
"@hcengineering/recruit": "^0.6.8",
"@hcengineering/task": "^0.6.3"
},
"repository": "https://github.com/hcengineering/anticrm",
"publishConfig": {
Expand Down
72 changes: 72 additions & 0 deletions plugins/bitrix/src/hr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Organization } from '@hcengineering/contact'
import core, { Account, Client, Doc, Ref, SortingOrder, TxOperations } from '@hcengineering/core'
import recruit, { Vacancy } from '@hcengineering/recruit'
import task, { KanbanTemplate, State, calcRank, createKanban } from '@hcengineering/task'

export async function createVacancy (
rawClient: Client,
name: string,
templateId: Ref<KanbanTemplate>,
account: Ref<Account>,
company?: Ref<Organization>
): Promise<Ref<Vacancy>> {
const client = new TxOperations(rawClient, account)
const template = await client.findOne(task.class.KanbanTemplate, { _id: templateId })
if (template === undefined) {
throw Error(`Failed to find target kanban template: ${templateId}`)
}

const sequence = await client.findOne(task.class.Sequence, { attachedTo: recruit.class.Vacancy })
if (sequence === undefined) {
throw new Error('sequence object not found')
}

const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)

const id = await client.createDoc(recruit.class.Vacancy, core.space.Space, {
name,
description: template.shortDescription ?? '',
fullDescription: template.description,
private: false,
archived: false,
company,
number: (incResult as any).object.sequence,
members: []
})

await createKanban(client, id, templateId)
return id
}

export async function createApplication (
client: TxOperations,
selectedState: State,
_space: Ref<Vacancy>,
doc: Doc
): Promise<void> {
if (selectedState === undefined) {
throw new Error(`Please select initial state:${_space}`)
}
const state = await client.findOne(task.class.State, { space: _space, _id: selectedState?._id })
if (state === undefined) {
throw new Error(`create application: state not found space:${_space}`)
}
const sequence = await client.findOne(task.class.Sequence, { attachedTo: recruit.class.Applicant })
if (sequence === undefined) {
throw new Error('sequence object not found')
}

const lastOne = await client.findOne(recruit.class.Applicant, {}, { sort: { rank: SortingOrder.Descending } })
const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)

await client.addCollection(recruit.class.Applicant, _space, doc._id, recruit.mixin.Candidate, 'applications', {
state: state._id,
doneState: null,
number: (incResult as any).object.sequence,
assignee: null,
rank: calcRank(lastOne, undefined),
startDate: null,
dueDate: null,
createOn: Date.now()
})
}
17 changes: 8 additions & 9 deletions plugins/bitrix/src/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,19 @@ export async function syncDocument (

// Just create supplier documents, like TagElements.
for (const ed of resultDoc.extraDocs) {
await applyOp.createDoc(
ed._class,
ed.space,
ed,
ed._id,
resultDoc.document.modifiedOn,
resultDoc.document.modifiedBy
)
const { _class, space, _id, ...data } = ed
await applyOp.createDoc(_class, space, data, _id, resultDoc.document.modifiedOn, resultDoc.document.modifiedBy)
}

for (const op of resultDoc.postOperations) {
await op(resultDoc.document, existing)
}

const idMapping = new Map<Ref<Doc>, Ref<Doc>>()

// Find all attachment documents to existing.
const byClass = new Map<Ref<Class<Doc>>, (AttachedDoc & BitrixSyncDoc)[]>()

const idMapping = new Map<Ref<Doc>, Ref<Doc>>()
for (const d of resultDoc.extraSync) {
byClass.set(d._class, [...(byClass.get(d._class) ?? []), d])
}
Expand Down
34 changes: 33 additions & 1 deletion plugins/bitrix/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChannelProvider } from '@hcengineering/contact'
import { AttachedDoc, Class, Doc, Mixin, Ref } from '@hcengineering/core'
import { ExpertKnowledge, InitialKnowledge, MeaningfullKnowledge } from '@hcengineering/tags'
import { KanbanTemplate } from '../../task/lib'

/**
* @public
Expand Down Expand Up @@ -174,7 +175,8 @@ export enum MappingOperation {
CreateTag, // Create tag
CreateChannel, // Create channel
DownloadAttachment,
FindReference
FindReference,
CreateHRApplication
}
/**
* @public
Expand Down Expand Up @@ -252,6 +254,35 @@ export interface FindReferenceOperation {
referenceClass: Ref<Class<Doc>>
}

/**
* @public
*/
export interface CreateAttachedField {
match: boolean // We should match type and pass if exists.

// Original document field to use value from.
sourceField: string
valueField: string // final value should go into valueField, field name to match, like `space`

// If reference is defined, we should find for some existing document by matching field with sourceField value.
// Document we should match value against.
referenceClass: Ref<Class<Doc>>
// Field to check for matched value against.
referenceField?: string
}

/**
* @public
*/
export interface CreateHRApplication {
kind: MappingOperation.CreateHRApplication

vacancyField: string // Name of vacancy in bitrix.
stateField: string // Name of status in bitrix.

defaultTemplate: Ref<KanbanTemplate>
}

/**
* @public
*/
Expand All @@ -265,6 +296,7 @@ export interface BitrixFieldMapping extends AttachedDoc {
| CreateChannelOperation
| DownloadAttachmentOperation
| FindReferenceOperation
| CreateHRApplication
}

/**
Expand Down
Loading

0 comments on commit f57e565

Please sign in to comment.