From aaea9a13747af581639962c170ab87a5e73557e0 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Tue, 14 Jan 2025 18:52:55 +0900 Subject: [PATCH 01/12] [fix] divisions post parameter --- openapi/openapi.yaml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 3501e6ce..f880866f 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -760,7 +760,19 @@ paths: get: tags: - division - description: divisionの一覧の取得 + description: division一覧の取得 + クエリでyearを指定することで年度ごとのdivisionを取得可能 + parameters: + - name: year + in: query + description: year + schema: + type: integer + - name: financialRecordID + in: query + description: financialRecordID + schema: + type: integer responses: "200": description: divisionの一覧を取得 From e6ebc8efcff872bb188772ef4f5f96408b945c19 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Tue, 14 Jan 2025 18:53:25 +0900 Subject: [PATCH 02/12] [fix] generated --- api/generated/openapi_gen.go | 29 +++++++++++++++++-- view/next-project/src/generated/hooks.ts | 26 +++++++++++------ .../next-project/src/generated/model/index.ts | 1 + 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/api/generated/openapi_gen.go b/api/generated/openapi_gen.go index 7883cf9f..77b2153e 100644 --- a/api/generated/openapi_gen.go +++ b/api/generated/openapi_gen.go @@ -258,6 +258,15 @@ type PutDepartmentsIdParams struct { Name *string `form:"name,omitempty" json:"name,omitempty"` } +// GetDivisionsParams defines parameters for GetDivisions. +type GetDivisionsParams struct { + // Year year + Year *int `form:"year,omitempty" json:"year,omitempty"` + + // FinancialRecordID financialRecordID + FinancialRecordID *int `form:"financialRecordID,omitempty" json:"financialRecordID,omitempty"` +} + // PostExpensesParams defines parameters for PostExpenses. type PostExpensesParams struct { // Name name @@ -613,7 +622,7 @@ type ServerInterface interface { PutDepartmentsId(ctx echo.Context, id int, params PutDepartmentsIdParams) error // (GET /divisions) - GetDivisions(ctx echo.Context) error + GetDivisions(ctx echo.Context, params GetDivisionsParams) error // (POST /divisions) PostDivisions(ctx echo.Context) error @@ -1465,8 +1474,24 @@ func (w *ServerInterfaceWrapper) PutDepartmentsId(ctx echo.Context) error { func (w *ServerInterfaceWrapper) GetDivisions(ctx echo.Context) error { var err error + // Parameter object where we will unmarshal all parameters from the context + var params GetDivisionsParams + // ------------- Optional query parameter "year" ------------- + + err = runtime.BindQueryParameter("form", true, false, "year", ctx.QueryParams(), ¶ms.Year) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter year: %s", err)) + } + + // ------------- Optional query parameter "financialRecordID" ------------- + + err = runtime.BindQueryParameter("form", true, false, "financialRecordID", ctx.QueryParams(), ¶ms.FinancialRecordID) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter financialRecordID: %s", err)) + } + // Invoke the callback with all the unmarshaled arguments - err = w.Handler.GetDivisions(ctx) + err = w.Handler.GetDivisions(ctx, params) return err } diff --git a/view/next-project/src/generated/hooks.ts b/view/next-project/src/generated/hooks.ts index cd2aadb1..7f2fb383 100644 --- a/view/next-project/src/generated/hooks.ts +++ b/view/next-project/src/generated/hooks.ts @@ -72,6 +72,7 @@ import type { GetBureausId200, GetDepartments200, GetDepartmentsId200, + GetDivisionsParams, GetExpenses200, GetExpensesDetails200, GetExpensesDetailsYear200, @@ -2228,7 +2229,7 @@ export const useDeleteDepartmentsId = ( } /** - * divisionの一覧の取得 + * division一覧の取得 クエリでyearを指定することで年度ごとのdivisionを取得可能 */ export type getDivisionsResponse = { data: DivisionDetails; @@ -2236,15 +2237,22 @@ export type getDivisionsResponse = { headers: Headers; } -export const getGetDivisionsUrl = () => { +export const getGetDivisionsUrl = (params?: GetDivisionsParams,) => { + const normalizedParams = new URLSearchParams(); + Object.entries(params || {}).forEach(([key, value]) => { + + if (value !== undefined) { + normalizedParams.append(key, value === null ? 'null' : value.toString()) + } + }); - return `/divisions` + return normalizedParams.size ? `/divisions?${normalizedParams.toString()}` : `/divisions` } -export const getDivisions = async ( options?: RequestInit): Promise => { +export const getDivisions = async (params?: GetDivisionsParams, options?: RequestInit): Promise => { - return customFetch>(getGetDivisionsUrl(), + return customFetch>(getGetDivisionsUrl(params), { ...options, method: 'GET' @@ -2256,19 +2264,19 @@ export const getDivisions = async ( options?: RequestInit): Promise [`/divisions`] as const; +export const getGetDivisionsKey = (params?: GetDivisionsParams,) => [`/divisions`, ...(params ? [params]: [])] as const; export type GetDivisionsQueryResult = NonNullable>> export type GetDivisionsQueryError = unknown export const useGetDivisions = ( - options?: { swr?:SWRConfiguration>, TError> & { swrKey?: Key, enabled?: boolean }, request?: SecondParameter } + params?: GetDivisionsParams, options?: { swr?:SWRConfiguration>, TError> & { swrKey?: Key, enabled?: boolean }, request?: SecondParameter } ) => { const {swr: swrOptions, request: requestOptions} = options ?? {} const isEnabled = swrOptions?.enabled !== false - const swrKey = swrOptions?.swrKey ?? (() => isEnabled ? getGetDivisionsKey() : null); - const swrFn = () => getDivisions(requestOptions) + const swrKey = swrOptions?.swrKey ?? (() => isEnabled ? getGetDivisionsKey(params) : null); + const swrFn = () => getDivisions(params, requestOptions) const query = useSwr>, TError>(swrKey, swrFn, swrOptions) diff --git a/view/next-project/src/generated/model/index.ts b/view/next-project/src/generated/model/index.ts index db4a8cc4..7d50f8e4 100644 --- a/view/next-project/src/generated/model/index.ts +++ b/view/next-project/src/generated/model/index.ts @@ -65,6 +65,7 @@ export * from './getBureaus200'; export * from './getBureausId200'; export * from './getDepartments200'; export * from './getDepartmentsId200'; +export * from './getDivisionsParams'; export * from './getExpenses200'; export * from './getExpensesDetails200'; export * from './getExpensesDetailsYear200'; From 8827803eb21f87664ea147c2d5ea7681506292db Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Tue, 14 Jan 2025 18:54:31 +0900 Subject: [PATCH 03/12] [fix] go.mod --- api/go.mod | 2 +- api/go.sum | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/go.mod b/api/go.mod index b3d22312..cb4515b7 100644 --- a/api/go.mod +++ b/api/go.mod @@ -3,7 +3,7 @@ module github.com/NUTFes/FinanSu/api go 1.16 require ( - github.com/doug-martin/goqu/v9 v9.19.0 // indirect + github.com/doug-martin/goqu/v9 v9.19.0 github.com/go-sql-driver/mysql v1.6.0 github.com/go-test/deep v1.0.8 // indirect github.com/google/go-cmp v0.6.0 // indirect diff --git a/api/go.sum b/api/go.sum index e7a0e742..68032a39 100644 --- a/api/go.sum +++ b/api/go.sum @@ -2,6 +2,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= @@ -161,6 +162,7 @@ github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRy github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/lib/pq v1.10.1 h1:6VXZrLU0jHBYyAqrSPa+MgPfnSvTPuMgK+k0o5kVFWo= github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -269,6 +271,7 @@ github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKk github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= From db76c496e2219dca17828fd1c696f0196f99c567 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Tue, 14 Jan 2025 18:55:05 +0900 Subject: [PATCH 04/12] [feat] create divisions api --- .../controller/division_controller.go | 82 ++++++++++ .../repository/division_repository.go | 142 +++++++++++++++++ api/internals/di/di.go | 4 + api/internals/usecase/division_usecase.go | 147 ++++++++++++++++++ api/router/router.go | 9 ++ 5 files changed, 384 insertions(+) create mode 100644 api/externals/controller/division_controller.go create mode 100644 api/externals/repository/division_repository.go create mode 100644 api/internals/usecase/division_usecase.go diff --git a/api/externals/controller/division_controller.go b/api/externals/controller/division_controller.go new file mode 100644 index 00000000..94ff25f1 --- /dev/null +++ b/api/externals/controller/division_controller.go @@ -0,0 +1,82 @@ +package controller + +import ( + "net/http" + + "github.com/NUTFes/FinanSu/api/generated" + "github.com/NUTFes/FinanSu/api/internals/usecase" + "github.com/labstack/echo/v4" +) + +type divisionController struct { + u usecase.DivisionUseCase +} + +type DivisionController interface { + IndexDivisions(echo.Context) error + CreateDivision(echo.Context) error + UpdateDivision(echo.Context) error + DestroyDivision(echo.Context) error +} + +func NewDivisionController(u usecase.DivisionUseCase) DivisionController { + return &divisionController{u} +} + +func (d *divisionController) IndexDivisions(c echo.Context) error { + ctx := c.Request().Context() + year := c.QueryParam("year") + financialRecordId := c.QueryParam("financial_record_id") + var divisionDetails divisionDetails + + divisionDetails, err := d.u.GetDivisions(ctx, year, financialRecordId) + if err != nil { + return err + } + return c.JSON(http.StatusOK, divisionDetails) +} + +func (d *divisionController) CreateDivision(c echo.Context) error { + ctx := c.Request().Context() + division := new(division) + + if err := c.Bind(division); err != nil { + return c.String(http.StatusBadRequest, "Bad Request") + } + latestDivision, err := d.u.CreateDivision(ctx, *division) + if err != nil { + return err + } + return c.JSON(http.StatusOK, latestDivision) +} + +func (d *divisionController) UpdateDivision(c echo.Context) error { + ctx := c.Request().Context() + id := c.Param("id") + division := new(division) + + if err := c.Bind(division); err != nil { + return c.String(http.StatusBadRequest, "Bad Request") + } + updatedDivision, err := d.u.UpdateDivision(ctx, id, *division) + if err != nil { + return err + } + return c.JSON(http.StatusOK, updatedDivision) +} + +func (d *divisionController) DestroyDivision(c echo.Context) error { + ctx := c.Request().Context() + id := c.Param("id") + + err := d.u.DestroyDivision(ctx, id) + if err != nil { + return err + } + return c.String(http.StatusOK, "Destroy Division") +} + +type ( + division = generated.Division + divisionDetails = generated.DivisionDetails +) diff --git a/api/externals/repository/division_repository.go b/api/externals/repository/division_repository.go new file mode 100644 index 00000000..5a94910e --- /dev/null +++ b/api/externals/repository/division_repository.go @@ -0,0 +1,142 @@ +package repository + +import ( + "context" + "database/sql" + + "github.com/NUTFes/FinanSu/api/drivers/db" + "github.com/NUTFes/FinanSu/api/externals/repository/abstract" + "github.com/NUTFes/FinanSu/api/generated" + goqu "github.com/doug-martin/goqu/v9" +) + +type divisionRepository struct { + client db.Client + crud abstract.Crud +} + +type DivisionRepository interface { + AllByPeriodAndFinancialRecord(context.Context, string, string) (*sql.Rows, error) + GetById(context.Context, string) (*sql.Row, error) + Create(context.Context, division) error + Update(context.Context, string, division) error + Delete(context.Context, string) error + FindLatestRecord(context.Context) (*sql.Row, error) +} + +func NewDivisionRepository(c db.Client, ac abstract.Crud) DivisionRepository { + return &divisionRepository{c, ac} +} + +// 年度別と財務記録で取得 +func (dr *divisionRepository) AllByPeriodAndFinancialRecord( + c context.Context, + year string, + financialRecordId string, +) (*sql.Rows, error) { + + ds := baseGetQuery + + if year != "" { + ds = ds.Where(goqu.C("years.year").Eq(year)) + } + + if financialRecordId != "" { + ds = ds.Where(goqu.C("financial_records.id").Eq(financialRecordId)) + } + + // クエリを構築し、SQLを生成 + query, _, err := ds.GroupBy("divisions.id").ToSQL() + if err != nil { + return nil, err + } + return dr.crud.Read(c, query) +} + +// IDで取得 +func (dr *divisionRepository) GetById( + c context.Context, + id string, +) (*sql.Row, error) { + ds, _, err := baseGetQuery. + Where(goqu.Ex{"divisions.id": id}). + ToSQL() + if err != nil { + return nil, err + } + return dr.crud.ReadByID(c, ds) +} + +// 部門作成 +func (dr *divisionRepository) Create( + c context.Context, + division division, +) error { + ds := dialect.Insert("divisions"). + Rows(goqu.Record{"name": division.Name, "financial_record_id": division.FinancialRecordID}) + query, _, err := ds.ToSQL() + if err != nil { + return err + } + return dr.crud.UpdateDB(c, query) +} + +// 部門更新 +func (dr *divisionRepository) Update( + c context.Context, + id string, + division division, +) error { + ds := dialect.Update("divisions"). + Set(goqu.Record{"name": division.Name, "financial_record_id": division.FinancialRecordID}). + Where(goqu.Ex{"id": id}) + query, _, err := ds.ToSQL() + if err != nil { + return err + } + return dr.crud.UpdateDB(c, query) +} + +// 部門削除 +func (dr *divisionRepository) Delete( + c context.Context, + id string, +) error { + ds := dialect.Delete("divisions").Where(goqu.Ex{"id": id}) + query, _, err := ds.ToSQL() + if err != nil { + return err + } + return dr.crud.UpdateDB(c, query) +} + +// 最新の部門を取得する +func (dr *divisionRepository) FindLatestRecord(c context.Context) (*sql.Row, error) { + ds := baseGetQuery + query, _, err := ds.Limit(1).ToSQL() + + if err != nil { + return nil, err + } + return dr.crud.ReadByID(c, query) +} + +// Note: この中のみで呼ぶために小文字宣言 +type division = generated.Division + +// NOTE: getの共通部分抜き出し +var baseGetQuery = dialect.From("divisions"). + Select( + "divisions.id", + "divisions.name", + "financial_records.name", + goqu.COALESCE(goqu.SUM("item_budgets.amount"), 0).As("budget"), + goqu.COALESCE(goqu.SUM("buy_reports.amount"), 0).As("expense"), + goqu.COALESCE(goqu.L("SUM(item_budgets.amount) - SUM(buy_reports.amount)"), 0).As("balance")). + InnerJoin(goqu.I("financial_records"), goqu.On(goqu.I("financial_records.id").Eq(goqu.I("divisions.financial_record_id")))). + InnerJoin(goqu.I("years"), goqu.On(goqu.I("financial_records.year_id").Eq(goqu.I("years.id")))). + LeftJoin(goqu.I("festival_items"), goqu.On(goqu.I("divisions.id").Eq(goqu.I("festival_items.division_id")))). + LeftJoin(goqu.I("item_budgets"), goqu.On(goqu.I("festival_items.id").Eq(goqu.I("item_budgets.festival_item_id")))). + LeftJoin(goqu.I("buy_reports"), goqu.On(goqu.I("festival_items.id").Eq(goqu.I("buy_reports.festival_item_id")))). + GroupBy(goqu.I("divisions.id")). + Order(goqu.I("divisions.id").Desc()) diff --git a/api/internals/di/di.go b/api/internals/di/di.go index c9ce3006..a9ca4449 100644 --- a/api/internals/di/di.go +++ b/api/internals/di/di.go @@ -30,6 +30,7 @@ func InitializeServer() db.Client { budgetRepository := repository.NewBudgetRepository(client, crud) bureauRepository := repository.NewBureauRepository(client, crud) departmentRepository := repository.NewDepartmentRepository(client, crud) + divisionRepository := repository.NewDivisionRepository(client, crud) expenseRepository := repository.NewExpenseRepository(client, crud) financialRecordRepository := repository.NewFinancialRecordRepository(client, crud) fundInformationRepository := repository.NewFundInformationRepository(client, crud) @@ -57,6 +58,7 @@ func InitializeServer() db.Client { budgetUseCase := usecase.NewBudgetUseCase(budgetRepository) bureauUseCase := usecase.NewBureauUseCase(bureauRepository) departmentUseCase := usecase.NewDepartmentUseCase(departmentRepository) + divisionUseCase := usecase.NewDivisionUseCase(divisionRepository) expenseUseCase := usecase.NewExpenseUseCase(expenseRepository) financialRecordUseCase := usecase.NewFinancialRecordUseCase(financialRecordRepository) fundInformationUseCase := usecase.NewFundInformationUseCase(fundInformationRepository) @@ -91,6 +93,7 @@ func InitializeServer() db.Client { budgetController := controller.NewBudgetController(budgetUseCase) bureauController := controller.NewBureauController(bureauUseCase) departmentController := controller.NewDepartmentController(departmentUseCase) + divisionController := controller.NewDivisionController(divisionUseCase) expenseController := controller.NewExpenseController(expenseUseCase) financialRecordController := controller.NewFinancialRecordController(financialRecordUseCase) fundInformationController := controller.NewFundInformationController(fundInformationUseCase) @@ -119,6 +122,7 @@ func InitializeServer() db.Client { budgetController, bureauController, departmentController, + divisionController, expenseController, financialRecordController, fundInformationController, diff --git a/api/internals/usecase/division_usecase.go b/api/internals/usecase/division_usecase.go new file mode 100644 index 00000000..77fdff31 --- /dev/null +++ b/api/internals/usecase/division_usecase.go @@ -0,0 +1,147 @@ +package usecase + +import ( + "context" + "fmt" + + rep "github.com/NUTFes/FinanSu/api/externals/repository" + "github.com/NUTFes/FinanSu/api/generated" +) + +type divisionUseCase struct { + rep rep.DivisionRepository +} + +type DivisionUseCase interface { + GetDivisions(context.Context, string, string) (divisionDetails, error) + CreateDivision(context.Context, division) (divisionWithBalance, error) + UpdateDivision(context.Context, string, division) (divisionWithBalance, error) + DestroyDivision(context.Context, string) error +} + +func NewDivisionUseCase(rep rep.DivisionRepository) DivisionUseCase { + return &divisionUseCase{rep} +} + +func (du divisionUseCase) GetDivisions(c context.Context, year string, financialRecordId string) (divisionDetails, error) { + var details divisionDetails + var divisions []divisionWithBalance + + rows, err := du.rep.AllByPeriodAndFinancialRecord(c, year, financialRecordId) + if err != nil { + return divisionDetails{}, err + } + defer rows.Close() + + for rows.Next() { + var division divisionWithBalance + err := rows.Scan( + &division.Id, + &division.Name, + &division.FinancialRecord, + &division.Expense, + &division.Balance, + &division.Budget, + ) + if err != nil { + return divisionDetails{}, err + } + divisions = append(divisions, division) + } + + details.Divisions = &divisions + + var total total + budgetTotal := 0 + expenseTotal := 0 + balanceTotal := 0 + + for _, division := range divisions { + budgetTotal += *division.Budget + expenseTotal += *division.Expense + balanceTotal += *division.Balance + } + + total.Budget = &budgetTotal + total.Expense = &expenseTotal + total.Balance = &balanceTotal + details.Total = &total + + return details, nil +} + +func (du *divisionUseCase) CreateDivision( + c context.Context, + division division, +) (divisionWithBalance, error) { + latestDivisionWithBalance := divisionWithBalance{} + + if err := du.rep.Create(c, division); err != nil { + return latestDivisionWithBalance, err + } + + row, err := du.rep.FindLatestRecord(c) + if err != nil { + fmt.Println(err) + return latestDivisionWithBalance, err + } + err = row.Scan( + &latestDivisionWithBalance.Id, + &latestDivisionWithBalance.Name, + &latestDivisionWithBalance.FinancialRecord, + &latestDivisionWithBalance.Expense, + &latestDivisionWithBalance.Balance, + &latestDivisionWithBalance.Budget, + ) + if err != nil { + return latestDivisionWithBalance, err + } + + return latestDivisionWithBalance, nil +} + +func (du *divisionUseCase) UpdateDivision( + c context.Context, + id string, + division division, +) (divisionWithBalance, error) { + updatedDivisionWithBalance := divisionWithBalance{} + + if err := du.rep.Update(c, id, division); err != nil { + return updatedDivisionWithBalance, err + } + + row, err := du.rep.GetById(c, id) + if err != nil { + return updatedDivisionWithBalance, err + } + err = row.Scan( + &updatedDivisionWithBalance.Id, + &updatedDivisionWithBalance.Name, + &updatedDivisionWithBalance.FinancialRecord, + &updatedDivisionWithBalance.Expense, + &updatedDivisionWithBalance.Balance, + &updatedDivisionWithBalance.Budget, + ) + if err != nil { + return updatedDivisionWithBalance, err + } + + return updatedDivisionWithBalance, nil +} + +func (du *divisionUseCase) DestroyDivision(c context.Context, id string) error { + + if err := du.rep.Delete(c, id); err != nil { + return err + } + return nil +} + +// Note: 型名省略。この中のみで呼ぶために小文字宣言 +type ( + division = generated.Division + divisionDetails = generated.DivisionDetails + divisionWithBalance = generated.DivisionWithBalance + total = generated.Total +) diff --git a/api/router/router.go b/api/router/router.go index f8d3c735..ee302c32 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -14,6 +14,7 @@ type router struct { departmentController controller.DepartmentController expenseController controller.ExpenseController financialRecordController controller.FinancialRecordController + divisionController controller.DivisionController fundInformationController controller.FundInformationController healthcheckController controller.HealthcheckController mailAuthController controller.MailAuthController @@ -41,6 +42,7 @@ func NewRouter( budgetController controller.BudgetController, bureauController controller.BureauController, departmentController controller.DepartmentController, + divisionController controller.DivisionController, expenseController controller.ExpenseController, financialRecordController controller.FinancialRecordController, fundInformationController controller.FundInformationController, @@ -67,6 +69,7 @@ func NewRouter( departmentController, expenseController, financialRecordController, + divisionController, fundInformationController, healthController, mailAuthController, @@ -146,6 +149,12 @@ func (r router) ProvideRouter(e *echo.Echo) { e.PUT("/departments/:id", r.departmentController.UpdateDepartment) e.DELETE("/departments/:id", r.departmentController.DestroyDepartment) + // divisions + e.GET("/divisions", r.divisionController.IndexDivisions) + e.POST("/divisions", r.divisionController.CreateDivision) + e.PUT("/divisions/:id", r.divisionController.UpdateDivision) + e.DELETE("/divisions/:id", r.divisionController.DestroyDivision) + // expenseのRoute e.GET("/expenses", r.expenseController.IndexExpense) e.GET("/expenses/updateTP", r.expenseController.UpdateExpenseTP) From 422b9d70418842742ee7d285f97f8319c0ab1c13 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Wed, 15 Jan 2025 20:18:15 +0900 Subject: [PATCH 05/12] =?UTF-8?q?[fix]=20=E5=9E=8B=E5=90=8D=E3=81=AE?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3&row.Scan=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/internals/usecase/division_usecase.go | 46 +++++++++++------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/api/internals/usecase/division_usecase.go b/api/internals/usecase/division_usecase.go index 77fdff31..e13406eb 100644 --- a/api/internals/usecase/division_usecase.go +++ b/api/internals/usecase/division_usecase.go @@ -13,9 +13,9 @@ type divisionUseCase struct { } type DivisionUseCase interface { - GetDivisions(context.Context, string, string) (divisionDetails, error) - CreateDivision(context.Context, division) (divisionWithBalance, error) - UpdateDivision(context.Context, string, division) (divisionWithBalance, error) + GetDivisions(context.Context, string, string) (DivisionDetails, error) + CreateDivision(context.Context, Division) (DivisionWithBalance, error) + UpdateDivision(context.Context, string, Division) (DivisionWithBalance, error) DestroyDivision(context.Context, string) error } @@ -23,35 +23,35 @@ func NewDivisionUseCase(rep rep.DivisionRepository) DivisionUseCase { return &divisionUseCase{rep} } -func (du divisionUseCase) GetDivisions(c context.Context, year string, financialRecordId string) (divisionDetails, error) { - var details divisionDetails - var divisions []divisionWithBalance +func (du divisionUseCase) GetDivisions(c context.Context, year string, financialRecordId string) (DivisionDetails, error) { + var details DivisionDetails + var divisions []DivisionWithBalance rows, err := du.rep.AllByPeriodAndFinancialRecord(c, year, financialRecordId) if err != nil { - return divisionDetails{}, err + return DivisionDetails{}, err } defer rows.Close() for rows.Next() { - var division divisionWithBalance + var division DivisionWithBalance err := rows.Scan( &division.Id, &division.Name, &division.FinancialRecord, + &division.Budget, &division.Expense, &division.Balance, - &division.Budget, ) if err != nil { - return divisionDetails{}, err + return DivisionDetails{}, err } divisions = append(divisions, division) } details.Divisions = &divisions - var total total + var total Total budgetTotal := 0 expenseTotal := 0 balanceTotal := 0 @@ -72,9 +72,9 @@ func (du divisionUseCase) GetDivisions(c context.Context, year string, financial func (du *divisionUseCase) CreateDivision( c context.Context, - division division, -) (divisionWithBalance, error) { - latestDivisionWithBalance := divisionWithBalance{} + division Division, +) (DivisionWithBalance, error) { + latestDivisionWithBalance := DivisionWithBalance{} if err := du.rep.Create(c, division); err != nil { return latestDivisionWithBalance, err @@ -89,9 +89,9 @@ func (du *divisionUseCase) CreateDivision( &latestDivisionWithBalance.Id, &latestDivisionWithBalance.Name, &latestDivisionWithBalance.FinancialRecord, + &latestDivisionWithBalance.Budget, &latestDivisionWithBalance.Expense, &latestDivisionWithBalance.Balance, - &latestDivisionWithBalance.Budget, ) if err != nil { return latestDivisionWithBalance, err @@ -103,9 +103,9 @@ func (du *divisionUseCase) CreateDivision( func (du *divisionUseCase) UpdateDivision( c context.Context, id string, - division division, -) (divisionWithBalance, error) { - updatedDivisionWithBalance := divisionWithBalance{} + division Division, +) (DivisionWithBalance, error) { + updatedDivisionWithBalance := DivisionWithBalance{} if err := du.rep.Update(c, id, division); err != nil { return updatedDivisionWithBalance, err @@ -119,9 +119,9 @@ func (du *divisionUseCase) UpdateDivision( &updatedDivisionWithBalance.Id, &updatedDivisionWithBalance.Name, &updatedDivisionWithBalance.FinancialRecord, + &updatedDivisionWithBalance.Budget, &updatedDivisionWithBalance.Expense, &updatedDivisionWithBalance.Balance, - &updatedDivisionWithBalance.Budget, ) if err != nil { return updatedDivisionWithBalance, err @@ -138,10 +138,8 @@ func (du *divisionUseCase) DestroyDivision(c context.Context, id string) error { return nil } -// Note: 型名省略。この中のみで呼ぶために小文字宣言 type ( - division = generated.Division - divisionDetails = generated.DivisionDetails - divisionWithBalance = generated.DivisionWithBalance - total = generated.Total + Division = generated.Division + DivisionDetails = generated.DivisionDetails + DivisionWithBalance = generated.DivisionWithBalance ) From 62d483c81db559d0ebab88fb6937ee78248d10c1 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Wed, 15 Jan 2025 20:18:26 +0900 Subject: [PATCH 06/12] =?UTF-8?q?[fix]=20=E5=9E=8B=E5=90=8D=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/controller/division_controller.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/api/externals/controller/division_controller.go b/api/externals/controller/division_controller.go index 94ff25f1..b043dac4 100644 --- a/api/externals/controller/division_controller.go +++ b/api/externals/controller/division_controller.go @@ -27,7 +27,7 @@ func (d *divisionController) IndexDivisions(c echo.Context) error { ctx := c.Request().Context() year := c.QueryParam("year") financialRecordId := c.QueryParam("financial_record_id") - var divisionDetails divisionDetails + var divisionDetails DivisionDetails divisionDetails, err := d.u.GetDivisions(ctx, year, financialRecordId) if err != nil { @@ -38,7 +38,7 @@ func (d *divisionController) IndexDivisions(c echo.Context) error { func (d *divisionController) CreateDivision(c echo.Context) error { ctx := c.Request().Context() - division := new(division) + division := new(Division) if err := c.Bind(division); err != nil { return c.String(http.StatusBadRequest, "Bad Request") @@ -53,7 +53,7 @@ func (d *divisionController) CreateDivision(c echo.Context) error { func (d *divisionController) UpdateDivision(c echo.Context) error { ctx := c.Request().Context() id := c.Param("id") - division := new(division) + division := new(Division) if err := c.Bind(division); err != nil { return c.String(http.StatusBadRequest, "Bad Request") @@ -77,6 +77,6 @@ func (d *divisionController) DestroyDivision(c echo.Context) error { } type ( - division = generated.Division - divisionDetails = generated.DivisionDetails + Division = generated.Division + DivisionDetails = generated.DivisionDetails ) From e9985c868d7df3ef83663e7f61a59357f2e71eae Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Wed, 15 Jan 2025 20:19:09 +0900 Subject: [PATCH 07/12] =?UTF-8?q?[fix]=20query=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/repository/division_repository.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/api/externals/repository/division_repository.go b/api/externals/repository/division_repository.go index 5a94910e..99ae21b0 100644 --- a/api/externals/repository/division_repository.go +++ b/api/externals/repository/division_repository.go @@ -35,7 +35,7 @@ func (dr *divisionRepository) AllByPeriodAndFinancialRecord( financialRecordId string, ) (*sql.Rows, error) { - ds := baseGetQuery + ds := selectDivisionQuery if year != "" { ds = ds.Where(goqu.C("years.year").Eq(year)) @@ -58,7 +58,7 @@ func (dr *divisionRepository) GetById( c context.Context, id string, ) (*sql.Row, error) { - ds, _, err := baseGetQuery. + ds, _, err := selectDivisionQuery. Where(goqu.Ex{"divisions.id": id}). ToSQL() if err != nil { @@ -112,7 +112,7 @@ func (dr *divisionRepository) Delete( // 最新の部門を取得する func (dr *divisionRepository) FindLatestRecord(c context.Context) (*sql.Row, error) { - ds := baseGetQuery + ds := selectDivisionQuery query, _, err := ds.Limit(1).ToSQL() if err != nil { @@ -125,14 +125,14 @@ func (dr *divisionRepository) FindLatestRecord(c context.Context) (*sql.Row, err type division = generated.Division // NOTE: getの共通部分抜き出し -var baseGetQuery = dialect.From("divisions"). +var selectDivisionQuery = dialect.From("divisions"). Select( "divisions.id", "divisions.name", "financial_records.name", goqu.COALESCE(goqu.SUM("item_budgets.amount"), 0).As("budget"), goqu.COALESCE(goqu.SUM("buy_reports.amount"), 0).As("expense"), - goqu.COALESCE(goqu.L("SUM(item_budgets.amount) - SUM(buy_reports.amount)"), 0).As("balance")). + goqu.L("COALESCE(SUM(item_budgets.amount), 0) - COALESCE(SUM(buy_reports.amount), 0)").As("balance")). InnerJoin(goqu.I("financial_records"), goqu.On(goqu.I("financial_records.id").Eq(goqu.I("divisions.financial_record_id")))). InnerJoin(goqu.I("years"), goqu.On(goqu.I("financial_records.year_id").Eq(goqu.I("years.id")))). LeftJoin(goqu.I("festival_items"), goqu.On(goqu.I("divisions.id").Eq(goqu.I("festival_items.division_id")))). From 96b7e675851db423505af57861244efe10ec1f66 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Thu, 16 Jan 2025 18:00:44 +0900 Subject: [PATCH 08/12] =?UTF-8?q?[fix]=20=E4=B8=8D=E8=A6=81=E3=81=AA?= =?UTF-8?q?=E5=AE=A3=E8=A8=80=E3=81=AE=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/controller/division_controller.go | 1 - 1 file changed, 1 deletion(-) diff --git a/api/externals/controller/division_controller.go b/api/externals/controller/division_controller.go index b043dac4..973c1f6c 100644 --- a/api/externals/controller/division_controller.go +++ b/api/externals/controller/division_controller.go @@ -27,7 +27,6 @@ func (d *divisionController) IndexDivisions(c echo.Context) error { ctx := c.Request().Context() year := c.QueryParam("year") financialRecordId := c.QueryParam("financial_record_id") - var divisionDetails DivisionDetails divisionDetails, err := d.u.GetDivisions(ctx, year, financialRecordId) if err != nil { From 1b4fcc317749a252e345bda430cfaf7885a36f12 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Thu, 16 Jan 2025 18:01:24 +0900 Subject: [PATCH 09/12] =?UTF-8?q?[fix]=20=E3=83=AD=E3=82=B0=E3=81=AE?= =?UTF-8?q?=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/internals/usecase/division_usecase.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/api/internals/usecase/division_usecase.go b/api/internals/usecase/division_usecase.go index e13406eb..c01107d6 100644 --- a/api/internals/usecase/division_usecase.go +++ b/api/internals/usecase/division_usecase.go @@ -2,7 +2,6 @@ package usecase import ( "context" - "fmt" rep "github.com/NUTFes/FinanSu/api/externals/repository" "github.com/NUTFes/FinanSu/api/generated" @@ -82,7 +81,6 @@ func (du *divisionUseCase) CreateDivision( row, err := du.rep.FindLatestRecord(c) if err != nil { - fmt.Println(err) return latestDivisionWithBalance, err } err = row.Scan( From 827a0c49044c67b9fcacc1a6d7f0d41c0baafcb0 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Thu, 16 Jan 2025 18:03:52 +0900 Subject: [PATCH 10/12] =?UTF-8?q?[fix]=20=E3=82=AF=E3=82=A8=E3=83=AA?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3&=E3=82=A2=E3=83=83=E3=83=91=E3=83=BC?= =?UTF-8?q?=E3=82=AD=E3=83=A3=E3=83=A1=E3=83=AB=E3=81=AB=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/division_repository.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/api/externals/repository/division_repository.go b/api/externals/repository/division_repository.go index 99ae21b0..699f374c 100644 --- a/api/externals/repository/division_repository.go +++ b/api/externals/repository/division_repository.go @@ -18,8 +18,8 @@ type divisionRepository struct { type DivisionRepository interface { AllByPeriodAndFinancialRecord(context.Context, string, string) (*sql.Rows, error) GetById(context.Context, string) (*sql.Row, error) - Create(context.Context, division) error - Update(context.Context, string, division) error + Create(context.Context, Division) error + Update(context.Context, string, Division) error Delete(context.Context, string) error FindLatestRecord(context.Context) (*sql.Row, error) } @@ -38,15 +38,14 @@ func (dr *divisionRepository) AllByPeriodAndFinancialRecord( ds := selectDivisionQuery if year != "" { - ds = ds.Where(goqu.C("years.year").Eq(year)) + ds = ds.Where(goqu.Ex{"years.year": year}) } - if financialRecordId != "" { - ds = ds.Where(goqu.C("financial_records.id").Eq(financialRecordId)) + ds = ds.Where(goqu.Ex{"financial_records.idr": financialRecordId}) } // クエリを構築し、SQLを生成 - query, _, err := ds.GroupBy("divisions.id").ToSQL() + query, _, err := ds.ToSQL() if err != nil { return nil, err } @@ -70,7 +69,7 @@ func (dr *divisionRepository) GetById( // 部門作成 func (dr *divisionRepository) Create( c context.Context, - division division, + division Division, ) error { ds := dialect.Insert("divisions"). Rows(goqu.Record{"name": division.Name, "financial_record_id": division.FinancialRecordID}) @@ -85,7 +84,7 @@ func (dr *divisionRepository) Create( func (dr *divisionRepository) Update( c context.Context, id string, - division division, + division Division, ) error { ds := dialect.Update("divisions"). Set(goqu.Record{"name": division.Name, "financial_record_id": division.FinancialRecordID}). @@ -121,8 +120,7 @@ func (dr *divisionRepository) FindLatestRecord(c context.Context) (*sql.Row, err return dr.crud.ReadByID(c, query) } -// Note: この中のみで呼ぶために小文字宣言 -type division = generated.Division +type Division = generated.Division // NOTE: getの共通部分抜き出し var selectDivisionQuery = dialect.From("divisions"). From ef31134affb473c4f6b57c31cc4d0395b21b350b Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Fri, 17 Jan 2025 21:26:30 +0900 Subject: [PATCH 11/12] =?UTF-8?q?[fix]=20=E3=82=BF=E3=82=A4=E3=83=9D?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/repository/division_repository.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/externals/repository/division_repository.go b/api/externals/repository/division_repository.go index 699f374c..0ad97afc 100644 --- a/api/externals/repository/division_repository.go +++ b/api/externals/repository/division_repository.go @@ -41,7 +41,7 @@ func (dr *divisionRepository) AllByPeriodAndFinancialRecord( ds = ds.Where(goqu.Ex{"years.year": year}) } if financialRecordId != "" { - ds = ds.Where(goqu.Ex{"financial_records.idr": financialRecordId}) + ds = ds.Where(goqu.Ex{"financial_records.id": financialRecordId}) } // クエリを構築し、SQLを生成 From a1d20f1e4110c3763081109be5d4bbc411da8ac5 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Fri, 17 Jan 2025 21:27:02 +0900 Subject: [PATCH 12/12] =?UTF-8?q?[fix]=20division=20parameter=E3=82=92?= =?UTF-8?q?=E3=82=AD=E3=83=A3=E3=83=A1=E3=83=AB=E3=82=B1=E3=83=BC=E3=82=B9?= =?UTF-8?q?=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/generated/openapi_gen.go | 10 +++++----- openapi/openapi.yaml | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/generated/openapi_gen.go b/api/generated/openapi_gen.go index 77b2153e..62bb8728 100644 --- a/api/generated/openapi_gen.go +++ b/api/generated/openapi_gen.go @@ -263,8 +263,8 @@ type GetDivisionsParams struct { // Year year Year *int `form:"year,omitempty" json:"year,omitempty"` - // FinancialRecordID financialRecordID - FinancialRecordID *int `form:"financialRecordID,omitempty" json:"financialRecordID,omitempty"` + // FinancialRecordId financial_record_id + FinancialRecordId *int `form:"financial_record_id,omitempty" json:"financial_record_id,omitempty"` } // PostExpensesParams defines parameters for PostExpenses. @@ -1483,11 +1483,11 @@ func (w *ServerInterfaceWrapper) GetDivisions(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter year: %s", err)) } - // ------------- Optional query parameter "financialRecordID" ------------- + // ------------- Optional query parameter "financial_record_id" ------------- - err = runtime.BindQueryParameter("form", true, false, "financialRecordID", ctx.QueryParams(), ¶ms.FinancialRecordID) + err = runtime.BindQueryParameter("form", true, false, "financial_record_id", ctx.QueryParams(), ¶ms.FinancialRecordId) if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter financialRecordID: %s", err)) + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter financial_record_id: %s", err)) } // Invoke the callback with all the unmarshaled arguments diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index f880866f..7d4ab555 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -768,9 +768,9 @@ paths: description: year schema: type: integer - - name: financialRecordID + - name: financial_record_id in: query - description: financialRecordID + description: financial_record_id schema: type: integer responses: