123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119 |
- import { apiTypes } from "#api/current-api.js";
- import {
- CustomFieldWithUserCopyValue,
- CustomFieldWithValidators,
- CustomFieldWithValidatorsAndValue,
- CustomFieldWithValue,
- } from "#api/v_0.1.0/types/custom-fields-types.js";
- import { DbSchema } from "#db/db-schema.js";
- import { selPool } from "#db/db.js";
- import { ApiError } from "#exceptions/api-error.js";
- import { logger } from "#plugins/logger.js";
- import { DatabaseTransactionConnection, sql } from "slonik";
- import { z } from "zod";
- import { ordersService } from "../shop/orders-service.js";
- import { v7 } from "uuid";
- class CActService {
- async addDataToActValidator(
- validator: z.infer<typeof apiTypes.activities.ActValidator>,
- activityId: string,
- ): Promise<z.infer<typeof apiTypes.activities.ActValidatorWithData>> {
- switch (validator.code) {
- case "max-regs": {
- const currentRegs = await selPool.oneFirst(sql.type(
- z.object({
- count: z.number(),
- }),
- )`
- select
- count(*)
- from
- act.activity_regs
- where
- activity_id = ${activityId}
- `);
- return {
- ...validator,
- serverData: {
- currentRegs,
- },
- };
- }
- default: {
- return validator;
- }
- }
- }
- async addDataToActValidators({
- validators,
- activityId,
- }: {
- validators: z.infer<typeof apiTypes.activities.ActValidator>[];
- activityId: string;
- }) {
- return await Promise.all(
- validators.map(
- async (validator) =>
- await cActService.addDataToActValidator(validator, activityId),
- ),
- );
- }
- async getActRegs(userId: string) {
- const actRegsOwner = await selPool.any(sql.type(
- z.object({
- activityRegId: DbSchema.act.activityRegs.activityRegId,
- activityRegNumber: DbSchema.act.activityRegs.number,
- activityId: DbSchema.act.activityRegs.activityId,
- activityCode: DbSchema.act.activities.code,
- activityPublicName: DbSchema.act.activities.publicName,
- peId: DbSchema.act.activityRegs.peId,
- peName: DbSchema.act.partEntities.name.nullable(),
- peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
- userId: DbSchema.act.activityRegs.userId.nullable(),
- isPaid: DbSchema.act.activityRegs.isPaid,
- isCanceled: DbSchema.act.activityRegs.isCanceled,
- statusHistory: z.array(
- z.object({
- statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
- name: DbSchema.act.actRegStatuses.name,
- code: DbSchema.act.actRegStatuses.code,
- note: DbSchema.act.actRegStatusHistory.note,
- setDate: DbSchema.act.actRegStatusHistory.setDate,
- actRegStatusId: DbSchema.act.actRegStatuses.actRegStatusId,
- color: DbSchema.act.actRegStatuses.color,
- isPaymentOpen: DbSchema.act.actRegStatuses.isPaymentOpen,
- }),
- ),
- isUserReg: DbSchema.act.activities.isUserReg,
- }),
- )`
- select
- ar.activity_reg_id "activityRegId",
- ar.number "activityRegNumber",
- ar.activity_id "activityId",
- ar.activity_code "activityCode",
- ar.activity_public_name "activityPublicName",
- ar.pe_id "peId",
- ar.pe_name "peName",
- ar.pe_owner_id "peOwnerId",
- ar.user_id "userId",
- ar.is_paid "isPaid",
- ar.status_history "statusHistory",
- ar.is_user_reg "isUserReg",
- ar.is_canceled "isCanceled"
- from
- act.act_regs_with_status ar
- where
- ar.user_id = ${userId}
- or
- ar.pe_owner_id = ${userId}
- `);
- const actRegsMember = await selPool.any(sql.type(
- z.object({
- activityRegId: DbSchema.act.activityRegs.activityRegId,
- activityRegNumber: DbSchema.act.activityRegs.number,
- activityId: DbSchema.act.activityRegs.activityId,
- activityCode: DbSchema.act.activities.code,
- activityPublicName: DbSchema.act.activities.publicName,
- peId: DbSchema.act.activityRegs.peId,
- peName: DbSchema.act.partEntities.name.nullable(),
- peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
- userId: DbSchema.act.activityRegs.userId.nullable(),
- isPaid: DbSchema.act.activityRegs.isPaid,
- isCanceled: DbSchema.act.activityRegs.isCanceled,
- statusHistory: z.array(
- z.object({
- statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
- name: DbSchema.act.actRegStatuses.name,
- code: DbSchema.act.actRegStatuses.code,
- note: DbSchema.act.actRegStatusHistory.note,
- setDate: DbSchema.act.actRegStatusHistory.setDate,
- actRegStatusId: DbSchema.act.actRegStatuses.actRegStatusId,
- color: DbSchema.act.actRegStatuses.color,
- isPaymentOpen: DbSchema.act.actRegStatuses.isPaymentOpen,
- }),
- ),
- isUserReg: DbSchema.act.activities.isUserReg,
- }),
- )`
- select
- ar.activity_reg_id "activityRegId",
- ar.number "activityRegNumber",
- ar.activity_id "activityId",
- ar.activity_code "activityCode",
- ar.activity_public_name "activityPublicName",
- ar.pe_id "peId",
- ar.pe_name "peName",
- ar.pe_owner_id "peOwnerId",
- ar.user_id "userId",
- ar.is_paid "isPaid",
- ar.status_history "statusHistory",
- ar.is_user_reg "isUserReg",
- ar.is_canceled "isCanceled"
- from
- act.act_regs_with_status ar
- where
- EXISTS (
- select 1
- from act.pe_members pm_check
- where pm_check.pe_id = ar.pe_id
- and pm_check.user_id = ${userId}
- and pm_check.is_active = true
- )
- `);
- const actRegsChildrenMember = await selPool.any(sql.type(
- z.object({
- activityRegId: DbSchema.act.activityRegs.activityRegId,
- activityRegNumber: DbSchema.act.activityRegs.number,
- activityId: DbSchema.act.activityRegs.activityId,
- activityCode: DbSchema.act.activities.code,
- activityPublicName: DbSchema.act.activities.publicName,
- peId: DbSchema.act.activityRegs.peId,
- peName: DbSchema.act.partEntities.name.nullable(),
- peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
- userId: DbSchema.act.activityRegs.userId.nullable(),
- isPaid: DbSchema.act.activityRegs.isPaid,
- isCanceled: DbSchema.act.activityRegs.isCanceled,
- statusHistory: z.array(
- z.object({
- statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
- name: DbSchema.act.actRegStatuses.name,
- code: DbSchema.act.actRegStatuses.code,
- note: DbSchema.act.actRegStatusHistory.note,
- setDate: DbSchema.act.actRegStatusHistory.setDate,
- actRegStatusId: DbSchema.act.actRegStatuses.actRegStatusId,
- color: DbSchema.act.actRegStatuses.color,
- isPaymentOpen: DbSchema.act.actRegStatuses.isPaymentOpen,
- }),
- ),
- isUserReg: DbSchema.act.activities.isUserReg,
- }),
- )`
- select distinct -- DISTINCT нужен для удаления дубликатов, если несколько детей соответствуют условию
- ar.activity_reg_id "activityRegId",
- ar.number "activityRegNumber",
- ar.activity_id "activityId",
- ar.activity_code "activityCode",
- ar.activity_public_name "activityPublicName",
- ar.pe_id "peId",
- ar.pe_name "peName",
- ar.pe_owner_id "peOwnerId",
- ar.user_id "userId", -- ID пользователя из регистрации
- usr.user_id "childUserId", -- ID ребенка, через которого найдена связь
- ar.is_paid "isPaid",
- ar.status_history "statusHistory",
- ar.is_user_reg "isUserReg",
- ar.is_canceled "isCanceled"
- from
- act.act_regs_with_status ar
- join
- act.pe_members pm on ar.pe_id = pm.pe_id -- Присоединяем участников по pe_id
- join
- usr.users usr on pm.user_id = usr.user_id -- Присоединяем пользователей, чтобы проверить, является ли участник ребенком
- where
- pm.is_active = true
- and usr.is_child = true
- and usr.parent_id = ${userId}; -- Фильтруем по ID родителя
- `);
- return {
- owner: [...actRegsOwner],
- member: [...actRegsMember],
- childrenMember: [...actRegsChildrenMember],
- };
- }
- async getActRegWithValues(activityRegId: string) {
- const actReg = await selPool.maybeOne(sql.type(
- z.object({
- activityRegId: DbSchema.act.activityRegs.activityRegId,
- activityRegNumber: DbSchema.act.activityRegs.number,
- activityId: DbSchema.act.activityRegs.activityId,
- activityCode: DbSchema.act.activities.code,
- activityPublicName: DbSchema.act.activities.publicName,
- peId: DbSchema.act.activityRegs.peId,
- peName: DbSchema.act.partEntities.name.nullable(),
- peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
- userId: DbSchema.act.activityRegs.userId.nullable(),
- isPaid: DbSchema.act.activityRegs.isPaid,
- isCanceled: DbSchema.act.activityRegs.isCanceled,
- statusHistory: z.array(
- z.object({
- statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
- name: DbSchema.act.actRegStatuses.name,
- code: DbSchema.act.actRegStatuses.code,
- note: DbSchema.act.actRegStatusHistory.note,
- setDate: DbSchema.act.actRegStatusHistory.setDate,
- actRegStatusId: DbSchema.act.actRegStatuses.actRegStatusId,
- color: DbSchema.act.actRegStatuses.color,
- isPaymentOpen: DbSchema.act.actRegStatuses.isPaymentOpen,
- }),
- ),
- fields: z.array(
- CustomFieldWithValue.extend({
- arffId: DbSchema.act.activityRegFormFields.arffId,
- isChangeResetStatus:
- DbSchema.act.activityRegFormFields.isChangeResetStatus,
- }),
- ),
- isUserReg: DbSchema.act.activities.isUserReg,
- }),
- )`
- select
- ar.activity_reg_id "activityRegId",
- ar.number "activityRegNumber",
- ar.activity_id "activityId",
- ar.activity_code "activityCode",
- ar.activity_public_name "activityPublicName",
- ar.pe_id "peId",
- ar.pe_name "peName",
- ar.pe_owner_id "peOwnerId",
- ar.user_id "userId",
- ar.is_paid "isPaid",
- ar.status_history "statusHistory",
- ar.fields "fields",
- ar.is_user_reg "isUserReg",
- ar.is_canceled "isCanceled"
- from
- act.act_regs_with_values ar
- where
- ar.activity_reg_id = ${activityRegId}
- `);
- return actReg;
- }
- async getActRegForPeMember({
- activityRegId,
- tr,
- }: {
- activityRegId: string;
- tr?: DatabaseTransactionConnection;
- }) {
- const db = this.getConnection(tr);
- const actReg = await db.maybeOne(sql.type(
- z.object({
- activityRegId: DbSchema.act.activityRegs.activityRegId,
- activityRegNumber: DbSchema.act.activityRegs.number,
- activityId: DbSchema.act.activityRegs.activityId,
- activityCode: DbSchema.act.activities.code,
- activityPublicName: DbSchema.act.activities.publicName,
- peId: DbSchema.act.activityRegs.peId,
- peName: DbSchema.act.partEntities.name.nullable(),
- peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
- userId: DbSchema.act.activityRegs.userId.nullable(),
- isPaid: DbSchema.act.activityRegs.isPaid,
- isCanceled: DbSchema.act.activityRegs.isCanceled,
- statusHistory: z.array(
- z.object({
- statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
- name: DbSchema.act.actRegStatuses.name,
- code: DbSchema.act.actRegStatuses.code,
- note: DbSchema.act.actRegStatusHistory.note,
- setDate: DbSchema.act.actRegStatusHistory.setDate,
- actRegStatusId: DbSchema.act.actRegStatuses.actRegStatusId,
- color: DbSchema.act.actRegStatuses.color,
- isPaymentOpen: DbSchema.act.actRegStatuses.isPaymentOpen,
- }),
- ),
- isUserReg: DbSchema.act.activities.isUserReg,
- }),
- )`
- select
- ar.activity_reg_id "activityRegId",
- ar.number "activityRegNumber",
- ar.activity_id "activityId",
- ar.activity_code "activityCode",
- ar.activity_public_name "activityPublicName",
- ar.pe_id "peId",
- ar.pe_name "peName",
- ar.pe_owner_id "peOwnerId",
- ar.user_id "userId",
- ar.is_paid "isPaid",
- ar.status_history "statusHistory",
- ar.is_user_reg "isUserReg",
- ar.is_canceled "isCanceled"
- from
- act.act_regs_with_status ar
- where
- ar.activity_reg_id = ${activityRegId}
- `);
- return actReg;
- }
- async getInitialRegStatusId(activityId: string) {
- const initialRegStatusId = await selPool.oneFirst(sql.type(
- z.object({
- initialRegStatusId: DbSchema.act.activities.initialRegStatusId,
- }),
- )`
- select
- initial_reg_status_id "initialRegStatusId"
- from
- act.activities
- where
- activity_id = ${activityId}
- `);
- return initialRegStatusId;
- }
- async getActivity({
- activityCode,
- tr,
- }: {
- activityCode: string;
- tr?: DatabaseTransactionConnection;
- }) {
- const db = this.getConnection(tr);
- return await db.maybeOne(sql.type(
- z.object({
- activityId: DbSchema.act.activities.activityId,
- code: DbSchema.act.activities.code,
- publicName: DbSchema.act.activities.publicName,
- eventInstId: DbSchema.act.activities.eventInstId,
- categoryId: DbSchema.act.activities.categoryId,
- isUserReg: DbSchema.act.activities.isUserReg,
- paymentConfig: DbSchema.act.activities.paymentConfig,
- registrationProductId: DbSchema.act.activities.registrationProductId,
- participantProductId: DbSchema.act.activities.participantProductId,
- nextRegStatusIdAfterPayment:
- DbSchema.act.activities.nextRegStatusIdAfterPayment,
- }),
- )`
- select
- a.activity_id "activityId",
- a.code "code",
- a.public_name "publicName",
- a.event_inst_id "eventInstId",
- a.category_id "categoryId",
- a.is_user_reg "isUserReg",
- a.payment_config "paymentConfig",
- a.registration_product_id "registrationProductId",
- a.participant_product_id "participantProductId",
- a.next_reg_status_id_after_payment "nextRegStatusIdAfterPayment"
- from
- act.activities a
- where
- a.code = ${activityCode}
- `);
- }
- async checkActivityRegNumber(activityRegNumber: string) {
- const isExist = await selPool.exists(sql.unsafe`
- select
- number
- from
- act.activity_regs
- where
- number = ${activityRegNumber}
- `);
- return !!isExist;
- }
- async updateActRegPaymentStatus({
- tr,
- activityRegId,
- }: {
- tr: DatabaseTransactionConnection;
- activityRegId: string;
- }) {
- logger.info(`Обновление статуса оплаты для регистрации ${activityRegId}`);
- const actReg = await this.getActRegForPeMember({ activityRegId, tr });
- if (!actReg) {
- throw ApiError.BadRequest("actRegNotFound", "Не найдена регистрация");
- }
- const activity = await this.getActivity({
- activityCode: actReg.activityCode,
- tr,
- });
- if (!activity) {
- throw ApiError.BadRequest("activityNotFound", "Не найдена активность");
- }
- // оплата за всю регистрацию
- if (activity.paymentConfig === "PER_REGISTRATION") {
- const isPaid = await this.checkActivityRegPayment({
- activityRegId,
- tr,
- });
- // если надо поменять
- if (actReg.isPaid !== isPaid) {
- if (isPaid) {
- await tr.query(sql.unsafe`
- update act.activity_regs
- set is_paid = true
- where activity_reg_id = ${activityRegId}
- `);
- await tr.query(sql.unsafe`
- insert into act.act_reg_status_history (
- activity_reg_id,
- act_reg_status_id,
- note
- )
- values (
- ${activityRegId},
- ${activity.nextRegStatusIdAfterPayment},
- 'Оплачено'
- )
- `);
- } else {
- // такого по идее не должно быть
- logger.error("isPaid !== actReg.isPaid", {
- isPaid,
- actReg,
- activity,
- });
- }
- }
- // TODO: QR
- }
- // оплата за каждого участника
- if (activity.paymentConfig === "PER_PARTICIPANT") {
- if (!actReg.peId) {
- throw Error("peId not found");
- }
- const isAllPaid = await this.checkMembersPayment({
- activityRegId,
- peId: actReg.peId,
- tr,
- });
- // если надо поменять
- if (isAllPaid !== actReg.isPaid) {
- if (!isAllPaid) {
- await tr.query(sql.unsafe`
- update act.activity_regs
- set is_paid = false
- where activity_reg_id = ${activityRegId}
- `);
- // TODO: Возможно стоит добавить в act.activities поле payment_status_id
- await tr.query(sql.unsafe`
- insert into act.act_reg_status_history (
- activity_reg_id,
- act_reg_status_id,
- note
- )
- values (
- ${activityRegId},
- 'd6d27702-cded-4625-be07-e339c4003c2f',
- 'Оплачены не все участники'
- )
- `);
- } else {
- await tr.query(sql.unsafe`
- update act.activity_regs
- set is_paid = true
- where activity_reg_id = ${activityRegId}
- `);
- await tr.query(sql.unsafe`
- insert into act.act_reg_status_history (
- activity_reg_id,
- act_reg_status_id,
- note
- )
- values (
- ${activityRegId},
- ${activity.nextRegStatusIdAfterPayment},
- 'Оплачены все участники'
- )
- `);
- }
- }
- }
- }
- private getConnection(connection?: DatabaseTransactionConnection) {
- return connection || selPool;
- }
- async checkMembersPayment({
- peId,
- activityRegId,
- tr,
- }: {
- peId: string;
- activityRegId: string;
- tr?: DatabaseTransactionConnection;
- }) {
- const db = this.getConnection(tr);
- const members = await db.any(sql.type(
- z.object({
- peMemberId: DbSchema.act.peMembers.peMemberId,
- userId: DbSchema.act.peMembers.userId,
- }),
- )`
- select
- pm.pe_member_id "peMemberId",
- pm.user_id "userId"
- from
- act.pe_members pm
- where
- pm.pe_id = ${peId}
- and pm.is_active = true
- `);
- const memberIds = members.map((member) => member.peMemberId);
- const paidMemberRows = await db.any(sql.unsafe`
- select distinct
- oi.pe_member_id -- Выбираем ID тех, кто заплатил
- from
- shop.order_items oi
- where
- oi.pe_member_id = ANY(${sql.array(memberIds, "uuid")})
- and oi.status = 'PAID'
- and oi.activity_reg_id = ${activityRegId}
- `);
- return memberIds.length === paidMemberRows.length;
- }
- async checkActivityRegPayment({
- activityRegId,
- tr,
- }: {
- activityRegId: string;
- tr?: DatabaseTransactionConnection;
- }) {
- const db = this.getConnection(tr);
- const isPaid = await db.exists(sql.unsafe`
- select 1
- from shop.order_items oi
- where oi.activity_reg_id = ${activityRegId}
- and oi.status = 'PAID'
- `);
- return !!isPaid;
- }
- async checkActRegRole(userId: string, activityRegId: string) {
- const actReg = await this.getActRegWithValues(activityRegId);
- if (!actReg) {
- throw ApiError.BadRequest("actRegNotFound", "Не найдена регистрация");
- }
- if (actReg.peOwnerId === userId || actReg.userId === userId) {
- return "owner";
- }
- const isMemeber = await selPool.exists(sql.unsafe`
- select 1
- from act.pe_members
- where pe_id = ${actReg.peId}
- and user_id = ${userId}
- and is_active = true
- `);
- if (isMemeber) return "member";
- const isParent = await selPool.exists(sql.unsafe`
- select 1
- from act.pe_members m
- join usr.users u on
- m.user_id = u.user_id and
- u.parent_id = ${userId} and
- u.is_child = true
- where
- m.pe_id = ${actReg.peId}
- and m.is_active = true
- `);
- if (isParent) return "parent";
- return undefined;
- }
- async getPeForActReg({
- peId,
- activityRegId,
- }: {
- peId: string;
- activityRegId: string;
- }) {
- return await selPool.maybeOne(sql.type(
- z.object({
- peId: DbSchema.act.partEntities.peId,
- peTypeId: DbSchema.act.partEntities.peTypeId,
- peTypeCode: DbSchema.act.peTypes.code,
- peTypeName: DbSchema.act.peTypes.name,
- name: DbSchema.act.partEntities.name,
- eventInstId: DbSchema.act.partEntities.eventInstId,
- ownerId: DbSchema.act.partEntities.ownerId,
- ownerIdentity: z.string(),
- members: z.array(
- z.object({
- peMemberId: DbSchema.act.peMembers.peMemberId,
- userId: DbSchema.act.peMembers.userId,
- identity: z.string(),
- isPaid: z.boolean(),
- }),
- ),
- }),
- )`
- select
- pe.pe_id "peId",
- pt.pe_type_id "peTypeId",
- pt.code "peTypeCode",
- pt.name "peTypeName",
- pe.event_inst_id "eventInstId",
- pe.owner_id "ownerId",
- pe.name,
- ui.identity "ownerIdentity",
- coalesce(m.members, '[]'::jsonb) "members"
- from
- act.part_entities pe
- left join ev.users_identity ui on
- ui.user_id = pe.owner_id
- left join act.pe_types pt on
- pt.pe_type_id = pe.pe_type_id
- -- members
- left join lateral (
- select
- jsonb_agg(jsonb_build_object(
- 'peMemberId', pm.pe_member_id,
- 'userId', pm.user_id,
- 'identity', ui.identity,
- 'isPaid', oi.order_item_id is not null
- )) as members
- from
- act.pe_members pm
- left join ev.users_identity ui on
- ui.user_id = pm.user_id
- -- is_paid
- left join shop.order_items oi on
- oi.pe_member_id = pm.pe_member_id and
- oi.activity_reg_id = ${activityRegId} and
- oi.status = 'PAID'
- where
- pm.pe_id = ${peId} and
- pm.is_active = true
- ) m on true
- where
- pe.pe_id = ${peId}
- `);
- }
- async checkPeMemberActivityRegPayment({
- peMemberId,
- activityRegId,
- }: {
- peMemberId: string;
- activityRegId: string;
- }) {
- const isPaid = await selPool.exists(sql.unsafe`
- select 1
- from shop.order_items oi
- where oi.pe_member_id = ${peMemberId}
- and oi.activity_reg_id = ${activityRegId}
- and oi.status = 'PAID'
- `);
- return !!isPaid;
- }
- async getActRegDataWithUserCopyValuesAndActValidators(
- userId: string,
- eventId: string,
- activityCode: string,
- ) {
- return await selPool.maybeOne(sql.type(
- z.object({
- activityId: DbSchema.act.activities.activityId,
- code: DbSchema.act.activities.code,
- publicName: DbSchema.act.activities.publicName,
- eventInstId: DbSchema.act.activities.eventInstId,
- categoryId: DbSchema.act.activities.categoryId,
- categoryCode: DbSchema.act.activityCategories.code,
- validators: z.array(apiTypes.activities.ActValidator),
- peTypes: z.array(
- z.object({
- peTypeId: DbSchema.act.peTypes.peTypeId,
- code: DbSchema.act.peTypes.code,
- name: DbSchema.act.peTypes.name,
- }),
- ),
- fields: z.array(
- CustomFieldWithUserCopyValue.extend({ arffId: z.string() }),
- ),
- isUserReg: DbSchema.act.activities.isUserReg,
- }),
- )`
- select
- a.activity_id "activityId",
- a.code,
- a.public_name "publicName",
- a.event_inst_id "eventInstId",
- a.category_id "categoryId",
- a.category_code "categoryCode",
- a.validators,
- a.pe_types "peTypes",
- coalesce(f.fields, '[]'::jsonb) "fields",
- a.is_user_reg "isUserReg"
- from
- act.act_with_validators a
- left join lateral (
- select
- jsonb_agg(jsonb_build_object(
- 'fieldDefinitionId', f.field_definition_id,
- 'arffId', af.arff_id,
- 'isCopyUserValue', af.is_copy_user_value,
- 'code', f.code,
- 'userCopyValue', ufwv.value,
- 'fieldTypeCode', f.field_type_code,
- 'title', COALESCE(af.field_title_override, f.title),
- 'mask', f.mask,
- 'options', f."options",
- 'validators', f.validators,
- 'orderNumber', af.order_number
- )) as fields
- from
- act.activity_reg_form_fields af
- left join cf.custom_fields_with_validators f on
- f.field_definition_id = af.field_definition_id
- -- значение из профиля юзера
- left join ev.user_fields_with_values ufwv on
- af.field_definition_id = ufwv.field_definition_id
- and ufwv.user_id = ${userId}
- and ufwv.event_id = ${eventId}
- and ufwv.value is not null
- -- только если нужно копировать
- and af.is_copy_user_value = true
- where
- af.activity_id = a.activity_id
- ) f on true
- where a.code = ${activityCode}
- `);
- }
- async getActRegDataWithFieldsAndValidatorsAndActValidators(
- activityCode: string,
- ) {
- return await selPool.maybeOne(sql.type(
- z.object({
- activityId: DbSchema.act.activities.activityId,
- code: DbSchema.act.activities.code,
- publicName: DbSchema.act.activities.publicName,
- eventInstId: DbSchema.act.activities.eventInstId,
- categoryId: DbSchema.act.activities.categoryId,
- categoryCode: DbSchema.act.activityCategories.code,
- validators: z.array(apiTypes.activities.ActValidator),
- peTypes: z.array(
- z.object({
- peTypeId: DbSchema.act.peTypes.peTypeId,
- code: DbSchema.act.peTypes.code,
- name: DbSchema.act.peTypes.name,
- }),
- ),
- fields: z.array(
- CustomFieldWithValidators.extend({ arffId: z.string() }),
- ),
- isUserReg: DbSchema.act.activities.isUserReg,
- }),
- )`
- select
- a.activity_id "activityId",
- a.code,
- a.public_name "publicName",
- a.event_inst_id "eventInstId",
- a.category_id "categoryId",
- a.category_code "categoryCode",
- a.validators,
- a.pe_types "peTypes",
- coalesce(f.fields, '[]'::jsonb) "fields",
- a.is_user_reg "isUserReg"
- from
- act.act_with_validators a
- left join lateral (
- select
- jsonb_agg(jsonb_build_object(
- 'fieldDefinitionId', f.field_definition_id,
- 'arffId', af.arff_id,
- 'isCopyUserValue', af.is_copy_user_value,
- 'code', f.code,
- 'fieldTypeCode', f.field_type_code,
- 'title', COALESCE(af.field_title_override, f.title),
- 'mask', f.mask,
- 'options', f."options",
- 'validators', f.validators,
- 'orderNumber', af.order_number
- )) as fields
- from
- act.activity_reg_form_fields af
- left join cf.custom_fields_with_validators f on
- f.field_definition_id = af.field_definition_id
- where
- af.activity_id = a.activity_id
- ) f on true
- where a.code = ${activityCode}
- `);
- }
- async getActRegWithFieldsAndValuesWithValidators(activityRegId: string) {
- return selPool.maybeOne(sql.type(
- z.object({
- activityRegId: DbSchema.act.activityRegs.activityRegId,
- activityRegNumber: DbSchema.act.activityRegs.number,
- activityId: DbSchema.act.activityRegs.activityId,
- activityCode: DbSchema.act.activities.code,
- activityPublicName: DbSchema.act.activities.publicName,
- peId: DbSchema.act.activityRegs.peId,
- peName: DbSchema.act.partEntities.name.nullable(),
- peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
- userId: DbSchema.act.activityRegs.userId.nullable(),
- isPaid: DbSchema.act.activityRegs.isPaid,
- isCanceled: DbSchema.act.activityRegs.isCanceled,
- statusHistory: z.array(
- z.object({
- statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
- name: DbSchema.act.actRegStatuses.name,
- code: DbSchema.act.actRegStatuses.code,
- note: DbSchema.act.actRegStatusHistory.note,
- setDate: DbSchema.act.actRegStatusHistory.setDate,
- actRegStatusId: DbSchema.act.actRegStatuses.actRegStatusId,
- color: DbSchema.act.actRegStatuses.color,
- isPaymentOpen: DbSchema.act.actRegStatuses.isPaymentOpen,
- }),
- ),
- fields: z.array(
- CustomFieldWithValidatorsAndValue.extend({
- arffId: DbSchema.act.activityRegFormFields.arffId,
- isChangeResetStatus:
- DbSchema.act.activityRegFormFields.isChangeResetStatus,
- }),
- ),
- isUserReg: DbSchema.act.activities.isUserReg,
- }),
- )`
- select
- ar.activity_reg_id "activityRegId",
- ar.number "activityRegNumber",
- ar.activity_id "activityId",
- ar.activity_code "activityCode",
- ar.activity_public_name "activityPublicName",
- ar.pe_id "peId",
- ar.pe_name "peName",
- ar.pe_owner_id "peOwnerId",
- ar.user_id "userId",
- ar.is_paid "isPaid",
- ar.is_canceled "isCanceled",
- ar.status_history "statusHistory",
- coalesce(f.fields "fields", '[]'::jsonb),
- ar.is_user_reg "isUserReg"
- from
- act.act_regs_with_status ar
- left join lateral (
- select
- jsonb_agg(jsonb_build_object(
- 'fieldDefinitionId', cfd.field_definition_id,
- 'arffId', f_1.arff_id,
- 'isCopyUserValue', f_1.is_copy_user_value,
- 'code', cfd.code,
- 'value', afv.value,
- 'fieldTypeCode', ft.code,
- 'title', coalesce(f_1.field_title_override, cfd.title),
- 'mask', cfd.mask,
- 'options', cfd.options,
- 'isChangeResetStatus', f_1.is_change_reset_status,
- 'validators', cfwv.validators,
- 'orderNumber', f_1.order_number
- )) as fields
- from
- act.activity_reg_form_fields f_1
- left join cf.custom_field_definitions cfd on
- f_1.field_definition_id = cfd.field_definition_id
- left join cf.field_types ft on
- cfd.field_type_id = ft.field_type_id
- left join act.ar_field_values afv on
- f_1.arff_id = afv.arff_id
- and afv.activity_reg_id = ar.activity_reg_id
- left join cf.custom_fields_with_validators cfwv on
- cfwv.field_definition_id = cfd.field_definition_id
- where
- f_1.activity_id = ar.activity_id) f on
- true
- where ar.activity_reg_id = ${activityRegId}
- `);
- }
- async refundByPeMemberId(peMember: {
- peMemberId: string;
- peId: string;
- userId: string;
- }) {
- const actRegs = await selPool.any(sql.type(
- z.object({
- activityRegId: DbSchema.act.activityRegs.activityRegId,
- activityId: DbSchema.act.activityRegs.activityId,
- }),
- )`
- select
- r.activity_reg_id "activityRegId",
- r.activity_id "activityId"
- from
- act.activity_regs r
- left join act.activities a on
- a.activity_id = r.activity_id and
- a.payment_config = 'PER_PARTICIPANT'
- where
- pe_id = ${peMember.peId}
- `);
- for (const actReg of actRegs) {
- const orderItem = await selPool.maybeOne(sql.type(
- z.object({
- orderItemId: DbSchema.shop.orderItems.orderItemId,
- orderId: DbSchema.shop.orderItems.orderId,
- productId: DbSchema.shop.orderItems.productId,
- unitPrice: DbSchema.shop.orderItems.unitPrice,
- }),
- )`
- select
- oi.order_item_id "orderItemId",
- oi.order_id "orderId",
- oi.product_id "productId",
- oi.unit_price::float "unitPrice"
- from
- shop.order_items oi
- where
- oi.activity_reg_id = ${actReg.activityRegId} and
- oi.pe_member_id = ${peMember.peMemberId} and
- oi.status = 'PAID'
- `);
- if (!orderItem) {
- logger.error(
- `Order item for activity reg ${actReg.activityRegId} and pe member ${peMember.peMemberId} not found`,
- );
- throw new Error("Order item not found");
- }
- await ordersService.refundOrderItem(orderItem.orderItemId);
- }
- }
- async getActivityRegsByPeId(peId: string) {
- return await selPool.any(sql.type(
- z.object({
- activityRegId: DbSchema.act.activityRegs.activityRegId,
- activityId: DbSchema.act.activityRegs.activityId,
- activityRegNumber: DbSchema.act.activityRegs.number,
- }),
- )`
- select
- r.activity_reg_id "activityRegId",
- r.activity_id "activityId",
- r.number "activityRegNumber"
- from
- act.activity_regs r
- where
- pe_id = ${peId}
- `);
- }
- async refundByActivityRegId(activityRegId: string) {
- const activityId = await selPool.maybeOneFirst(sql.type(
- z.object({
- activityId: DbSchema.act.activityRegs.activityId,
- }),
- )`
- select
- r.activity_id "activityId"
- from
- act.activity_regs r
- left join act.activities a on
- a.activity_id = r.activity_id
- where
- r.activity_reg_id = ${activityRegId}
- `);
- if (!activityId) {
- throw new Error("Activity reg not found");
- }
- const orderItems = await selPool.any(sql.type(
- z.object({
- orderItemId: DbSchema.shop.orderItems.orderItemId,
- orderId: DbSchema.shop.orderItems.orderId,
- }),
- )`
- select
- oi.order_item_id "orderItemId",
- oi.order_id "orderId"
- from
- shop.order_items oi
- where
- oi.activity_reg_id = ${activityRegId}
- `);
- for (const orderItem of orderItems) {
- await ordersService.refundOrderItem(orderItem.orderItemId);
- }
- }
- async resetAllActivityRegsByPe(
- tr: DatabaseTransactionConnection,
- peid: string,
- ) {
- const actRegs = await this.getActivityRegsByPeId(peid);
- for (const actReg of actRegs) {
- const initialRegStatusId = await this.getInitialRegStatusId(
- actReg.activityId,
- );
- await tr.query(sql.unsafe`
- insert into act.act_reg_status_history
- (act_reg_status_history_id, act_reg_id, act_reg_status_id, note)
- values
- (${v7()}, ${actReg.activityRegId}, ${initialRegStatusId}, 'Изменена сущность участия ${peid}')
- `);
- }
- }
- async getActWithActValidators(activityCode: string) {
- return await selPool.maybeOne(sql.type(
- z.object({
- activityId: DbSchema.act.activities.activityId,
- code: DbSchema.act.activities.code,
- publicName: DbSchema.act.activities.publicName,
- eventInstId: DbSchema.act.activities.eventInstId,
- categoryId: DbSchema.act.activities.categoryId,
- categoryCode: DbSchema.act.activityCategories.code,
- validators: z.array(apiTypes.activities.ActValidator),
- peTypes: z.array(
- z.object({
- peTypeId: DbSchema.act.peTypes.peTypeId,
- code: DbSchema.act.peTypes.code,
- name: DbSchema.act.peTypes.name,
- }),
- ),
- isUserReg: DbSchema.act.activities.isUserReg,
- }),
- )`
- select
- a.activity_id "activityId",
- a.code,
- a.public_name "publicName",
- a.event_inst_id "eventInstId",
- a.category_id "categoryId",
- a.category_code "categoryCode",
- a.validators,
- a.pe_types "peTypes",
- a.is_user_reg "isUserReg"
- from
- act.act_with_validators a
- where a.code = ${activityCode}
- `);
- }
- }
- export const cActService = new CActService();
|