API reference @cogover/sdk: Cơ cấu tổ chức
Trang này thuộc API reference của @cogover/sdk.
Cơ cấu tổ chức
org đọc phòng ban, vị trí và nhân sự của workspace: ai thuộc phòng ban nào, vị trí
nào áp dụng ở đâu và ai quản lý ai. Mọi method đều chỉ đọc. Câu trả lời về cấu trúc
được lấy từ bản sao cơ cấu tổ chức đã cache nên rất nhanh; thay đổi thực hiện trong
Cogover sẽ có hiệu lực sau vài giây. Thêm withDisplay: true để nhận thêm tên phòng
ban, vị trí theo ngôn ngữ và, với nhân sự, tên hiển thị, email, avatar và mã nhân sự.
Các field khác của nhân sự như số điện thoại hay custom field được đọc bằng
data.object("personnel"), nơi quyền record được áp dụng.
interface OrgApi {
readonly personnel: OrgPersonnelApi;
readonly departments: OrgDepartmentsApi;
readonly positions: OrgPositionsApi;
me(options?: OrgReadOptions): Promise<OrgPersonnel | null>;
isInDepartment(personnelId: string, departmentId: string,
options?: OrgIsInDepartmentOptions): Promise<boolean>;
isManagerOf(managerId: string, personnelId: string,
options?: OrgIsManagerOfOptions): Promise<boolean>;
}
interface OrgPersonnelApi {
get(id: string, options?: OrgReadOptions): Promise<OrgPersonnel | null>;
getMany(ids: readonly string[], options?: OrgReadOptions):
Promise<OrgGetManyResult<OrgPersonnel>>;
managerChain(id: string, options?: OrgPersonnelChainOptions):
Promise<readonly OrgManagerChain[]>;
}
interface OrgDepartmentsApi {
get(id: string, options?: OrgReadOptions): Promise<OrgDepartment | null>;
tree(options?: OrgTreeOptions): Promise<readonly OrgDepartmentNode[]>;
ancestors(id: string, options?: OrgReadOptions): Promise<readonly OrgDepartment[]>;
members(id: string, options?: OrgDepartmentMembersOptions): Promise<OrgPage<OrgMember>>;
managers(id: string, options?: OrgManagerOptions): Promise<readonly OrgManagerTier[]>;
managerChain(id: string, options?: OrgManagerOptions): Promise<OrgManagerChain>;
}
interface OrgPositionsApi {
list(options?: OrgReadOptions): Promise<readonly OrgPosition[]>;
get(id: string, options?: OrgReadOptions): Promise<OrgPosition | null>;
members(id: string, options?: OrgPositionMembersOptions): Promise<OrgPage<OrgMember>>;
}
Mọi method trả dữ liệu đều có overload thứ hai: khi options.withDisplay là literal
true, kiểu kết quả là biến thể <true> của các kiểu bên dưới và các field hiển thị
luôn có mặt. Khi không có option này, các field hiển thị không tồn tại trên kiểu.
interface OrgReadOptions {
readonly withDisplay?: boolean;
readonly language?: string; // ví dụ "vi-VN"; mặc định là ngôn ngữ của invocation
}
interface OrgPageOptions extends OrgReadOptions {
readonly includeSubDepartments?: boolean;
readonly accountOnly?: boolean;
readonly limit?: number; // mặc định 500, tối đa 2000; 200 khi có withDisplay
readonly cursor?: string;
}
interface OrgDepartmentMembersOptions extends OrgPageOptions { readonly positionId?: string; }
interface OrgPositionMembersOptions extends OrgPageOptions { readonly departmentId?: string; }
interface OrgManagerOptions extends OrgReadOptions { readonly accountOnly?: boolean; }
interface OrgPersonnelChainOptions extends OrgManagerOptions { readonly departmentId?: string; }
interface OrgTreeOptions extends OrgReadOptions {
readonly rootId?: string;
readonly depth?: number; // 1 đến 100; mặc định lấy mọi cấp
}
interface OrgIsInDepartmentOptions { readonly includeSubDepartments?: boolean; }
interface OrgIsManagerOfOptions {
readonly departmentId?: string;
readonly directOnly?: boolean;
}
interface OrgPersonnelDisplay {
readonly name: string;
readonly email: string | null;
readonly avatar: string | null; // URL công khai
readonly code: string | null;
}
interface OrgNameDisplay { readonly name: string; }
type OrgMembership<D extends boolean = false> = {
readonly personnelId: string;
readonly departmentId: string;
readonly positionId: string | null;
readonly level: number; // 0 nhân viên, 1 cấp quản lý cao nhất, 2 cao nhì, ...
readonly primary: boolean;
} & (D extends true
? { readonly departmentName: string | null; readonly positionName: string | null }
: {});
type OrgPersonnel<D extends boolean = false> = {
readonly id: string;
readonly accountId: string | null; // null: chưa có tài khoản workspace
readonly memberships: readonly OrgMembership<D>[];
} & (D extends true ? { readonly display: OrgPersonnelDisplay | null } : {});
type OrgMember<D extends boolean = false> = OrgMembership<D> & {
readonly accountId: string | null;
} & (D extends true ? { readonly display: OrgPersonnelDisplay | null } : {});
type OrgDepartment<D extends boolean = false> = {
readonly id: string;
readonly parentId: string | null;
readonly level: number; // 1 với phòng ban gốc
readonly childIds: readonly string[];
readonly positionIds: readonly string[];
} & (D extends true ? { readonly display: OrgNameDisplay | null } : {});
type OrgDepartmentNode<D extends boolean = false> = OrgDepartment<D> & {
readonly children: readonly OrgDepartmentNode<D>[];
};
type OrgPosition<D extends boolean = false> = {
readonly id: string;
readonly departmentOnly: boolean;
readonly departmentIds: readonly string[];
readonly excludedDepartmentIds: readonly string[];
} & (D extends true ? { readonly display: OrgNameDisplay | null } : {});
type OrgManagerTier<D extends boolean = false> = {
readonly departmentId: string;
readonly level: number;
readonly distance: number; // 0 phòng xuất phát, 1 phòng cha, ...
readonly personnelIds: readonly string[];
} & (D extends true ? {
readonly departmentName: string | null;
readonly personnel: readonly { readonly id: string; readonly display: OrgPersonnelDisplay | null }[];
} : {});
interface OrgManagerChain<D extends boolean = false> {
readonly fromDepartmentId: string;
readonly personnelLevel: number;
readonly tiers: readonly OrgManagerTier<D>[];
readonly vacantDepartmentIds: readonly string[];
readonly truncated: boolean;
}
interface OrgPage<T> {
readonly items: readonly T[];
readonly total: number;
readonly nextCursor?: string;
}
interface OrgGetManyResult<T> {
readonly items: readonly T[];
readonly missingIds: readonly string[];
}export default defineScript(async ({ org, input }) => {
const order = input as { ownerId: string; departmentId: string };
// Chỉ cần cấu trúc: trả lời mà không đọc record.
const [chain] = await org.personnel.managerChain(order.ownerId, {
departmentId: order.departmentId,
accountOnly: true,
});
const approverIds = chain?.tiers[0]?.personnelIds ?? [];
// Cần tên để hiển thị: thêm tối đa một lần đọc cho mỗi loại dữ liệu.
const me = await org.me({ withDisplay: true });
return {
approverIds,
greeting: me?.display?.name,
departments: me?.memberships.map(m => m.departmentName) ?? [],
};
});Dữ liệu hiển thị
-
withDisplaythêmdisplayvào nhân sự, phòng ban và vị trí, và thêmdepartmentName/positionNamevào membership. Giá trị lànullkhi không đọc được record tương ứng, ví dụ record vừa bị xoá. -
languagechọn bản dịch tên phòng ban và vị trí, ví dụ"vi-VN"hoặc"en-US"; tag không có vùng ("vi") khớp với bản dịch đầu tiên của ngôn ngữ đó. Mặc định là ngôn ngữ trong membership của user thực hiện invocation, sau đó đến ngôn ngữ của user, rồi của workspace; nếu không có bản dịch phù hợp thì dùng tên đã lưu. -
namecủa nhân sự là họ tên đầy đủ mà workspace hiển thị;emaillà email tài khoản, nếu không có thì là email công việc;avatarlà URL ảnh công khai. - Dữ liệu hiển thị chỉ gồm các field trên và mọi thành viên workspace đều xem được, giống như trong ô chọn người dùng. Mỗi lần gọi tốn tối đa một lần đọc cho mỗi loại dữ liệu và mỗi 200 ID; các giá trị vừa đọc được cache.
org.me(options?)
Trả nhân sự của user thực hiện invocation, hoặc null với invocation system hay
inbound. Method này tương đương org.personnel.get với
invocation.user.membership.personnelId.
org.personnel.get(id, options?) và org.personnel.getMany(ids, options?)
get trả một nhân sự đang hoạt động kèm mọi membership phòng ban, phòng ban chính
đứng đầu, hoặc null khi ID không phải nhân sự đang hoạt động của workspace.
getMany đọc tối đa 200 ID trong một lời gọi: ID trùng được gộp, items giữ thứ tự
request và ID không tồn tại được liệt kê trong missingIds. Nhân sự chưa có tài
khoản workspace có accountId: null; người đã rời workspace không được trả về.
org.departments.get(id, options?), tree(options?) và ancestors(id, options?)
-
gettrả một phòng ban đang hoạt động hoặcnull.childIdstheo thứ tự hiển thị;positionIdslà các vị trí áp dụng cho phòng ban. -
treetrả các phòng ban gốc (hoặc chỉrootId) kèm phòng ban con.depth: 1chỉ trả phòng gốc; dưới độ sâu yêu cầu,childrenrỗng nhưngchildIdsvẫn liệt kê phòng con. Cây có hơn 5000 phòng ban sẽ némValidationError; hãy thu hẹp bằngrootIdhoặcdepth. ancestorstrả phòng cha trước, phòng gốc sau cùng.-
Phòng ban có phòng cha đã ngừng hoạt động hoặc đã xoá được trả như phòng gốc
(
parentId: null).
org.departments.members(id, options?) và org.positions.members(id, options?)
Trả một trang membership: quản lý trước theo cấp, sau đó đến nhân viên. Nhân sự thuộc
nhiều phòng ban trong phạm vi được liệt kê một lần cho mỗi phòng ban.
includeSubDepartments thêm mọi phòng con theo thứ tự cây, positionId chỉ giữ
người giữ vị trí đó, departmentId giới hạn người giữ vị trí trong một phòng ban, và
accountOnly chỉ giữ nhân sự có tài khoản workspace. Truyền nextCursor làm
cursor để đọc trang tiếp; total đếm mọi trang. Kích thước trang mặc định 500 và
tối đa 2000, hoặc tối đa 200 khi có withDisplay.
org.positions.list(options?) và org.positions.get(id, options?)
Trả các vị trí đang hoạt động, vị trí tạo trước đứng trước. Vị trí chỉ áp dụng cho
phòng ban riêng (departmentOnly: true) áp dụng cho departmentIds; vị trí còn lại
áp dụng cho mọi phòng ban trừ excludedDepartmentIds.
Quản lý và chuỗi quản lý
level của membership đánh dấu quản lý: 0 là nhân viên, 1 là cấp quản lý cao
nhất của phòng ban, 2 là cấp cao nhì, và cứ thế tiếp. Nhiều người có thể cùng cấp.
-
org.departments.managers(id, options?)trả quản lý của riêng phòng ban đó, mỗi cấp một tier, cấp1đứng đầu. -
org.departments.managerChain(id, options?)trả các quản lý phía trên một nhân viên của phòng ban, gần nhất trước, đến tận phòng ban gốc. -
org.personnel.managerChain(id, options?)trả một chuỗi cho mỗi phòng ban của nhân sự, phòng ban chính đứng đầu;departmentIdchỉ giữ chuỗi bắt đầu từ phòng ban đó. Kết quả rỗng với nhân sự không tồn tại.
Chuỗi được tạo theo các quy tắc:
-
Trong phòng ban xuất phát, quản lý của nhân sự là những người có số cấp nhỏ hơn cấp
của chính nhân sự đó (mọi quản lý nếu là nhân viên), gần nhất trước: cấp
3, rồi2, rồi1. Trưởng phòng không có quản lý trong phòng của mình. - Sau đó mỗi phòng cha đến tận phòng gốc thêm mọi quản lý của mình, số cấp lớn nhất trước. Mọi quản lý của phòng cha đều đứng trên mọi quản lý của các phòng con.
- Mỗi nhân sự chỉ xuất hiện một lần, ở tier gần nhất, và nhân sự xuất phát không bao giờ được liệt kê.
-
accountOnly: truebỏ qua nhân sự chưa có tài khoản workspace, ví dụ khi chuỗi dùng để chọn người duyệt. -
vacantDepartmentIdsliệt kê các phòng ban đi qua mà không có quản lý hợp lệ nào; chuỗi tiếp tục với phòng cha của chúng. Phòng của chính trưởng phòng không bị coi là trống. -
truncatedlàtruekhi một phòng cha đã ngừng hoạt động, nên chuỗi dừng trước phòng gốc thực sự.
Ví dụ, với ban lãnh đạo công ty (CEO cấp 1, phó CEO cấp 2), khối Kỹ thuật bên
dưới (giám đốc cấp 1) và phòng Kiểm thử thuộc khối Kỹ thuật (trưởng phòng 1, phó
phòng 2, trưởng nhóm 3), chuỗi của một tester là: trưởng nhóm, phó phòng, trưởng
phòng, giám đốc khối, phó CEO, CEO. Chuỗi của phó phòng Kiểm thử là: trưởng phòng,
giám đốc khối, phó CEO, CEO.
org.isInDepartment(personnelId, departmentId, options?) và org.isManagerOf(managerId, personnelId, options?)
isInDepartment cho biết nhân sự có thuộc phòng ban, hoặc một phòng con của nó khi
có includeSubDepartments. isManagerOf cho biết managerId có xuất hiện trong một
chuỗi quản lý của personnelId hay không; departmentId chỉ xét chuỗi bắt đầu từ
phòng ban đó và directOnly chỉ xét tier gần nhất. Cả hai trả false với ID không
tồn tại.
Quy tắc
-
orgdùng được trong script, route, record trigger ở cả hai thời điểm, background job và Development Session. -
orgđi theo danh tính mặc định của lần thực thi: lần thực thi có user hoặc danh tính system đều đọc được. Lần thực thi không có user (background job, inbound webhook, hoặc record trigger do một thao tác ghi của hệ thống gây ra) chỉ đọc được khi identity policy đã duyệt của project đặtallowInternalSystem: true; nếu không, mọi lời gọi trừorg.me()némPermissionDeniedErrorcódetails.reasonlà"IDENTITY_NOT_GRANTED". Khi đóorg.me()trảnullmà không thực hiện lời gọi nào, vì lần thực thi không có user. - Mọi lời gọi trong cùng một lần thực thi đọc cùng một phiên bản cơ cấu tổ chức.
-
ID được SDK kiểm tra và Cogover kiểm tra lại; ID hoặc option không hợp lệ ném
ValidationError. Mọi method đều trả về promise, và đối số không hợp lệ làm promise đó bị reject thay vì ném lỗi ngay khi gọi method. Các methodgettrảnullvới ID không tồn tại;members,managers,managerChain,ancestorsvàtree({ rootId })némNotFoundErrorvớiresourcelà"department"hoặc"position". -
Khi không đọc được cơ cấu tổ chức, lời gọi ném
CogoverApiErrorvới codeORGANIZATION_UNAVAILABLE. -
Lần đọc không có
withDisplaylà một lời gọi cục bộ; lần đọc cówithDisplay: truelà một capability call (xem Giới hạn của một lần thực thi). DùnggetManyhoặcmembersthay vì gọigettrong vòng lặp: mỗi lời gọi tính một lần.
Rate this page
On this page