Explorar o código

Обёртка в транзакции

Vadim hai 2 meses
pai
achega
c8a0f87599

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

@@ -578,7 +578,7 @@ class ClientActivitiesController {
         role,
       };
     } else {
-      const r = await cActService.getActRegForPeMember(activityRegId);
+      const r = await cActService.getActRegForPeMember({ activityRegId });
       if (!r)
         throw ApiError.BadRequest(
           "actRegNotFound",
@@ -604,7 +604,7 @@ class ClientActivitiesController {
   async getActivity(req: Request, res: Response) {
     const { activityCode } =
       api.client.activities.GET_Activity.req.params.parse(req.params);
-    const act = await cActService.getActivity(activityCode);
+    const act = await cActService.getActivity({ activityCode });
 
     if (!act)
       throw ApiError.BadRequest("actNotFound", "Мероприятие не найдено");
@@ -658,7 +658,7 @@ class ClientActivitiesController {
     const files = req.files;
     const user = sessionService.getUserFromReq(req);
 
-    const actReg = await cActService.getActRegForPeMember(activityRegId);
+    const actReg = await cActService.getActRegForPeMember({ activityRegId });
     if (!actReg)
       throw ApiError.BadRequest(
         "actRegNotFound",

+ 65 - 23
src/modules/client/activities/c-act-service.ts

@@ -6,7 +6,7 @@ import {
   CustomFieldWithValue,
 } from "#api/v_0.1.0/types/custom-fields-types.js";
 import { DbSchema } from "#db/db-schema.js";
-import { selPool, updPool } from "#db/db.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";
@@ -288,8 +288,15 @@ where
     return actReg;
   }
 
-  async getActRegForPeMember(activityRegId: string) {
-    const actReg = await selPool.maybeOne(sql.type(
+  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,
@@ -355,8 +362,15 @@ where
     return initialRegStatusId;
   }
 
-  async getActivity(activityCode: string) {
-    return await selPool.maybeOne(sql.type(
+  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,
@@ -401,13 +415,23 @@ where
     return !!isExist;
   }
 
-  async updateActRegPaymentStatus(activityRegId: string) {
-    const actReg = await this.getActRegForPeMember(activityRegId);
+  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(actReg.activityCode);
+    const activity = await this.getActivity({
+      activityCode: actReg.activityCode,
+      tr,
+    });
     if (!activity) {
       throw ApiError.BadRequest("activityNotFound", "Не найдена активность");
     }
@@ -416,17 +440,18 @@ where
     if (activity.paymentConfig === "PER_REGISTRATION") {
       const isPaid = await this.checkActivityRegPayment({
         activityRegId,
+        tr,
       });
       // если надо поменять
       if (actReg.isPaid !== isPaid) {
         if (isPaid) {
-          await updPool.query(sql.unsafe`
+          await tr.query(sql.unsafe`
           update act.activity_regs
           set is_paid = true
           where activity_reg_id = ${activityRegId}
         `);
 
-          await updPool.query(sql.unsafe`
+          await tr.query(sql.unsafe`
           insert into act.act_reg_status_history (
             activity_reg_id,
             act_reg_status_id,
@@ -460,19 +485,20 @@ where
       const isAllPaid = await this.checkMembersPayment({
         activityRegId,
         peId: actReg.peId,
+        tr,
       });
 
       // если надо поменять
       if (isAllPaid !== actReg.isPaid) {
         if (!isAllPaid) {
-          await updPool.query(sql.unsafe`
+          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 updPool.query(sql.unsafe`
+          await tr.query(sql.unsafe`
           insert into act.act_reg_status_history (
             activity_reg_id,
             act_reg_status_id,
@@ -485,12 +511,12 @@ where
           )
         `);
         } else {
-          await updPool.query(sql.unsafe`
+          await tr.query(sql.unsafe`
           update act.activity_regs
           set is_paid = true
           where activity_reg_id = ${activityRegId}
         `);
-          await updPool.query(sql.unsafe`
+          await tr.query(sql.unsafe`
           insert into act.act_reg_status_history (
             activity_reg_id,
             act_reg_status_id,
@@ -507,14 +533,21 @@ where
     }
   }
 
+  private getConnection(connection?: DatabaseTransactionConnection) {
+    return connection || selPool;
+  }
+
   async checkMembersPayment({
     peId,
     activityRegId,
+    tr,
   }: {
     peId: string;
     activityRegId: string;
+    tr?: DatabaseTransactionConnection;
   }) {
-    const members = await selPool.any(sql.type(
+    const db = this.getConnection(tr);
+    const members = await db.any(sql.type(
       z.object({
         peMemberId: DbSchema.act.peMembers.peMemberId,
         userId: DbSchema.act.peMembers.userId,
@@ -532,7 +565,7 @@ where
 
     const memberIds = members.map((member) => member.peMemberId);
 
-    const paidMemberRows = await selPool.any(sql.unsafe`
+    const paidMemberRows = await db.any(sql.unsafe`
       select distinct
         oi.pe_member_id  -- Выбираем ID тех, кто заплатил
       from
@@ -546,8 +579,15 @@ where
     return memberIds.length === paidMemberRows.length;
   }
 
-  async checkActivityRegPayment({ activityRegId }: { activityRegId: string }) {
-    const isPaid = await selPool.exists(sql.unsafe`
+  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}
@@ -801,7 +841,8 @@ where
                   'mask', cfd.mask, 
                   'options', cfd.options, 
                   'isChangeResetStatus', f_1.is_change_reset_status,
-                      'validators', cfwv.validators
+                  'validators', cfwv.validators,
+                  'orderNumber', f_1.order_number
                     )) as fields
         from
           act.activity_reg_form_fields f_1
@@ -862,10 +903,14 @@ where
         shop.order_items oi
       where
         oi.activity_reg_id = ${actReg.activityRegId} and
-        oi.pe_member_id = ${peMember.peMemberId}
+        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");
       }
 
@@ -916,9 +961,6 @@ where
       z.object({
         orderItemId: DbSchema.shop.orderItems.orderItemId,
         orderId: DbSchema.shop.orderItems.orderId,
-        paymentId: DbSchema.shop.payments.paymentId,
-        paymentExternalTransactionId:
-          DbSchema.shop.payments.externalTransactionId,
       }),
     )`
       select

+ 16 - 16
src/modules/client/activities/participant-entities/c-pe-controller.ts

@@ -506,7 +506,7 @@ class ClientPeController {
       `);
       }
 
-      await cPeService.updateAllActRegStatusByPe(peId);
+      await cPeService.updateAllActRegStatusByPe({ peId, tr });
     });
 
     RouterUtils.validAndSendResponse(api.client.pe.POST_JoinToPe.res, res, {
@@ -760,7 +760,7 @@ class ClientPeController {
 
     const user = sessionService.getUserFromReq(req);
     const peIdsToRecheck: Set<string> = new Set();
-    await updPool.transaction(async (t) => {
+    await updPool.transaction(async (tr) => {
       for (const r of requests) {
         const request = await cPeService.getPeMemberRequest(
           r.peMemberRequestId,
@@ -789,7 +789,7 @@ class ClientPeController {
           );
 
         peIdsToRecheck.add(pe.peId);
-        await t.query(sql.unsafe`
+        await tr.query(sql.unsafe`
           update act.pe_members_requests
           set
             status = ${r.status}
@@ -799,14 +799,14 @@ class ClientPeController {
 
         if (r.status === "ACCEPTED") {
           if (!peMember) {
-            await t.query(sql.unsafe`
+            await tr.query(sql.unsafe`
             insert into act.pe_members
               (pe_id, user_id)
             values
               (${pe.peId}, ${request.userId})
           `);
           } else {
-            await t.query(sql.unsafe`
+            await tr.query(sql.unsafe`
               update act.pe_members
               set
                 is_active = true
@@ -817,19 +817,19 @@ class ClientPeController {
           }
         }
       }
-    });
 
-    for (const peId of peIdsToRecheck) {
-      await cPeService.updateAllActRegStatusByPe(peId);
-    }
+      for (const peId of peIdsToRecheck) {
+        await cPeService.updateAllActRegStatusByPe({ peId, tr });
+      }
 
-    RouterUtils.validAndSendResponse(
-      api.client.pe.PATCH_PeMembersRequests.res,
-      res,
-      {
-        code: "success",
-      },
-    );
+      RouterUtils.validAndSendResponse(
+        api.client.pe.PATCH_PeMembersRequests.res,
+        res,
+        {
+          code: "success",
+        },
+      );
+    });
   }
 
   async excludeMemberFromPe(req: Request, res: Response) {

+ 13 - 3
src/modules/client/activities/participant-entities/c-pe-service.ts

@@ -6,7 +6,7 @@ import {
 } 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 { sql } from "slonik";
+import { DatabaseTransactionConnection, sql } from "slonik";
 import { z } from "zod";
 import { cActService } from "../c-act-service.js";
 
@@ -447,7 +447,13 @@ class CPeService {
     `);
   }
 
-  async updateAllActRegStatusByPe(peId: string) {
+  async updateAllActRegStatusByPe({
+    peId,
+    tr,
+  }: {
+    peId: string;
+    tr: DatabaseTransactionConnection;
+  }) {
     const actRegs = await selPool.any(sql.type(
       z.object({
         activityRegId: DbSchema.act.activityRegs.activityRegId,
@@ -464,8 +470,12 @@ class CPeService {
     `);
 
     // TODO: добавить в транзикции все функции, в которых что-то меняется
+
     for (const actReg of actRegs) {
-      await cActService.updateActRegPaymentStatus(actReg.activityRegId);
+      await cActService.updateActRegPaymentStatus({
+        activityRegId: actReg.activityRegId,
+        tr,
+      });
     }
   }