diff --git a/packages/server/src/user/user.service.ts b/packages/server/src/user/user.service.ts index 1b9a099..504e2f0 100644 --- a/packages/server/src/user/user.service.ts +++ b/packages/server/src/user/user.service.ts @@ -2,6 +2,8 @@ import { Injectable, NotFoundException } from '@nestjs/common' import { MembershipStatus, BookingStatus, UserRole, CardTypeCategory } from '@mp-pilates/shared' import type { PaginatedData, UserProfileResponse, UserStatsResponse } from '@mp-pilates/shared' import { PrismaService } from '../prisma/prisma.service' +import { Membership, CardType, Prisma } from '@prisma/client' +import { UpdateUserMembershipDto } from './dto/update-user-membership.dto' const VALID_CARD_TYPES = new Set(Object.values(CardTypeCategory)) @@ -226,4 +228,68 @@ export class UserService { return { items, total, page, limit } } + + // ─── Membership management ──────────────────────────────────────────────── + + async getUserMembership(userId: string) { + const membership = await this.prisma.membership.findFirst({ + where: { userId }, + include: { cardType: true }, + }) + return membership ? { ...membership, cardType: { ...membership.cardType } } : null + } + + async updateUserMembership(userId: string, dto: UpdateUserMembershipDto) { + const now = new Date() + const expireDate = new Date(dto.expireDate) + const remainingTimes = dto.remainingTimes ?? null + const isTimeBased = remainingTimes !== null + + let status: MembershipStatus = MembershipStatus.ACTIVE + if (expireDate < now) { + status = MembershipStatus.EXPIRED + } else if (isTimeBased && remainingTimes <= 0) { + status = MembershipStatus.USED_UP + } + + const existing = await this.prisma.membership.findFirst({ where: { userId } }) + + let membership: Membership & { cardType: CardType } + if (existing) { + const updated = await this.prisma.membership.update({ + where: { id: existing.id }, + data: { + cardTypeId: dto.cardTypeId, + remainingTimes: dto.remainingTimes ?? null, + startDate: new Date(dto.startDate), + expireDate: new Date(dto.expireDate), + status, + }, + include: { cardType: true }, + }) + membership = { ...updated, cardType: { ...updated.cardType } } + } else { + const created = await this.prisma.membership.create({ + data: { + userId, + cardTypeId: dto.cardTypeId, + remainingTimes: dto.remainingTimes ?? null, + startDate: new Date(dto.startDate), + expireDate: new Date(dto.expireDate), + status, + }, + include: { cardType: true }, + }) + membership = { ...created, cardType: { ...created.cardType } } + } + + return membership + } + + async deleteUserMembership(userId: string): Promise { + await this.prisma.membership.updateMany({ + where: { userId }, + data: { status: MembershipStatus.EXPIRED }, + }) + } }