Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge dev into main #1410

Merged
merged 47 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
4c13e0c
feat: add List component
jinhyeonkwon Jan 15, 2025
7a02da5
chore: start Fnd 013,014
Gerbera3090 Jan 21, 2025
dcc25b1
Merge remote-tracking branch 'origin/dev' into 1363-impl-funding-api-…
Gerbera3090 Jan 23, 2025
2dd05d5
fix: entity and schema funding and comment
Gerbera3090 Jan 23, 2025
9b49f2c
Merge remote-tracking branch 'origin/dev' into 1363-impl-funding-api-…
Gerbera3090 Jan 23, 2025
43d8afe
fix: lint after merge
Gerbera3090 Jan 23, 2025
49f424d
fix: adjust api number
Gerbera3090 Jan 23, 2025
a1d8080
feat: funding 12 13 for executive approval
Gerbera3090 Jan 23, 2025
d15f31a
feat: funding 12 13 for executive approval and get
Gerbera3090 Jan 23, 2025
6eafbed
feat: add file for noncorporate
Gerbera3090 Jan 24, 2025
9637960
feat: add file for noncorporate
Gerbera3090 Jan 24, 2025
08affda
feat: prevent errornous cases
Gerbera3090 Jan 24, 2025
9e857ea
chore: description for fnd013
Gerbera3090 Jan 24, 2025
416f7ce
fix: add partial for funding tag list
wjeongchoi Jan 24, 2025
6a02c59
fix: fix mock funding details
wjeongchoi Jan 24, 2025
98cc77b
fix: add nonCorporateTransactionFiles
wjeongchoi Jan 24, 2025
e36ddb5
fix: build error
wjeongchoi Jan 24, 2025
614e145
chore: delete comment for finished todo
wjeongchoi Jan 24, 2025
2eb2196
feat: tx conventions
Gerbera3090 Jan 25, 2025
43fc947
Merge remote-tracking branch 'origin' into 1363-impl-funding-api-for-…
Gerbera3090 Jan 25, 2025
8846d32
feat: adjust merge and fix review
Gerbera3090 Jan 25, 2025
b3f0bbb
refactor: split list and listitem into seperate files
jinhyeonkwon Jan 25, 2025
421b99c
Merge branch '1363-impl-funding-api-for-executive-feedbacks' of https…
Gerbera3090 Jan 25, 2025
28063b0
fix: build error
jooyeongmee Jan 25, 2025
55bb084
Merge pull request #1343 from academic-relations/1342-feat-list-compo…
jinhyeonkwon Jan 26, 2025
b1727dd
feat: update activity API response with commentedAt and editedAt fields
pbc1017 Jan 27, 2025
98ab816
fix: use getKSTDate() for deletedAt and editedAt in activity update
pbc1017 Jan 27, 2025
72a837c
fix: update final reviewer column to use commentedExecutive name
pbc1017 Jan 27, 2025
ddd5f1b
Merge pull request #1393 from academic-relations/1392-fix-act024-act028
pbc1017 Jan 27, 2025
159ce83
fix: merge from dev
Gerbera3090 Jan 27, 2025
addc8ab
Merge branch 'dev' into 1363-impl-funding-api-for-executive-feedbacks
wjeongchoi Jan 27, 2025
cce5714
Merge pull request #1375 from academic-relations/1363-impl-funding-ap…
Gerbera3090 Jan 28, 2025
543f478
fix: update check clubId logic in FudningDetailFrame
jooyeongmee Jan 29, 2025
33aecd6
Merge pull request #1396 from academic-relations/fix-check-clubId-iss…
jooyeongmee Jan 29, 2025
c91f2d4
feat: add funding paths and update funding status progress handling
pbc1017 Jan 29, 2025
1657071
refactor: update navigation and paths configuration
pbc1017 Jan 29, 2025
ef7ac18
chore: remove commented out communication channel navigation item
pbc1017 Jan 29, 2025
5a5d132
Merge pull request #1398 from academic-relations/1397-add-funding-pat…
pbc1017 Jan 29, 2025
2da5efa
feat: add partial approve related logic in funding detail frame
jooyeongmee Jan 30, 2025
79f47bc
fix: reset file input using ref to allow re-selection of the same file
jooyeongmee Jan 30, 2025
7375cf6
fix: add a validation logic to funding expenditure date field
jooyeongmee Jan 30, 2025
1c4edd6
fix: update funding progress toast section
jooyeongmee Jan 30, 2025
0385d5f
Merge pull request #1407 from academic-relations/1406-add-funding-exp…
jooyeongmee Jan 31, 2025
ff78b90
Merge pull request #1405 from academic-relations/1404-fileupload-issue
jooyeongmee Jan 31, 2025
a5b0f4a
Merge pull request #1403 from academic-relations/1402-add-partial-app…
jooyeongmee Jan 31, 2025
0d1e97c
feat: add club delegate check and funding deadline validation methods
pbc1017 Jan 31, 2025
9734286
Merge pull request #1409 from academic-relations/1408-add-check-logic…
pbc1017 Jan 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion packages/api/src/drizzle/drizzle.provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
// dizzle.provider.ts

import { drizzle } from "drizzle-orm/mysql2";
import { ExtractTablesWithRelations } from "drizzle-orm";
import { MySqlTransaction } from "drizzle-orm/mysql-core";
import {
drizzle,
MySql2PreparedQueryHKT,
MySql2QueryResultHKT,
} from "drizzle-orm/mysql2";
import mysql from "mysql2/promise";

import logger from "../common/util/logger";
Expand Down Expand Up @@ -83,3 +89,11 @@ export const drizzleProvider = [
exports: [DrizzleAsyncProvider],
},
];

// transaction의 type
export type DrizzleTransaction = MySqlTransaction<
MySql2QueryResultHKT,
MySql2PreparedQueryHKT,
Record<string, never>,
ExtractTablesWithRelations<Record<string, never>>
>;
26 changes: 25 additions & 1 deletion packages/api/src/drizzle/schema/funding.schema.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { FundingStatusEnum } from "@sparcs-clubs/interface/common/enum/funding.enum";

import {
boolean,
datetime,
Expand All @@ -21,7 +23,9 @@ export const Funding = mysqlTable(
activityDId: int("activity_d_id")
.notNull()
.references(() => ActivityD.id),
fundingStatusEnum: int("funding_status_enum").notNull(),
fundingStatusEnum: int("funding_status_enum")
.notNull()
.default(FundingStatusEnum.Applied),
purposeActivityId: int("purpose_activity_id"),
name: varchar("name", { length: 255 }).notNull(),
expenditureDate: datetime("expenditure_date").notNull(),
Expand Down Expand Up @@ -134,6 +138,24 @@ export const FundingTradeDetailFile = mysqlTable(
}),
);

export const FundingNonCorporateTransactionFile = mysqlTable(
"funding_non_corporate_transaction_file",
{
id: int("id").autoincrement().primaryKey().notNull(),
fundingId: int("funding_id").notNull(),
fileId: varchar("file_id", { length: 128 }).notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
deletedAt: timestamp("deleted_at"),
},
table => ({
fundingForeignKey: foreignKey({
name: "non_corporate_transaction_file_funding_id_fk",
columns: [table.fundingId],
foreignColumns: [Funding.id],
}),
}),
);

export const FundingFoodExpenseFile = mysqlTable(
"funding_food_expense_file",
{
Expand Down Expand Up @@ -362,6 +384,8 @@ export const FundingFeedback = mysqlTable(
fundingId: int("funding_id").notNull(),
chargedExecutiveId: int("charged_executive_id").notNull(),
feedback: text("feedback").notNull(),
fundingStatusEnum: int("funding_status_enum").notNull(), // Funding 에서 이관
approvedAmount: int("approved_amount").notNull(), // Funding 에서 이관
createdAt: timestamp("created_at").defaultNow().notNull(),
deletedAt: timestamp("deleted_at"),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export default class ActivityRepository {
// 작성에 성공하면 True, 실패하면 False를 리턴합니다.
async deleteActivity(contents: { activityId: number }): Promise<boolean> {
const isDeletionSucceed = await this.db.transaction(async tx => {
const deletedAt = new Date();
const deletedAt = getKSTDate();
const [activitySetResult] = await tx
.update(Activity)
.set({
Expand Down Expand Up @@ -457,7 +457,7 @@ export default class ActivityRepository {
activityStatusEnumId: ActivityStatusEnum;
}) {
const isUpdateSucceed = await this.db.transaction(async tx => {
const deletedAt = new Date();
const deletedAt = getKSTDate();

const [activitySetResult] = await tx
.update(Activity)
Expand Down
2 changes: 2 additions & 0 deletions packages/api/src/feature/activity/service/activity.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,8 @@ export default class ActivityService {
commentedExecutive,
chargedExecutive,
updatedAt: activity.updatedAt,
commentedAt: activity.commentedAt,
editedAt: activity.editedAt,
};
}),
);
Expand Down
9 changes: 9 additions & 0 deletions packages/api/src/feature/club/service/club.public.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ export default class ClubPublicService {
return true;
}

async checkStudentDelegate(studentId: number, clubId: number) {
if (!(await this.isStudentDelegate(studentId, clubId))) {
throw new HttpException(
"It seems that you are not the delegate of the club.",
HttpStatus.FORBIDDEN,
);
}
}

/**
* @param clubStatusEnumId 동아리 상태 enum id의 배열
* @param studentId 사용중인 학생 id
Expand Down
53 changes: 49 additions & 4 deletions packages/api/src/feature/funding/controller/funding.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,35 @@ import apiFnd006, {
ApiFnd006RequestQuery,
ApiFnd006ResponseOk,
} from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd006";
import apiFnd007 from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd007";
import apiFnd007, {
ApiFnd007ResponseOk,
} from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd007";
import apiFnd012, {
ApiFnd012RequestParam,
ApiFnd012RequestUrl,
ApiFnd012ResponseOk,
} from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd012";
import apiFnd013, {
ApiFnd013RequestBody,
ApiFnd013RequestParam,
ApiFnd013RequestUrl,
ApiFnd013ResponseCreated,
} from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd013";

import { ZodPipe } from "@sparcs-clubs/api/common/pipe/zod-pipe";

import {
Executive,
Public,
Student,
} from "@sparcs-clubs/api/common/util/decorators/method-decorator";
import { GetStudent } from "@sparcs-clubs/api/common/util/decorators/param-decorator";
import {
GetExecutive,
GetStudent,
} from "@sparcs-clubs/api/common/util/decorators/param-decorator";

import FundingService from "../service/funding.service";

import type { ApiFnd007ResponseOk } from "@sparcs-clubs/interface/api/funding/endpoint/apiFnd007";

@Controller()
export default class FundingController {
constructor(private fundingService: FundingService) {}
Expand Down Expand Up @@ -132,4 +147,34 @@ export default class FundingController {
async getPublicFundingsDeadline(): Promise<ApiFnd007ResponseOk> {
return this.fundingService.getPublicFundingsDeadline();
}

@Executive()
@Get(ApiFnd012RequestUrl)
@UsePipes(new ZodPipe(apiFnd012))
async getExecutiveFunding(
@GetExecutive() executive: GetExecutive,
@Param() param: ApiFnd012RequestParam,
): Promise<ApiFnd012ResponseOk> {
return this.fundingService.getExecutiveFunding(
executive.executiveId,
param.id,
);
}

@Executive()
@Post(ApiFnd013RequestUrl)
@UsePipes(new ZodPipe(apiFnd013))
async postExecutiveFundingComment(
@GetExecutive() executive: GetExecutive,
@Param() param: ApiFnd013RequestParam,
@Body() body: ApiFnd013RequestBody,
): Promise<ApiFnd013ResponseCreated> {
return this.fundingService.postExecutiveFundingComment(
executive.executiveId,
param.id,
body.fundingStatusEnum,
body.approvedAmount,
body.content,
);
}
}
35 changes: 25 additions & 10 deletions packages/api/src/feature/funding/model/funding.comment.model.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,53 @@
import { IFundingComment } from "@sparcs-clubs/interface/api/funding/type/funding.type";
import { FundingStatusEnum } from "@sparcs-clubs/interface/common/enum/funding.enum";
import { InferSelectModel } from "drizzle-orm";

export type FundingCommentDBResult = {
id: number;
fundingId: number;
chargedExecutiveId: number;
content: string;
createdAt: Date;
};
import { FundingFeedback } from "@sparcs-clubs/api/drizzle/schema/funding.schema";

import { MFunding } from "./funding.model";
import { VFundingSummary } from "./funding.summary.model";

export type FundingCommentDBResult = InferSelectModel<typeof FundingFeedback>;

export class MFundingComment implements IFundingComment {
id: number;

fundingId: number;
funding: { id: number };

chargedExecutive: {
id: number;
};

content: string;

fundingStatusEnum: FundingStatusEnum;

approvedAmount: number;

createdAt: Date;

constructor(data: IFundingComment) {
Object.assign(this, data);
}

isFinalComment(funding: VFundingSummary | MFunding): boolean {
return (
funding.approvedAmount === this.approvedAmount &&
funding.fundingStatusEnum === this.fundingStatusEnum &&
funding.id === this.funding.id
);
}

static fromDBResult(result: FundingCommentDBResult) {
return new MFundingComment({
id: result.id,
fundingId: result.fundingId,
funding: { id: result.fundingId },
chargedExecutive: {
id: result.chargedExecutiveId,
},
content: result.content,
fundingStatusEnum: result.fundingStatusEnum,
approvedAmount: result.approvedAmount,
content: result.feedback,
createdAt: result.createdAt,
});
}
Expand Down
15 changes: 10 additions & 5 deletions packages/api/src/feature/funding/model/funding.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
INonCorporateTransaction,
ITransportation,
} from "@sparcs-clubs/interface/api/funding/type/funding.type";
import { FundingStatusEnum } from "@sparcs-clubs/interface/common/enum/funding.enum";

export type FundingDBResult = {
funding: {
Expand Down Expand Up @@ -79,6 +80,7 @@ export type FundingDBResult = {
fixtureSoftwareEvidenceFiles?: Array<{
id: string;
}>;
nonCorporateTransactionFiles?: Array<{ id: string }>;
foodExpenseFiles?: Array<{ id: string }>;
laborContractFiles?: Array<{ id: string }>;
externalEventParticipationFeeFiles?: Array<{
Expand All @@ -98,11 +100,11 @@ export type FundingDBResult = {
export class MFunding implements IFunding {
id: number;

clubId: number;
club: { id: number };

activityDId: number;
activityD: { id: number };

fundingStatusEnum: number;
fundingStatusEnum: FundingStatusEnum;

purposeActivity?: Pick<IActivitySummary, "id">;

Expand Down Expand Up @@ -177,9 +179,9 @@ export class MFunding implements IFunding {
static fromDBResult(result: FundingDBResult) {
return new MFunding({
id: result.funding.id,
clubId: result.funding.clubId,
club: { id: result.funding.clubId },
name: result.funding.name,
activityDId: result.funding.activityDId,
activityD: { id: result.funding.activityDId },
fundingStatusEnum: result.funding.fundingStatusEnum,
purposeActivity: result.funding.purposeActivityId
? {
Expand Down Expand Up @@ -261,6 +263,9 @@ export class MFunding implements IFunding {
traderName: result.funding.traderName,
traderAccountNumber: result.funding.traderAccountNumber,
wasteExplanation: result.funding.wasteExplanation,
files: result.nonCorporateTransactionFiles.map(file => ({
id: file.id,
})),
}
: undefined,
foodExpense: result.funding.isFoodExpense
Expand Down
62 changes: 62 additions & 0 deletions packages/api/src/feature/funding/model/funding.summary.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { IFundingSummary } from "@sparcs-clubs/interface/api/funding/type/funding.type";
import { InferSelectModel } from "drizzle-orm";

import { Funding } from "@sparcs-clubs/api/drizzle/schema/funding.schema";

import { MFunding } from "./funding.model";

export type FundingSummaryDBResult = Pick<
InferSelectModel<typeof Funding>,
| "id"
| "name"
| "fundingStatusEnum"
| "expenditureAmount"
| "purposeActivityId"
| "approvedAmount"
>;

export class VFundingSummary implements IFundingSummary {
id: IFundingSummary["id"];

name: IFundingSummary["name"];

fundingStatusEnum: IFundingSummary["fundingStatusEnum"];

expenditureAmount: IFundingSummary["expenditureAmount"];

purposeActivity?: IFundingSummary["purposeActivity"];

approvedAmount?: IFundingSummary["approvedAmount"];

// 첫 번째 생성자: IFundingSummary로부터 초기화
constructor(fundingSummary: IFundingSummary);

// 두 번째 생성자: MFunding로부터 초기화
constructor(funding: MFunding);

constructor(param: IFundingSummary | MFunding) {
if (param instanceof MFunding) {
this.id = param.id;
this.name = param.name;
this.fundingStatusEnum = param.fundingStatusEnum;
this.expenditureAmount = param.expenditureAmount;
this.purposeActivity = param.purposeActivity;
this.approvedAmount = param.approvedAmount;
} else {
Object.assign(this, param);
}
}

static fromDBResult(result: FundingSummaryDBResult) {
return new VFundingSummary({
id: result.id,
name: result.name,
fundingStatusEnum: result.fundingStatusEnum,
expenditureAmount: result.expenditureAmount,
purposeActivity: result.purposeActivityId
? { id: result.purposeActivityId }
: undefined,
approvedAmount: result.approvedAmount,
});
}
}
Loading