|
@@ -8,8 +8,10 @@ import {
|
|
import { DbSchema } from "#db/db-schema.js";
|
|
import { DbSchema } from "#db/db-schema.js";
|
|
import { selPool, updPool } from "#db/db.js";
|
|
import { selPool, updPool } from "#db/db.js";
|
|
import { ApiError } from "#exceptions/api-error.js";
|
|
import { ApiError } from "#exceptions/api-error.js";
|
|
|
|
+import { logger } from "#plugins/logger.js";
|
|
import { sql } from "slonik";
|
|
import { sql } from "slonik";
|
|
import { z } from "zod";
|
|
import { z } from "zod";
|
|
|
|
+import { ordersService } from "../shop/orders-service.js";
|
|
|
|
|
|
class CActService {
|
|
class CActService {
|
|
async addDataToActValidator(
|
|
async addDataToActValidator(
|
|
@@ -57,6 +59,7 @@ class CActService {
|
|
peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
|
|
peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
|
|
userId: DbSchema.act.activityRegs.userId.nullable(),
|
|
userId: DbSchema.act.activityRegs.userId.nullable(),
|
|
isPaid: DbSchema.act.activityRegs.isPaid,
|
|
isPaid: DbSchema.act.activityRegs.isPaid,
|
|
|
|
+ isCanceled: DbSchema.act.activityRegs.isCanceled,
|
|
statusHistory: z.array(
|
|
statusHistory: z.array(
|
|
z.object({
|
|
z.object({
|
|
statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
|
|
statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
|
|
@@ -83,7 +86,8 @@ class CActService {
|
|
ar.user_id "userId",
|
|
ar.user_id "userId",
|
|
ar.is_paid "isPaid",
|
|
ar.is_paid "isPaid",
|
|
ar.status_history "statusHistory",
|
|
ar.status_history "statusHistory",
|
|
- ar.is_user_reg "isUserReg"
|
|
|
|
|
|
+ ar.is_user_reg "isUserReg",
|
|
|
|
+ ar.is_canceled "isCanceled"
|
|
from
|
|
from
|
|
act.act_regs_with_status ar
|
|
act.act_regs_with_status ar
|
|
where
|
|
where
|
|
@@ -96,6 +100,7 @@ class CActService {
|
|
from act.pe_members pm_check
|
|
from act.pe_members pm_check
|
|
where pm_check.pe_id = ar.pe_id
|
|
where pm_check.pe_id = ar.pe_id
|
|
and pm_check.user_id = ${userId}
|
|
and pm_check.user_id = ${userId}
|
|
|
|
+ and pm_check.is_active = true
|
|
);
|
|
);
|
|
`);
|
|
`);
|
|
return actRegs;
|
|
return actRegs;
|
|
@@ -113,6 +118,7 @@ class CActService {
|
|
peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
|
|
peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
|
|
userId: DbSchema.act.activityRegs.userId.nullable(),
|
|
userId: DbSchema.act.activityRegs.userId.nullable(),
|
|
isPaid: DbSchema.act.activityRegs.isPaid,
|
|
isPaid: DbSchema.act.activityRegs.isPaid,
|
|
|
|
+ isCanceled: DbSchema.act.activityRegs.isCanceled,
|
|
statusHistory: z.array(
|
|
statusHistory: z.array(
|
|
z.object({
|
|
z.object({
|
|
statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
|
|
statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
|
|
@@ -147,7 +153,8 @@ class CActService {
|
|
ar.is_paid "isPaid",
|
|
ar.is_paid "isPaid",
|
|
ar.status_history "statusHistory",
|
|
ar.status_history "statusHistory",
|
|
ar.fields "fields",
|
|
ar.fields "fields",
|
|
- ar.is_user_reg "isUserReg"
|
|
|
|
|
|
+ ar.is_user_reg "isUserReg",
|
|
|
|
+ ar.is_canceled "isCanceled"
|
|
from
|
|
from
|
|
act.act_regs_with_values ar
|
|
act.act_regs_with_values ar
|
|
where
|
|
where
|
|
@@ -168,6 +175,7 @@ class CActService {
|
|
peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
|
|
peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
|
|
userId: DbSchema.act.activityRegs.userId.nullable(),
|
|
userId: DbSchema.act.activityRegs.userId.nullable(),
|
|
isPaid: DbSchema.act.activityRegs.isPaid,
|
|
isPaid: DbSchema.act.activityRegs.isPaid,
|
|
|
|
+ isCanceled: DbSchema.act.activityRegs.isCanceled,
|
|
statusHistory: z.array(
|
|
statusHistory: z.array(
|
|
z.object({
|
|
z.object({
|
|
statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
|
|
statusHistoryId: DbSchema.act.actRegStatusHistory.statusHistoryId,
|
|
@@ -194,7 +202,8 @@ class CActService {
|
|
ar.user_id "userId",
|
|
ar.user_id "userId",
|
|
ar.is_paid "isPaid",
|
|
ar.is_paid "isPaid",
|
|
ar.status_history "statusHistory",
|
|
ar.status_history "statusHistory",
|
|
- ar.is_user_reg "isUserReg"
|
|
|
|
|
|
+ ar.is_user_reg "isUserReg",
|
|
|
|
+ ar.is_canceled "isCanceled"
|
|
from
|
|
from
|
|
act.act_regs_with_values ar
|
|
act.act_regs_with_values ar
|
|
where
|
|
where
|
|
@@ -266,7 +275,7 @@ class CActService {
|
|
}
|
|
}
|
|
|
|
|
|
async updateActRegPaymentStatus(activityRegId: string) {
|
|
async updateActRegPaymentStatus(activityRegId: string) {
|
|
- const actReg = await this.getActRegWithValues(activityRegId);
|
|
|
|
|
|
+ const actReg = await this.getActRegForPeMember(activityRegId);
|
|
if (!actReg) {
|
|
if (!actReg) {
|
|
throw ApiError.BadRequest("actRegNotFound", "Не найдена регистрация");
|
|
throw ApiError.BadRequest("actRegNotFound", "Не найдена регистрация");
|
|
}
|
|
}
|
|
@@ -281,14 +290,16 @@ class CActService {
|
|
const isPaid = await this.checkActivityRegPayment({
|
|
const isPaid = await this.checkActivityRegPayment({
|
|
activityRegId,
|
|
activityRegId,
|
|
});
|
|
});
|
|
- if (isPaid) {
|
|
|
|
- await updPool.query(sql.unsafe`
|
|
|
|
|
|
+ // если надо поменять
|
|
|
|
+ if (actReg.isPaid !== isPaid) {
|
|
|
|
+ if (isPaid) {
|
|
|
|
+ await updPool.query(sql.unsafe`
|
|
update act.activity_regs
|
|
update act.activity_regs
|
|
set is_paid = true
|
|
set is_paid = true
|
|
where activity_reg_id = ${activityRegId}
|
|
where activity_reg_id = ${activityRegId}
|
|
`);
|
|
`);
|
|
|
|
|
|
- await updPool.query(sql.unsafe`
|
|
|
|
|
|
+ await updPool.query(sql.unsafe`
|
|
insert into act.act_reg_status_history (
|
|
insert into act.act_reg_status_history (
|
|
activity_reg_id,
|
|
activity_reg_id,
|
|
act_reg_status_id,
|
|
act_reg_status_id,
|
|
@@ -300,6 +311,14 @@ class CActService {
|
|
'Оплачено'
|
|
'Оплачено'
|
|
)
|
|
)
|
|
`);
|
|
`);
|
|
|
|
+ } else {
|
|
|
|
+ // такого по идее не должно быть
|
|
|
|
+ logger.error("isPaid !== actReg.isPaid", {
|
|
|
|
+ isPaid,
|
|
|
|
+ actReg,
|
|
|
|
+ activity,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// TODO: QR
|
|
// TODO: QR
|
|
@@ -316,19 +335,35 @@ class CActService {
|
|
peId: actReg.peId,
|
|
peId: actReg.peId,
|
|
});
|
|
});
|
|
|
|
|
|
- if (isAllPaid) {
|
|
|
|
- await updPool.query(sql.unsafe`
|
|
|
|
|
|
+ // если надо поменять
|
|
|
|
+ if (isAllPaid !== actReg.isPaid) {
|
|
|
|
+ if (!isAllPaid) {
|
|
|
|
+ await updPool.query(sql.unsafe`
|
|
update act.activity_regs
|
|
update act.activity_regs
|
|
set is_paid = false
|
|
set is_paid = false
|
|
where activity_reg_id = ${activityRegId}
|
|
where activity_reg_id = ${activityRegId}
|
|
`);
|
|
`);
|
|
- } else {
|
|
|
|
- await updPool.query(sql.unsafe`
|
|
|
|
|
|
+
|
|
|
|
+ // TODO: Возможно стоит добавить в act.activities поле payment_status_id
|
|
|
|
+ await updPool.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 updPool.query(sql.unsafe`
|
|
update act.activity_regs
|
|
update act.activity_regs
|
|
set is_paid = true
|
|
set is_paid = true
|
|
where activity_reg_id = ${activityRegId}
|
|
where activity_reg_id = ${activityRegId}
|
|
`);
|
|
`);
|
|
- await updPool.query(sql.unsafe`
|
|
|
|
|
|
+ await updPool.query(sql.unsafe`
|
|
insert into act.act_reg_status_history (
|
|
insert into act.act_reg_status_history (
|
|
activity_reg_id,
|
|
activity_reg_id,
|
|
act_reg_status_id,
|
|
act_reg_status_id,
|
|
@@ -340,6 +375,7 @@ class CActService {
|
|
'Оплачены все участники'
|
|
'Оплачены все участники'
|
|
)
|
|
)
|
|
`);
|
|
`);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -364,6 +400,7 @@ class CActService {
|
|
act.pe_members pm
|
|
act.pe_members pm
|
|
where
|
|
where
|
|
pm.pe_id = ${peId}
|
|
pm.pe_id = ${peId}
|
|
|
|
+ and pm.is_active = true
|
|
`);
|
|
`);
|
|
|
|
|
|
const memberIds = members.map((member) => member.peMemberId);
|
|
const memberIds = members.map((member) => member.peMemberId);
|
|
@@ -408,6 +445,7 @@ class CActService {
|
|
from act.pe_members
|
|
from act.pe_members
|
|
where pe_id = ${actReg.peId}
|
|
where pe_id = ${actReg.peId}
|
|
and user_id = ${userId}
|
|
and user_id = ${userId}
|
|
|
|
+ and is_active = true
|
|
`);
|
|
`);
|
|
|
|
|
|
if (isMemeber) return "member";
|
|
if (isMemeber) return "member";
|
|
@@ -415,6 +453,24 @@ class CActService {
|
|
return undefined;
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ 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(
|
|
async getActRegDataWithUserCopyValuesAndActValidators(
|
|
userId: string,
|
|
userId: string,
|
|
eventId: string,
|
|
eventId: string,
|
|
@@ -564,6 +620,7 @@ class CActService {
|
|
peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
|
|
peOwnerId: DbSchema.act.partEntities.ownerId.nullable(),
|
|
userId: DbSchema.act.activityRegs.userId.nullable(),
|
|
userId: DbSchema.act.activityRegs.userId.nullable(),
|
|
isPaid: DbSchema.act.activityRegs.isPaid,
|
|
isPaid: DbSchema.act.activityRegs.isPaid,
|
|
|
|
+ isCanceled: DbSchema.act.activityRegs.isCanceled,
|
|
validators: z.array(apiTypes.activities.ActValidator),
|
|
validators: z.array(apiTypes.activities.ActValidator),
|
|
statusHistory: z.array(
|
|
statusHistory: z.array(
|
|
z.object({
|
|
z.object({
|
|
@@ -604,6 +661,7 @@ class CActService {
|
|
ar.pe_owner_id "peOwnerId",
|
|
ar.pe_owner_id "peOwnerId",
|
|
ar.user_id "userId",
|
|
ar.user_id "userId",
|
|
ar.is_paid "isPaid",
|
|
ar.is_paid "isPaid",
|
|
|
|
+ ar.is_canceled "isCanceled",
|
|
ar.status_history "statusHistory",
|
|
ar.status_history "statusHistory",
|
|
f.fields "fields",
|
|
f.fields "fields",
|
|
awv.validators,
|
|
awv.validators,
|
|
@@ -645,6 +703,120 @@ class CActService {
|
|
where ar.activity_reg_id = ${activityRegId}
|
|
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}
|
|
|
|
+ `);
|
|
|
|
+
|
|
|
|
+ if (!orderItem) {
|
|
|
|
+ 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,
|
|
|
|
+ paymentId: DbSchema.shop.payments.paymentId,
|
|
|
|
+ paymentExternalTransactionId:
|
|
|
|
+ DbSchema.shop.payments.externalTransactionId,
|
|
|
|
+ }),
|
|
|
|
+ )`
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
export const cActService = new CActService();
|
|
export const cActService = new CActService();
|