Explorar el Código

Добавлена оплата за себя

Vadim hace 2 meses
padre
commit
6cf6a6413e

+ 28 - 21
src/api/v_0.1.0/client/client-activities-api.ts

@@ -120,6 +120,29 @@ class ClientActivitiesApi {
     }),
   };
 
+  private actEntityShema = z.union([
+    z.object({
+      pe: z.object({
+        peId: z.string().uuid(),
+        peTypeCode: z.string(),
+        peTypeName: z.string(),
+        name: z.string(),
+        members: z.array(
+          PeMemberWithIdentityShema.extend({
+            isPaid: z.boolean(),
+          }),
+        ),
+      }),
+    }),
+    z.object({
+      user: z.object({
+        userId: z.string().uuid(),
+        isChild: z.boolean(),
+        identity: z.string(),
+      }),
+    }),
+  ]);
+
   GET_ActReg = {
     req: {
       params: z.object({
@@ -132,28 +155,12 @@ class ClientActivitiesApi {
       actReg: z.discriminatedUnion("role", [
         actTypes.ActivityRegWithFields.extend({
           role: z.literal("owner"),
-          pe: z
-            .object({
-              peId: z.string().uuid(),
-              peTypeCode: z.string(),
-              peTypeName: z.string(),
-              name: z.string(),
-              members: z.array(
-                PeMemberWithIdentityShema.extend({
-                  isPaid: z.boolean(),
-                }),
-              ),
-            })
-            .optional(),
-          user: z
-            .object({
-              userId: z.string().uuid(),
-              isChild: z.boolean(),
-              identity: z.string(),
-            })
-            .optional(),
+          entity: this.actEntityShema,
+        }),
+        actTypes.ActivityReg.extend({
+          role: z.enum(["member", "parent"]),
+          entity: this.actEntityShema,
         }),
-        actTypes.ActivityReg.extend({ role: z.literal("member") }),
       ]),
     }),
   };

+ 86 - 57
src/modules/client/activities/c-act-controller.ts

@@ -24,8 +24,8 @@ import { cPeService } from "./participant-entities/c-pe-service.js";
 import { cActService } from "./c-act-service.js";
 import { validatePeForAct } from "./validators/act-pe-validators.js";
 import { generateRandomNumber } from "#utils/other-utils.js";
-import { PeMemberWithIdentityShema } from "#api/v_0.1.0/types/pe-types.js";
 import { cUsersService } from "../users/c-users-service.js";
+import { logger } from "#plugins/logger.js";
 
 class ClientActivitiesController {
   async getEventActivities(
@@ -500,7 +500,7 @@ class ClientActivitiesController {
     );
 
     const user = sessionService.getUserFromReq(req);
-    const role = await cActService.checkActRegOwner(user.userId, activityRegId);
+    const role = await cActService.checkActRegRole(user.userId, activityRegId);
     if (!role) throw ApiError.ForbiddenError();
 
     let actReg: z.infer<
@@ -508,87 +508,116 @@ class ClientActivitiesController {
     > | null;
     if (role === "owner") {
       const r = await cActService.getActRegWithValues(activityRegId);
-      if (!r)
+      if (!r) {
         throw ApiError.BadRequest(
           "actRegNotFound",
           "Регистрация на мероприятии не найдена",
         );
+      }
 
-      let pe:
-        | {
-            peId: string;
-            peTypeCode: string;
-            peTypeName: string;
-            name: string;
-            members: (z.infer<typeof PeMemberWithIdentityShema> & {
-              isPaid: boolean;
-            })[];
-          }
-        | undefined = undefined;
-      let user:
-        | {
-            userId: string;
-            isChild: boolean;
-            identity: string;
-          }
-        | undefined = undefined;
-
+      // регистрация через pe
       if (r.peId) {
-        const _pe = await cPeService.getPeForMember(r.peId);
-        if (!_pe)
+        const pe = await cActService.getPeForActReg({
+          peId: r.peId,
+          activityRegId,
+        });
+        if (!pe)
           throw ApiError.BadRequest(
             "peNotFound",
             "Сущность участия не найдена",
           );
 
-        const m = [
-          ...(await cPeService.getActivePeMembersWithIdentity(r.peId)),
-        ];
-        const peMembers = await Promise.all(
-          m.map(async (m) => ({
-            ...m,
-            // TODO: слишком много операций, проще одним запросом вместо getPeMembersWithIdentity
-            isPaid: await cActService.checkPeMemberActivityRegPayment({
-              peMemberId: m.peMemberId,
-              activityRegId: activityRegId,
-            }),
-          })),
-        );
-        pe = {
-          ..._pe,
-          members: peMembers,
+        actReg = {
+          ...r,
+          entity: { pe },
+          role,
         };
-      } else if (r.isUserReg && r.userId) {
+      }
+      // личная регистрация
+      else if (r.isUserReg && r.userId) {
         const _user = await cUsersService.getUserWithIdentity(r.userId);
         if (!_user)
           throw ApiError.BadRequest("userNotFound", "Пользователь не найден");
 
-        user = _user;
-      } else {
+        actReg = {
+          ...r,
+          entity: { user: _user },
+          role,
+        };
+      }
+      // никакая не регистрация
+      else {
+        logger.error({
+          func: "getActReg1",
+          message: "Регистрация на мероприятии не найдена",
+          activityRegId,
+          userId: user.userId,
+          role,
+        });
         throw ApiError.BadRequest(
           "actRegNotFound",
           "Регистрация на мероприятии не найдена",
         );
       }
-
-      actReg = {
-        ...r,
-        pe,
-        user,
-        role,
-      };
-    } else {
+    }
+    // для члена pe или родителя члена pe
+    // личной регистрации с оплатой за участников быть не должно
+    else {
       const r = await cActService.getActRegForPeMember({ activityRegId });
-      if (!r)
+
+      if (!r) {
         throw ApiError.BadRequest(
           "actRegNotFound",
           "Регистрация на мероприятии не найдена",
         );
+      }
 
-      actReg = {
-        ...r,
-        role,
-      };
+      // регистрация через pe
+      if (r.peId) {
+        const pe = await cActService.getPeForActReg({
+          peId: r.peId,
+          activityRegId,
+        });
+        if (!pe)
+          throw ApiError.BadRequest(
+            "peNotFound",
+            "Сущность участия не найдена",
+          );
+
+        actReg = {
+          ...r,
+          entity: { pe },
+          role,
+        };
+      }
+      // личная регистрация
+      else if (r.isUserReg && r.userId) {
+        logger.error({
+          func: "getActReg2",
+          r,
+          message: "Регистрация личная, но в ней участник не владелец",
+          activityRegId,
+          role,
+          userId: user.userId,
+        });
+        throw ApiError.BadRequest(
+          "actRegNotFound",
+          "Регистрация на мероприятии не найдена",
+        );
+      } else {
+        logger.error({
+          func: "getActReg3",
+          r,
+          message: "Что то очень странное",
+          activityRegId,
+          role,
+          userId: user.userId,
+        });
+        throw ApiError.BadRequest(
+          "actRegNotFound",
+          "Регистрация на мероприятии не найдена",
+        );
+      }
     }
 
     RouterUtils.validAndSendResponse(
@@ -808,7 +837,7 @@ class ClientActivitiesController {
       api.client.activities.DELETE_ActivityReg.req.params.parse(req.params);
 
     const user = sessionService.getUserFromReq(req);
-    const role = await cActService.checkActRegOwner(user.userId, activityRegId);
+    const role = await cActService.checkActRegRole(user.userId, activityRegId);
     if (role !== "owner") throw ApiError.ForbiddenError();
 
     await updPool.transaction(async (tr) => {

+ 86 - 4
src/modules/client/activities/c-act-service.ts

@@ -339,7 +339,7 @@ where
         ar.is_user_reg "isUserReg",
         ar.is_canceled "isCanceled"
       from
-        act.act_regs_with_values ar
+        act.act_regs_with_status ar
       where
         ar.activity_reg_id = ${activityRegId}
     `);
@@ -597,7 +597,7 @@ where
     return !!isPaid;
   }
 
-  async checkActRegOwner(userId: string, activityRegId: string) {
+  async checkActRegRole(userId: string, activityRegId: string) {
     const actReg = await this.getActRegWithValues(activityRegId);
     if (!actReg) {
       throw ApiError.BadRequest("actRegNotFound", "Не найдена регистрация");
@@ -614,12 +614,94 @@ where
       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,
@@ -824,7 +906,7 @@ where
         ar.is_paid "isPaid",
         ar.is_canceled "isCanceled",
         ar.status_history "statusHistory",
-        f.fields "fields",
+        coalesce(f.fields "fields", '[]'::jsonb),
 	      ar.is_user_reg "isUserReg"
       from
         act.act_regs_with_status ar