Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TSK-1015: Bitrix Create Vacancy/Application #2913

Merged
merged 1 commit into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 '@hcengineering/task'

/**
* @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