Skip to content

Commit

Permalink
Merge pull request #908 from NUTFes/feat/kubosaka/905-create-api-fest…
Browse files Browse the repository at this point in the history
…ival-item

[予算管理]購入物品APIの作成
  • Loading branch information
Kubosaka authored Jan 15, 2025
2 parents 3366ff1 + ad0eb98 commit 127dc88
Show file tree
Hide file tree
Showing 14 changed files with 623 additions and 73 deletions.
3 changes: 2 additions & 1 deletion api/drivers/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package db
import (
"database/sql"
"fmt"
"os"

_ "github.com/go-sql-driver/mysql"
"github.com/joho/godotenv"
"os"
)

type client struct {
Expand Down
78 changes: 78 additions & 0 deletions api/externals/controller/festival_item_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package controller

import (
"net/http"

"github.com/NUTFes/FinanSu/api/generated"
"github.com/NUTFes/FinanSu/api/internals/usecase"
"github.com/labstack/echo/v4"
)

type festivalItemController struct {
u usecase.FestivalItemUseCase
}

type FestivalItemController interface {
IndexFestivalItems(echo.Context) error
CreateFestivalItem(echo.Context) error
UpdateFestivalItem(echo.Context) error
DestroyFestivalItem(echo.Context) error
}

func NewFestivalItemController(u usecase.FestivalItemUseCase) FestivalItemController {
return &festivalItemController{u}
}

func (f *festivalItemController) IndexFestivalItems(c echo.Context) error {
ctx := c.Request().Context()
year := c.QueryParam("year")
divisionId := c.QueryParam("division_id")
var festivalItemDetails FestivalItemDetails

festivalItemDetails, err := f.u.GetFestivalItems(ctx, year, divisionId)
if err != nil {
return err
}
return c.JSON(http.StatusOK, festivalItemDetails)
}

func (f *festivalItemController) CreateFestivalItem(c echo.Context) error {
festivalItem := new(FestivalItem)
if err := c.Bind(festivalItem); err != nil {
return c.String(http.StatusBadRequest, "Bad Request")
}
latestFestivalItem, err := f.u.CreateFestivalItem(c.Request().Context(), *festivalItem)
if err != nil {
return err
}
return c.JSON(http.StatusOK, latestFestivalItem)
}

func (f *festivalItemController) UpdateFestivalItem(c echo.Context) error {
id := c.Param("id")
festivalItem := new(FestivalItem)
if err := c.Bind(festivalItem); err != nil {
return c.String(http.StatusBadRequest, "Bad Request")
}
updatedFestivalItem, err := f.u.UpdateFestivalItem(
c.Request().Context(),
id,
*festivalItem,
)
if err != nil {
return err
}
return c.JSON(http.StatusOK, updatedFestivalItem)
}

func (f *festivalItemController) DestroyFestivalItem(c echo.Context) error {
id := c.Param("id")
err := f.u.DestroyFestivalItem(c.Request().Context(), id)
if err != nil {
return err
}
return c.String(http.StatusOK, "Destroy Festival Item")
}

type FestivalItemDetails = generated.FestivalItemDetails
type FestivalItem = generated.FestivalItem
13 changes: 8 additions & 5 deletions api/externals/controller/financial_record_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func NewFinancialRecordController(u usecase.FinancialRecordUseCase) FinancialRec

func (f *financialRecordController) IndexFinancialRecords(c echo.Context) error {
year := c.QueryParam("year")
var financialRecordDetails generated.FinancialRecordDetails
var financialRecordDetails FinancialRecordDetails
var err error

if year != "" {
Expand All @@ -44,20 +44,20 @@ func (f *financialRecordController) IndexFinancialRecords(c echo.Context) error
}

func (f *financialRecordController) CreateFinancialRecord(c echo.Context) error {
financialRecord := new(generated.FinancialRecord)
financialRecord := new(FinancialRecord)
if err := c.Bind(financialRecord); err != nil {
return c.String(http.StatusBadRequest, "Bad Request")
}
latastFinancialRecord, err := f.u.CreateFinancialRecord(c.Request().Context(), *financialRecord)
latestFinancialRecord, err := f.u.CreateFinancialRecord(c.Request().Context(), *financialRecord)
if err != nil {
return err
}
return c.JSON(http.StatusOK, latastFinancialRecord)
return c.JSON(http.StatusOK, latestFinancialRecord)
}

func (f *financialRecordController) UpdateFinancialRecord(c echo.Context) error {
id := c.Param("id")
financialRecord := new(generated.FinancialRecord)
financialRecord := new(FinancialRecord)
if err := c.Bind(financialRecord); err != nil {
return c.String(http.StatusBadRequest, "Bad Request")
}
Expand All @@ -80,3 +80,6 @@ func (f *financialRecordController) DestroyFinancialRecord(c echo.Context) error
}
return c.String(http.StatusOK, "Destroy FinancialRecord")
}

type FinancialRecordDetails = generated.FinancialRecordDetails
type FinancialRecord = generated.FinancialRecord
26 changes: 26 additions & 0 deletions api/externals/repository/abstract/abstract_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ type Crud interface {
Read(context.Context, string) (*sql.Rows, error)
ReadByID(context.Context, string) (*sql.Row, error)
UpdateDB(context.Context, string) error
StartTransaction(context.Context) (*sql.Tx, error)
TransactionExec(context.Context, *sql.Tx, string) error
Commit(context.Context, *sql.Tx) error
RollBack(context.Context, *sql.Tx) error
}

func NewCrud(client db.Client) Crud {
Expand Down Expand Up @@ -47,3 +51,25 @@ func (a abstractRepository) UpdateDB(ctx context.Context, query string) error {
fmt.Printf("\x1b[36m%s\n", query)
return err
}

func (a abstractRepository) StartTransaction(ctx context.Context) (*sql.Tx, error) {
fmt.Printf("\x1b[36m%s\n", "TransactionStart")
return a.client.DB().BeginTx(ctx, nil)
}

func (a abstractRepository) TransactionExec(ctx context.Context, tx *sql.Tx, query string) error {
fmt.Printf("\x1b[36m%s\n", "TransactionExec")
_, err := tx.ExecContext(ctx, query)
fmt.Printf("\x1b[36m%s\n", query)
return err
}

func (a abstractRepository) Commit(ctx context.Context, tx *sql.Tx) error {
fmt.Printf("\x1b[36m%s\n", "Commit")
return tx.Commit()
}

func (a abstractRepository) RollBack(ctx context.Context, tx *sql.Tx) error {
fmt.Printf("\x1b[36m%s\n", "RollBack")
return tx.Rollback()
}
210 changes: 210 additions & 0 deletions api/externals/repository/festival_item_repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
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 festivalItemRepository struct {
client db.Client
crud abstract.Crud
}

type FestivalItem = generated.FestivalItem
type FestivalItemRepository interface {
AllByPeriodAndDivision(context.Context, string, string) (*sql.Rows, error)
GetById(context.Context, string) (*sql.Row, error)
CreateFestivalItem(context.Context, *sql.Tx, FestivalItem) error
CreateItemBudget(context.Context, *sql.Tx, FestivalItem) error
UpdateFestivalItem(context.Context, *sql.Tx, string, FestivalItem) error
UpdateItemBudget(context.Context, *sql.Tx, string, FestivalItem) error
DeleteFestivalItem(context.Context, *sql.Tx, string) error
DeleteItemBudget(context.Context, *sql.Tx, string) error
FindLatestRecord(context.Context) (*sql.Row, error)
StartTransaction(context.Context) (*sql.Tx, error)
RollBack(context.Context, *sql.Tx) error
Commit(context.Context, *sql.Tx) error
}

func NewFestivalItemRepository(c db.Client, ac abstract.Crud) FestivalItemRepository {
return &festivalItemRepository{c, ac}
}

// 年度別と部門で取得
func (fir *festivalItemRepository) AllByPeriodAndDivision(
c context.Context,
year string,
divisionId string,
) (*sql.Rows, error) {
ds := selectFestivalItemQuery
if divisionId != "" {
ds = ds.Where(goqu.Ex{"divisions.id": divisionId})
}

if year != "" {
ds = ds.Where(goqu.Ex{"years.year": year})
}

query, _, err := ds.ToSQL()

if err != nil {
return nil, err
}

return fir.crud.Read(c, query)
}

// IDで取得
func (fir *festivalItemRepository) GetById(
c context.Context,
id string,
) (*sql.Row, error) {
query, _, err := selectFestivalItemQuery.Where(goqu.Ex{"festival_items.id": id}).ToSQL()

if err != nil {
return nil, err
}
return fir.crud.ReadByID(c, query)
}

// 購入物品作成
func (fir *festivalItemRepository) CreateFestivalItem(
c context.Context,
tx *sql.Tx,
festivalItem FestivalItem,
) error {
ds := dialect.Insert("festival_items").
Rows(goqu.Record{"name": festivalItem.Name, "memo": festivalItem.Memo, "division_id": festivalItem.DivisionId})
query, _, err := ds.ToSQL()
if err != nil {
return err
}
err = fir.crud.TransactionExec(c, tx, query)
return err
}

func (fir *festivalItemRepository) CreateItemBudget(
c context.Context,
tx *sql.Tx,
festivalItem FestivalItem,
) error {
ds := dialect.Insert("item_budgets").
Rows(goqu.Record{"amount": festivalItem.Amount, "festival_item_id": goqu.L("LAST_INSERT_ID()")})
query, _, err := ds.ToSQL()
if err != nil {
return err
}
err = fir.crud.TransactionExec(c, tx, query)
return err
}

// festivalItem編集
func (fir *festivalItemRepository) UpdateFestivalItem(
c context.Context,
tx *sql.Tx,
id string,
festivalItem FestivalItem,
) error {
ds := dialect.Update("festival_items").
Set(goqu.Record{"name": festivalItem.Name, "memo": festivalItem.Memo, "division_id": festivalItem.DivisionId}).
Where(goqu.Ex{"id": id})
query, _, err := ds.ToSQL()
if err != nil {
return err
}
err = fir.crud.TransactionExec(c, tx, query)
return err
}

// itemBudget編集
func (fir *festivalItemRepository) UpdateItemBudget(
c context.Context,
tx *sql.Tx,
id string,
festivalItem FestivalItem,
) error {
ds := dialect.Update("item_budgets").
Set(goqu.Record{"amount": festivalItem.Amount}).
Where(goqu.Ex{"festival_item_id": id})
query, _, err := ds.ToSQL()
if err != nil {
return err
}
err = fir.crud.TransactionExec(c, tx, query)
return err
}

// 購入物品削除
func (fir *festivalItemRepository) DeleteFestivalItem(
c context.Context,
tx *sql.Tx,
id string,
) error {
ds := dialect.Delete("festival_items").Where(goqu.Ex{"id": id})
query, _, err := ds.ToSQL()
if err != nil {
return err
}
err = fir.crud.TransactionExec(c, tx, query)
return err
}

// 予算削除
func (fir *festivalItemRepository) DeleteItemBudget(
c context.Context,
tx *sql.Tx,
id string,
) error {
ds := dialect.Delete("item_budgets").Where(goqu.Ex{"festival_item_id": id})
query, _, err := ds.ToSQL()
if err != nil {
return err
}
err = fir.crud.TransactionExec(c, tx, query)
return err
}

// 最新のfestivalItemを取得する
func (fir *festivalItemRepository) FindLatestRecord(c context.Context) (*sql.Row, error) {
query, _, err := selectFestivalItemQuery.Limit(1).ToSQL()

if err != nil {
return nil, err
}
return fir.crud.ReadByID(c, query)
}

func (fir *festivalItemRepository) StartTransaction(c context.Context) (*sql.Tx, error) {
return fir.crud.StartTransaction(c)
}

func (fir *festivalItemRepository) RollBack(c context.Context, tx *sql.Tx) error {
return fir.crud.RollBack(c, tx)
}

func (fir *festivalItemRepository) Commit(c context.Context, tx *sql.Tx) error {
return fir.crud.Commit(c, tx)
}

var selectFestivalItemQuery = dialect.Select(
"festival_items.id",
"festival_items.name",
"festival_items.memo",
"financial_records.name",
"divisions.name",
goqu.L("COALESCE(`item_budgets`.`amount`, 0)").As("budget"),
goqu.COALESCE(goqu.SUM("buy_reports.amount"), 0).As("expense"),
goqu.L("COALESCE(SUM(item_budgets.amount), 0) - COALESCE(SUM(buy_reports.amount), 0)").As("balance")).
From("festival_items").
InnerJoin(goqu.I("divisions"), goqu.On(goqu.I("festival_items.division_id").Eq(goqu.I("divisions.id")))).
InnerJoin(goqu.I("financial_records"), goqu.On(goqu.I("divisions.financial_record_id").Eq(goqu.I("financial_records.id")))).
InnerJoin(goqu.I("years"), goqu.On(goqu.I("financial_records.year_id").Eq(goqu.I("years.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("festival_items.id", "item_budgets.amount").
Order(goqu.I("festival_items.id").Desc())
Loading

0 comments on commit 127dc88

Please sign in to comment.