From 1535dc5abad67153452a66fd9b5d73133698d306 Mon Sep 17 00:00:00 2001 From: Kubosaka Date: Sun, 12 Nov 2023 15:47:16 +0900 Subject: [PATCH 01/54] =?UTF-8?q?db=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/db/purchase_orders.sql | 2 ++ mysql/db/year_records.sql | 14 ++++++++++++++ mysql/db/years.sql | 1 + 3 files changed, 17 insertions(+) create mode 100644 mysql/db/year_records.sql diff --git a/mysql/db/purchase_orders.sql b/mysql/db/purchase_orders.sql index 1804fd92b..96cc8531a 100644 --- a/mysql/db/purchase_orders.sql +++ b/mysql/db/purchase_orders.sql @@ -17,3 +17,5 @@ INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) value INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2022-3-28', 1, 3, false); INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2022-4-6', 1, 4, true); INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2022-4-6', 1, 5, true); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check, created_at, updated_at) values ('2024-4-6', 1, 4, true, '2023-11-16 00:00:00', '2023-11-16 00:00:00'); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check, created_at, updated_at) values ('2024-4-6', 1, 5, true, '2023-11-16 00:00:00', '2023-11-16 00:00:00'); diff --git a/mysql/db/year_records.sql b/mysql/db/year_records.sql new file mode 100644 index 000000000..0d9cb396c --- /dev/null +++ b/mysql/db/year_records.sql @@ -0,0 +1,14 @@ +use finansu_db; + +CREATE TABLE year_records ( + id int(10) unsigned not null auto_increment, + year_id int(10) not null, + started_at datetime not null, + ended_at datetime not null, + created_at datetime not null default current_timestamp, + updated_at datetime not null default current_timestamp on update current_timestamp, + PRIMARY KEY (id) +); + +INSERT INTO year_records (year_id, started_at, ended_at) values (2, '2022-01-01 00:00:00', '2023-11-15 00:00:00'); +INSERT INTO year_records (year_id, started_at, ended_at) values (3, '2023-11-15 00:00:00', '2024-11-15 00:00:00'); diff --git a/mysql/db/years.sql b/mysql/db/years.sql index a7a55a4cd..df6d3a45e 100644 --- a/mysql/db/years.sql +++ b/mysql/db/years.sql @@ -10,3 +10,4 @@ CREATE TABLE years ( INSERT into years (year) values (2022); INSERT into years (year) values (2023); +INSERT into years (year) values (2024); From 272a7d0d628b3f067a9b7cb9205c243e83ae8e78 Mon Sep 17 00:00:00 2001 From: Kubosaka Date: Sun, 12 Nov 2023 16:27:08 +0900 Subject: [PATCH 02/54] =?UTF-8?q?api=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/purhcase_order_controller.go | 10 ++++ .../repository/purchase_order_repository.go | 40 ++++++++++++++ .../usecase/purchase_order_usecase.go | 55 +++++++++++++++++++ api/router/router.go | 1 + mysql/db/purcahse_items.sql | 4 +- 5 files changed, 108 insertions(+), 2 deletions(-) diff --git a/api/externals/controller/purhcase_order_controller.go b/api/externals/controller/purhcase_order_controller.go index ce86a2d48..b853fc774 100644 --- a/api/externals/controller/purhcase_order_controller.go +++ b/api/externals/controller/purhcase_order_controller.go @@ -19,6 +19,7 @@ type PurchaseOrderController interface { DestroyPurchaseOrder(echo.Context) error IndexOrderDetail(echo.Context) error ShowOrderDetail(echo.Context) error + IndexOrderDetailByYear(echo.Context) error } func NewPurchaseOrderController(u usecase.PurchaseOrderUseCase) PurchaseOrderController { @@ -99,3 +100,12 @@ func (p *purchaseOrderController) ShowOrderDetail(c echo.Context) error { } return c.JSON(http.StatusOK, orderDetail) } + +func (p *purchaseOrderController) IndexOrderDetailByYear(c echo.Context) error { + year := c.Param("year") + orderDetails, err := p.u.GetPurchaseOrderDetailsByYear(c.Request().Context(), year) + if err != nil { + return err + } + return c.JSON(http.StatusOK, orderDetails) +} diff --git a/api/externals/repository/purchase_order_repository.go b/api/externals/repository/purchase_order_repository.go index 696cd34c8..f4e6ea99e 100644 --- a/api/externals/repository/purchase_order_repository.go +++ b/api/externals/repository/purchase_order_repository.go @@ -25,6 +25,7 @@ type PurchaseOrderRepository interface { FindNewRecord(context.Context) (*sql.Row, error) DeleteItems(context.Context, string) error DeleteReport(context.Context, string) error + AllUserInfoByYear(context.Context, string) (*sql.Rows, error) } func NewPurchaseOrderRepository(c db.Client, ac abstract.Crud) PurchaseOrderRepository { @@ -160,3 +161,42 @@ func (por *purchaseOrderRepository) DeleteReport( query := `DELETE FROM purchase_reports WHERE purchase_order_id =` + id return por.crud.UpdateDB(c, query) } + +func (p *purchaseOrderRepository) AllUserInfoByYear(c context.Context, year string) (*sql.Rows, error) { + query := ` + SELECT + purchase_orders.id, + purchase_orders.deadline, + purchase_orders.user_id, + purchase_orders.expense_id, + purchase_orders.finance_check, + purchase_orders.created_at, + purchase_orders.updated_at, + users.id, + users.name, + users.bureau_id, + users.role_id, + users.created_at, + users.updated_at + FROM + purchase_orders + INNER JOIN + users + ON + purchase_orders.user_id = users.id + INNER JOIN + year_records + ON + purchase_orders.created_at > year_records.started_at + AND + purchase_orders.created_at < year_records.ended_at + INNER JOIN + years + ON + year_records.year_id = years.id + WHERE + years.year = ` + year + + " ORDER BY purchase_orders.id" + return p.crud.Read(c, query) +} + diff --git a/api/internals/usecase/purchase_order_usecase.go b/api/internals/usecase/purchase_order_usecase.go index 70a19a04f..602a13d15 100644 --- a/api/internals/usecase/purchase_order_usecase.go +++ b/api/internals/usecase/purchase_order_usecase.go @@ -20,6 +20,7 @@ type PurchaseOrderUseCase interface { DestroyPurchaseOrder(context.Context, string) error GetPurchaseOrderDetails(context.Context) ([]domain.OrderDetail, error) GetPurchaseOrderDetailByID(context.Context, string) (domain.OrderDetail, error) + GetPurchaseOrderDetailsByYear(context.Context, string) ([]domain.OrderDetail, error) } func NewPurchaseOrderUseCase(rep rep.PurchaseOrderRepository) PurchaseOrderUseCase { @@ -242,3 +243,57 @@ func (p *purchaseOrderUseCase) GetPurchaseOrderDetailByID(c context.Context, id orderDetail.PurchaseItem = purchaseItems return orderDetail, nil } + +func (p *purchaseOrderUseCase) GetPurchaseOrderDetailsByYear(c context.Context, year string) ([]domain.OrderDetail, error) { + orderDetail := domain.OrderDetail{} + var orderDetails []domain.OrderDetail + purchaseItem := domain.PurchaseItem{} + var purchaseItems []domain.PurchaseItem + rows, err := p.rep.AllUserInfoByYear(c, year) + if err != nil { + return nil, err + } + for rows.Next() { + err := rows.Scan( + &orderDetail.PurchaseOrder.ID, + &orderDetail.PurchaseOrder.DeadLine, + &orderDetail.PurchaseOrder.UserID, + &orderDetail.PurchaseOrder.ExpenseID, + &orderDetail.PurchaseOrder.FinanceCheck, + &orderDetail.PurchaseOrder.CreatedAt, + &orderDetail.PurchaseOrder.UpdatedAt, + &orderDetail.User.ID, + &orderDetail.User.Name, + &orderDetail.User.BureauID, + &orderDetail.User.RoleID, + &orderDetail.User.CreatedAt, + &orderDetail.User.UpdatedAt, + ) + if err != nil { + return nil, err + } + rows, err := p.rep.FindPurchaseItem(c, strconv.Itoa(int(orderDetail.PurchaseOrder.ID))) + for rows.Next() { + err := rows.Scan( + &purchaseItem.ID, + &purchaseItem.Item, + &purchaseItem.Price, + &purchaseItem.Quantity, + &purchaseItem.Detail, + &purchaseItem.Url, + &purchaseItem.PurchaseOrderID, + &purchaseItem.FinanceCheck, + &purchaseItem.CreatedAt, + &purchaseItem.UpdatedAt, + ) + if err != nil { + return nil, err + } + purchaseItems = append(purchaseItems, purchaseItem) + } + orderDetail.PurchaseItem = purchaseItems + orderDetails = append(orderDetails, orderDetail) + purchaseItems = nil + } + return orderDetails, nil +} diff --git a/api/router/router.go b/api/router/router.go index 133e6e447..249e342f1 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -159,6 +159,7 @@ func (r router) ProvideRouter(e *echo.Echo) { e.DELETE("/purchaseorders/:id", r.purchaseOrderController.DestroyPurchaseOrder) e.GET("/purchaseorders/details", r.purchaseOrderController.IndexOrderDetail) e.GET("/purchaseorders/:id/details", r.purchaseOrderController.ShowOrderDetail) + e.GET("/purchaseorders/details/:year", r.purchaseOrderController.IndexOrderDetailByYear) // purchasereportsのRoute e.GET("/purchasereports", r.purchaseReportController.IndexPurchaseReport) diff --git a/mysql/db/purcahse_items.sql b/mysql/db/purcahse_items.sql index 485e5ce85..01fe8faab 100644 --- a/mysql/db/purcahse_items.sql +++ b/mysql/db/purcahse_items.sql @@ -21,5 +21,5 @@ INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_i INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('机', 20000, 2, 'test-detail2', 'https://nutfes.net', 3, true); INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('椅子', 30000, 3, 'test-detail3', 'https://nutfes.net', 3, false); INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('酒', 10000, 10, 'test-detail', 'https://nutfes.net', 4, true); -INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('封筒', 100, 100, 'test-detail2', 'https://nutfes.net', 5, false); -INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('領収書', 100, 50, 'test-detail3', 'https://nutfes.net', 6, true); +INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('封筒', 100, 100, 'test-detail2', 'https://nutfes.net', 8, false); +INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('領収書', 100, 50, 'test-detail3', 'https://nutfes.net', 7, true); From 5ab737e67418211c18768b00fea7166638ef41ed Mon Sep 17 00:00:00 2001 From: Kubosaka Date: Mon, 13 Nov 2023 21:46:31 +0900 Subject: [PATCH 03/54] =?UTF-8?q?=E8=B3=BC=E5=85=A5=E7=94=B3=E8=AB=8B?= =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E5=B9=B4=E5=BA=A6=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/purchaseorders/index.tsx | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/view/next-project/src/pages/purchaseorders/index.tsx b/view/next-project/src/pages/purchaseorders/index.tsx index bc3434b44..9f1e80690 100644 --- a/view/next-project/src/pages/purchaseorders/index.tsx +++ b/view/next-project/src/pages/purchaseorders/index.tsx @@ -22,11 +22,12 @@ interface Props { expenses: Expense[]; } export async function getServerSideProps() { - const getPurchaseOrderViewUrl = process.env.SSR_API_URI + '/purchaseorders/details'; + const currentYear = '2024'; + const getPurchaseOrderViewUrl = + process.env.SSR_API_URI + '/purchaseorders/details/' + currentYear; const getExpenseUrl = process.env.SSR_API_URI + '/expenses'; const purchaseOrderViewRes = await get(getPurchaseOrderViewUrl); const expenseRes = await get(getExpenseUrl); - return { props: { purchaseOrderView: purchaseOrderViewRes, @@ -64,14 +65,15 @@ export default function PurchaseOrders(props: Props) { return datetime2; }; - const currentYear = new Date().getFullYear().toString(); - const [selectedYear, setSelectedYear] = useState(currentYear); + const [selectedYear, setSelectedYear] = useState('2024'); - const filteredPurchaseOrderViews = useMemo(() => { - return purchaseOrderViews.filter((purchaseOrderView: PurchaseOrderView) => { - return purchaseOrderView.purchaseOrder.createdAt?.includes(selectedYear); - }); - }, [purchaseOrderViews, selectedYear]); + const getPurchaseOrders = async () => { + const getPurchaseOrderViewUrlByYear = + process.env.CSR_API_URI + '/purchaseorders/details/' + selectedYear; + console.log(getPurchaseOrderViewUrlByYear); + const getPurchaseOrderByYears = await get(getPurchaseOrderViewUrlByYear); + setPurchaseOrderViews(getPurchaseOrderByYears); + }; // 購入申請の合計金額を計算 // // 申請を出した時点では購入物品のチェックはfalseなので、finance_check関係なく計算 @@ -85,24 +87,28 @@ export default function PurchaseOrders(props: Props) { // 全ての購入申請の合計金額を計算 const totalPurchaseOrderFee = useMemo(() => { - if (filteredPurchaseOrderViews) { + if (purchaseOrderViews) { let totalFee = 0; - filteredPurchaseOrderViews.map((purchaseOrderView: PurchaseOrderView) => { + purchaseOrderViews.map((purchaseOrderView: PurchaseOrderView) => { totalFee += TotalFee(purchaseOrderView.purchaseItem); }); return totalFee; } return 0; - }, [filteredPurchaseOrderViews]); + }, [purchaseOrderViews]); useEffect(() => { - if (filteredPurchaseOrderViews) { - const purchaseOrderChecks = filteredPurchaseOrderViews.map((purchaseOrderView) => { + getPurchaseOrders(); + }, [selectedYear]); + + useEffect(() => { + if (purchaseOrderViews) { + const purchaseOrderChecks = purchaseOrderViews.map((purchaseOrderView) => { return purchaseOrderView.purchaseOrder.financeCheck; }); setPurchaseOrderChecks(purchaseOrderChecks); } - }, [filteredPurchaseOrderViews]); + }, [purchaseOrderViews]); const updatePurchaseOrder = async (purchaseOrderID: number, purchaseOrder: PurchaseOrder) => { const url = process.env.CSR_API_URI + '/purchaseorders/' + purchaseOrderID; @@ -160,19 +166,20 @@ export default function PurchaseOrders(props: Props) { <select className='w-100 ' - defaultValue={currentYear} - onChange={(e) => setSelectedYear(e.target.value)} + defaultValue={selectedYear} + onChange={async (e) => { + setSelectedYear(e.target.value); + }} > - <option value='2021'>2021</option> - <option value='2022'>2022</option> - <option value='2023'>2023</option> + <option value='2023'>2023年度</option> + <option value='2024'>2024年度</option> </select> <PrimaryButton className='hidden md:block' onClick={async () => { downloadFile({ downloadContent: await createPurchaseOrdersCsv( - filteredPurchaseOrderViews, + purchaseOrderViews, props.expenses, ), fileName: `購入申請一覧(${selectedYear})_${formatYYYYMMDD(new Date())}.csv`, @@ -213,8 +220,8 @@ export default function PurchaseOrders(props: Props) { </tr> </thead> <tbody className='border border-x-white-0 border-b-primary-1 border-t-white-0'> - {filteredPurchaseOrderViews && - filteredPurchaseOrderViews.map((purchaseOrderViewItem, index) => ( + {purchaseOrderViews && + purchaseOrderViews.map((purchaseOrderViewItem, index) => ( <tr className='border-b' key={purchaseOrderViewItem.purchaseOrder.id}> <td className='py-3'> <div className='text-center text-sm text-black-600'> @@ -324,7 +331,7 @@ export default function PurchaseOrders(props: Props) { </td> </tr> ))} - {filteredPurchaseOrderViews.length > 0 && ( + {purchaseOrderViews.length > 0 && ( <tr className='border-b border-primary-1'> <td className='px-1 py-3' colSpan={5}> <div className='flex justify-end'> @@ -338,7 +345,7 @@ export default function PurchaseOrders(props: Props) { </td> </tr> )} - {!filteredPurchaseOrderViews.length && ( + {!purchaseOrderViews.length && ( <tr className='border-b border-primary-1'> <td className='px-1 py-3' colSpan={7}> <div className='flex justify-center'> From 67464c15c28b536471ed620bd9e661c875c0aff9 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Mon, 13 Nov 2023 22:08:41 +0900 Subject: [PATCH 04/54] =?UTF-8?q?=E6=9C=9F=E9=96=93=E5=8F=96=E5=BE=97?= =?UTF-8?q?=E3=81=99=E3=82=8BAPI=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/controller/year_controller.go | 13 ++++++++- api/externals/repository/year_repository.go | 19 ++++++++++++++ api/internals/domain/year.go | 10 +++++++ api/internals/usecase/year_usecase.go | 29 +++++++++++++++++++++ api/router/router.go | 3 +++ 5 files changed, 73 insertions(+), 1 deletion(-) diff --git a/api/externals/controller/year_controller.go b/api/externals/controller/year_controller.go index a3b98f4bd..962ed835e 100644 --- a/api/externals/controller/year_controller.go +++ b/api/externals/controller/year_controller.go @@ -1,9 +1,10 @@ package controller import ( + "net/http" + "github.com/NUTFes/FinanSu/api/internals/usecase" "github.com/labstack/echo/v4" - "net/http" ) type yearController struct { @@ -16,6 +17,7 @@ type YearController interface { CreateYear(echo.Context) error UpdateYear(echo.Context) error DestroyYear(echo.Context) error + IndexYearPeriods(echo.Context) error } func NewYearController(u usecase.YearUseCase) YearController { @@ -71,3 +73,12 @@ func (y *yearController) DestroyYear(c echo.Context) error { } return c.String(http.StatusOK, "Destroy Year") } + +func (y *yearController) IndexYearPeriods(c echo.Context) error { + years, err := y.u.GetYearPeriods(c.Request().Context()) + if err != nil { + return err + } + return c.JSON(http.StatusOK, years) +} + diff --git a/api/externals/repository/year_repository.go b/api/externals/repository/year_repository.go index 78c61cb77..38d67bfcf 100644 --- a/api/externals/repository/year_repository.go +++ b/api/externals/repository/year_repository.go @@ -20,6 +20,7 @@ type YearRepository interface { Update(context.Context, string, string) error Destroy(context.Context, string) error FindLatestRecord(context.Context) (*sql.Row, error) + AllYearPeriods(context.Context) (*sql.Rows, error) } func NewYearRepository(c db.Client, ac abstract.Crud) YearRepository { @@ -55,3 +56,21 @@ func (y *yearRepository) FindLatestRecord(c context.Context) (*sql.Row, error) { query := `SELECT * FROM years ORDER BY id DESC LIMIT 1` return y.crud.ReadByID(c, query) } + +func (y *yearRepository) AllYearPeriods(c context.Context) (*sql.Rows, error) { + query := ` + SELECT + years.id, + years.year, + year_records.started_at, + year_records.ended_at, + year_records.created_at, + year_records.updated_at + FROM + years + INNER JOIN + year_records + ON + years.id = year_records.year_id` + return y.crud.Read(c, query) +} diff --git a/api/internals/domain/year.go b/api/internals/domain/year.go index e1c825c88..e870299e2 100644 --- a/api/internals/domain/year.go +++ b/api/internals/domain/year.go @@ -10,3 +10,13 @@ type Year struct { CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` } + +type YearPeriod struct { + ID ID `json:"id"` + Year int `json:"year"` + StartedAt time.Time `json:"startedAt"` + EndedAt time.Time `json:"endedAt"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + diff --git a/api/internals/usecase/year_usecase.go b/api/internals/usecase/year_usecase.go index 2a64dea0f..b1a36b68a 100644 --- a/api/internals/usecase/year_usecase.go +++ b/api/internals/usecase/year_usecase.go @@ -2,6 +2,7 @@ package usecase import ( "context" + rep "github.com/NUTFes/FinanSu/api/externals/repository" "github.com/NUTFes/FinanSu/api/internals/domain" "github.com/pkg/errors" @@ -17,6 +18,7 @@ type YearUseCase interface { CreateYear(context.Context, string) (domain.Year, error) UpdateYear(context.Context, string, string) (domain.Year, error) DestroyYear(context.Context, string) error + GetYearPeriods(context.Context) ([]domain.YearPeriod, error) } func NewYearUseCase(rep rep.YearRepository) YearUseCase { @@ -106,3 +108,30 @@ func (y *yearUseCase) DestroyYear(c context.Context, id string) error { err := y.rep.Destroy(c, id) return err } + + +func (y *yearUseCase) GetYearPeriods(c context.Context) ([]domain.YearPeriod, error) { + yearPeriod := domain.YearPeriod{} + var yearPeriods []domain.YearPeriod + rows, err := y.rep.AllYearPeriods(c) + if err != nil { + return nil, err + } + defer rows.Close() + for rows.Next() { + err := rows.Scan( + &yearPeriod.ID, + &yearPeriod.Year, + &yearPeriod.StartedAt, + &yearPeriod.EndedAt, + &yearPeriod.CreatedAt, + &yearPeriod.UpdatedAt, + ) + if err != nil { + return nil, errors.Wrapf(err, "cannot connect SQL") + } + + yearPeriods = append(yearPeriods, yearPeriod) + } + return yearPeriods, nil +} diff --git a/api/router/router.go b/api/router/router.go index 249e342f1..e07971633 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -212,4 +212,7 @@ func (r router) ProvideRouter(e *echo.Echo) { e.PUT("/years/:id", r.yearController.UpdateYear) e.DELETE("/years/:id", r.yearController.DestroyYear) + // year_periods + e.GET("/years/periods", r.yearController.IndexYearPeriods) + } From 1c3c703f0e14bbe1bb05f7f069f84dbad3d14c83 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Mon, 13 Nov 2023 22:51:02 +0900 Subject: [PATCH 05/54] =?UTF-8?q?=E5=B9=B4=E5=BA=A6=E4=B8=80=E8=A6=A7?= =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AE=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/year_periods/index.tsx | 153 ++++++++++++++++++ view/next-project/src/type/common.ts | 10 ++ 2 files changed, 163 insertions(+) create mode 100644 view/next-project/src/pages/year_periods/index.tsx diff --git a/view/next-project/src/pages/year_periods/index.tsx b/view/next-project/src/pages/year_periods/index.tsx new file mode 100644 index 000000000..f28096172 --- /dev/null +++ b/view/next-project/src/pages/year_periods/index.tsx @@ -0,0 +1,153 @@ +import clsx from 'clsx'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import { useEffect, useState, useMemo } from 'react'; +import { useRecoilValue } from 'recoil'; + +import { authAtom } from '@/store/atoms'; +import { getCurrentUser } from '@/utils/api/currentUser'; +import { get } from '@api/api_methods'; +import { Card, Title } from '@components/common'; +import MainLayout from '@components/layout/MainLayout/MainLayout'; +import { YearRecords, User } from '@type/common'; + +interface Props { + yearRecords: YearRecords[]; +} + +export const getServerSideProps = async () => { + const getPeriodURL = process.env.SSR_API_URI + '/years/periods'; + const periodsRes = await get(getPeriodURL); + + return { + props: { + yearRecords: periodsRes, + }, + }; +}; + +export default function Periods(props: Props) { + const { yearRecords } = props; + const router = useRouter(); + + const auth = useRecoilValue(authAtom); + const [currentUser, setCurrentUser] = useState<User>(); + + const formatYearRecords = yearRecords.map((yearRecord) => { + return { + ...yearRecord, + startedAt: yearRecord.startedAt && new Date(yearRecord.startedAt).toLocaleDateString('ja'), + endedAt: yearRecord.endedAt && new Date(yearRecord.endedAt).toLocaleDateString('ja'), + }; + }); + + useEffect(() => { + const getUser = async () => { + const res = await getCurrentUser(auth); + setCurrentUser(res); + }; + getUser(); + }, []); + + // ログイン中のユーザの権限 + const isDeveloper = useMemo(() => { + if (currentUser?.roleID === 2) { + return true; + } else { + return false; + } + }, [currentUser?.roleID]); + + useEffect(() => { + if (!currentUser?.roleID) return; + if (!isDeveloper) { + router.push('/purchaseorders'); + } + }, [isDeveloper, currentUser?.roleID]); + + return ( + <MainLayout> + <Head> + <title>年度一覧 + + + + +
+
+ + </div> + </div> + <div className='mb-2 p-5'> + <table className='mb-5 w-full table-auto border-collapse'> + <thead> + <tr> + <th className='w-1/4 border border-x-white-0 border-b-primary-1 border-t-white-0 py-3'> + <p className='text-center text-sm text-black-600'>ID</p> + </th> + <th className='w-1/4 border border-x-white-0 border-b-primary-1 border-t-white-0 py-3'> + <p className='text-center text-sm text-black-600'>年度</p> + </th> + <th className='w-1/4 border border-x-white-0 border-b-primary-1 border-t-white-0 py-3'> + <p className='text-center text-sm text-black-600'>開始日</p> + </th> + <th className='w-1/4 border border-x-white-0 border-b-primary-1 border-t-white-0 py-3'> + <p className='text-center text-sm text-black-600'>終了日</p> + </th> + </tr> + </thead> + <tbody className='border border-x-white-0 border-b-primary-1 border-t-white-0'> + {formatYearRecords.map((yearRecord: YearRecords, index) => ( + <tr key={yearRecord.id}> + <td + className={clsx( + 'px-1 py-3', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + > + <p className='text-center text-sm text-black-600'>{yearRecord.id}</p> + </td> + <td + className={clsx( + 'px-1', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + > + <p className='text-center text-sm text-black-600'>{yearRecord.year}</p> + </td> + <td + className={clsx( + 'px-1', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + > + <p className='text-center text-sm text-black-600'>{yearRecord.startedAt}</p> + </td> + <td + className={clsx( + 'px-1', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + > + <p className='text-center text-sm text-black-600'>{yearRecord.endedAt}</p> + </td> + <td + className={clsx( + 'px-1', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + ></td> + </tr> + ))} + </tbody> + </table> + </div> + </Card> + </MainLayout> + ); +} diff --git a/view/next-project/src/type/common.ts b/view/next-project/src/type/common.ts index 77e6d8316..fdef5df92 100644 --- a/view/next-project/src/type/common.ts +++ b/view/next-project/src/type/common.ts @@ -232,3 +232,13 @@ export interface PurchaseReportView { reportUser: User; purchaseItems: PurchaseItem[]; } + +// // Year(年度) +export interface YearRecords { + id?: number; + year: number; + startedAt?: string; + endedAt?: string; + createdAt?: string; + updatedAt?: string; +} From 240de947ba4a49ca7512ea498528efa50bb493a9 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Tue, 14 Nov 2023 20:17:51 +0900 Subject: [PATCH 06/54] =?UTF-8?q?=E5=B9=B4=E5=BA=A6=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?=E3=81=AEAPI=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/controller/year_controller.go | 11 +++++ api/externals/repository/year_repository.go | 48 +++++++++++++++++++++ api/internals/usecase/year_usecase.go | 19 ++++++++ api/router/router.go | 1 + 4 files changed, 79 insertions(+) diff --git a/api/externals/controller/year_controller.go b/api/externals/controller/year_controller.go index 962ed835e..1883cd733 100644 --- a/api/externals/controller/year_controller.go +++ b/api/externals/controller/year_controller.go @@ -18,6 +18,7 @@ type YearController interface { UpdateYear(echo.Context) error DestroyYear(echo.Context) error IndexYearPeriods(echo.Context) error + CreateYearPeriod(echo.Context) error } func NewYearController(u usecase.YearUseCase) YearController { @@ -82,3 +83,13 @@ func (y *yearController) IndexYearPeriods(c echo.Context) error { return c.JSON(http.StatusOK, years) } +func (y *yearController) CreateYearPeriod(c echo.Context) error { + year := c.QueryParam("year") + startedAt := c.QueryParam("startedAt") + endedAt := c.QueryParam("endedAt") + latestYear, err := y.u.CreateYearPeriod(c.Request().Context(), year, startedAt, endedAt) + if err != nil { + return err + } + return c.JSON(http.StatusCreated, latestYear) +} diff --git a/api/externals/repository/year_repository.go b/api/externals/repository/year_repository.go index 38d67bfcf..5bb970756 100644 --- a/api/externals/repository/year_repository.go +++ b/api/externals/repository/year_repository.go @@ -3,6 +3,7 @@ package repository import ( "context" "database/sql" + "strconv" "github.com/NUTFes/FinanSu/api/drivers/db" "github.com/NUTFes/FinanSu/api/externals/repository/abstract" @@ -21,6 +22,8 @@ type YearRepository interface { Destroy(context.Context, string) error FindLatestRecord(context.Context) (*sql.Row, error) AllYearPeriods(context.Context) (*sql.Rows, error) + CreateYearPeriod(context.Context, string, string, string) error + FindPeriodLatestRecord(context.Context) (*sql.Row, error) } func NewYearRepository(c db.Client, ac abstract.Crud) YearRepository { @@ -57,6 +60,27 @@ func (y *yearRepository) FindLatestRecord(c context.Context) (*sql.Row, error) { return y.crud.ReadByID(c, query) } +func (y *yearRepository) FindPeriodLatestRecord(c context.Context) (*sql.Row, error) { + query := ` + SELECT + years.id, + years.year, + year_records.started_at, + year_records.ended_at, + year_records.created_at, + year_records.updated_at + FROM + years + INNER JOIN + year_records + ON + years.id = year_records.year_id + ORDER BY + year_records.id + DESC LIMIT 1` + return y.crud.ReadByID(c, query) +} + func (y *yearRepository) AllYearPeriods(c context.Context) (*sql.Rows, error) { query := ` SELECT @@ -74,3 +98,27 @@ func (y *yearRepository) AllYearPeriods(c context.Context) (*sql.Rows, error) { years.id = year_records.year_id` return y.crud.Read(c, query) } + +func (y *yearRepository) CreateYearPeriod(c context.Context, year string, startedAt string, endedAt string) error { + query := `INSERT INTO years (year) VALUES (` + year + ");" + y.crud.UpdateDB(c, query) + query = `SELECT LAST_INSERT_ID() AS last_id;` + row, err := y.crud.ReadByID(c, query) + last_id := 0 + err = row.Scan( + &last_id, + ) + if err != nil { + return err + } + print(last_id) + query = ` + INSERT INTO + year_records + (year_id, started_at, ended_at) + VALUES + (`+strconv.Itoa(last_id)+", '"+startedAt+"', '" +endedAt+"');" + print(query) + return y.crud.UpdateDB(c, query) +} + diff --git a/api/internals/usecase/year_usecase.go b/api/internals/usecase/year_usecase.go index b1a36b68a..cb8f66550 100644 --- a/api/internals/usecase/year_usecase.go +++ b/api/internals/usecase/year_usecase.go @@ -19,6 +19,7 @@ type YearUseCase interface { UpdateYear(context.Context, string, string) (domain.Year, error) DestroyYear(context.Context, string) error GetYearPeriods(context.Context) ([]domain.YearPeriod, error) + CreateYearPeriod(context.Context, string, string, string) (domain.YearPeriod, error) } func NewYearUseCase(rep rep.YearRepository) YearUseCase { @@ -135,3 +136,21 @@ func (y *yearUseCase) GetYearPeriods(c context.Context) ([]domain.YearPeriod, er } return yearPeriods, nil } + +func (y *yearUseCase) CreateYearPeriod(c context.Context, year string, startAt string, endedAt string) (domain.YearPeriod, error) { + latestYearPeriod := domain.YearPeriod{} + err := y.rep.CreateYearPeriod(c, year, startAt, endedAt) + row, err := y.rep.FindPeriodLatestRecord(c) + err = row.Scan( + &latestYearPeriod.ID, + &latestYearPeriod.Year, + &latestYearPeriod.StartedAt, + &latestYearPeriod.EndedAt, + &latestYearPeriod.CreatedAt, + &latestYearPeriod.UpdatedAt, + ) + if err != nil { + return latestYearPeriod, err + } + return latestYearPeriod, nil +} diff --git a/api/router/router.go b/api/router/router.go index e07971633..4849b031c 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -214,5 +214,6 @@ func (r router) ProvideRouter(e *echo.Echo) { // year_periods e.GET("/years/periods", r.yearController.IndexYearPeriods) + e.POST("/years/periods", r.yearController.CreateYearPeriod) } From 5fd221c8deb58ab4b546bf28dc0e78cb5f301291 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Wed, 15 Nov 2023 23:06:21 +0900 Subject: [PATCH 07/54] =?UTF-8?q?=E8=BF=BD=E5=8A=A0API=E3=82=92body?= =?UTF-8?q?=E3=81=A7=E5=8F=97=E3=81=91=E5=8F=96=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/controller/year_controller.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/api/externals/controller/year_controller.go b/api/externals/controller/year_controller.go index 1883cd733..94bd5d507 100644 --- a/api/externals/controller/year_controller.go +++ b/api/externals/controller/year_controller.go @@ -1,8 +1,11 @@ package controller import ( + "fmt" "net/http" + "strconv" + "github.com/NUTFes/FinanSu/api/internals/domain" "github.com/NUTFes/FinanSu/api/internals/usecase" "github.com/labstack/echo/v4" ) @@ -11,6 +14,8 @@ type yearController struct { u usecase.YearUseCase } +const Layout = "2006-01-02 15:04:05" + type YearController interface { IndexYear(echo.Context) error ShowYear(echo.Context) error @@ -84,12 +89,15 @@ func (y *yearController) IndexYearPeriods(c echo.Context) error { } func (y *yearController) CreateYearPeriod(c echo.Context) error { - year := c.QueryParam("year") - startedAt := c.QueryParam("startedAt") - endedAt := c.QueryParam("endedAt") - latestYear, err := y.u.CreateYearPeriod(c.Request().Context(), year, startedAt, endedAt) + yearPeriod := new(domain.YearPeriod) + if err := c.Bind(yearPeriod); err != nil { + fmt.Println("err") + return err + } + latestYearPeriod, err := y.u.CreateYearPeriod(c.Request().Context(), strconv.Itoa(yearPeriod.Year), yearPeriod.StartedAt.Format(Layout), yearPeriod.EndedAt.Format(Layout)) if err != nil { return err } - return c.JSON(http.StatusCreated, latestYear) + return c.JSON(http.StatusCreated, latestYearPeriod) } + From 55c673e5da35d096a582d7a293bfc0db6675cf30 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Wed, 15 Nov 2023 23:36:01 +0900 Subject: [PATCH 08/54] =?UTF-8?q?=E7=99=BB=E9=8C=B2=E3=83=A2=E3=83=BC?= =?UTF-8?q?=E3=83=80=E3=83=AB=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/year_periods/AddModal.tsx | 77 ++++++++ .../components/year_periods/DeleteModal.tsx | 52 ++++++ .../src/components/year_periods/EditModal.tsx | 164 ++++++++++++++++++ .../year_periods/OpenAddModalButton.tsx | 27 +++ .../year_periods/OpenDeleteModalButton.tsx | 25 +++ .../year_periods/OpenEditModalButton.tsx | 39 +++++ .../src/pages/year_periods/index.tsx | 4 + 7 files changed, 388 insertions(+) create mode 100644 view/next-project/src/components/year_periods/AddModal.tsx create mode 100644 view/next-project/src/components/year_periods/DeleteModal.tsx create mode 100644 view/next-project/src/components/year_periods/EditModal.tsx create mode 100644 view/next-project/src/components/year_periods/OpenAddModalButton.tsx create mode 100644 view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx create mode 100644 view/next-project/src/components/year_periods/OpenEditModalButton.tsx diff --git a/view/next-project/src/components/year_periods/AddModal.tsx b/view/next-project/src/components/year_periods/AddModal.tsx new file mode 100644 index 000000000..d87f3a414 --- /dev/null +++ b/view/next-project/src/components/year_periods/AddModal.tsx @@ -0,0 +1,77 @@ +import { useRouter } from 'next/router'; +import React, { Dispatch, FC, SetStateAction, useState, useMemo } from 'react'; +import { useRecoilState } from 'recoil'; + +import { Modal, CloseButton, Input, PrimaryButton } from '../common'; +import { userAtom } from '@/store/atoms'; +import { YearRecords } from '@/type/common'; + +interface ModalProps { + setShowModal: Dispatch<SetStateAction<boolean>>; +} + +const OpenAddModal: FC<ModalProps> = (props) => { + const [user] = useRecoilState(userAtom); + + const router = useRouter(); + + const [formData, setFormData] = useState<YearRecords>({ + id: 0, + year: 0, + startedAt: '', + endedAt: '', + createdAt: '', + updatedAt: '', + }); + + const handler = + (input: string) => + (e: React.ChangeEvent<HTMLSelectElement> | React.ChangeEvent<HTMLInputElement>) => { + setFormData({ ...formData, [input]: e.target.value }); + }; + + // const addFundInformation = async (data: FundInformation) => { + // const addFundInformationUrl = process.env.CSR_API_URI + '/fund_informations'; + // await post(addFundInformationUrl, data); + // }; + + return ( + <Modal className='md:w-1/2'> + <div className='w-full'> + <div className='ml-auto mr-5 w-fit'> + <CloseButton onClick={() => props.setShowModal(false)} /> + </div> + </div> + <h1 className='mx-auto mb-10 w-fit text-xl text-black-600'>募金の登録</h1> + <div className='my-6 grid grid-cols-5 items-center justify-items-center gap-4'> + <p className='col-span-2 text-black-600'>年度</p> + <div className='col-span-3 w-full'> + <Input className='w-full' onChange={handler('year')} placeholder='20XX' /> + </div> + <p className='col-span-2 text-black-600'>開始日</p> + <div className='col-span-3 w-full'> + <Input type='date' onChange={handler('startedAt')} className='w-full' /> + </div> + <p className='col-span-2 text-black-600'>終了日</p> + <div className='col-span-3 w-full'> + <Input type='date' onChange={handler('endedAt')} className='w-full' /> + </div> + </div> + <div className='mx-auto mb-5 w-fit'> + <PrimaryButton + className={'mx-2'} + onClick={() => { + // addFundInformation(formData); + console.log(formData); + props.setShowModal(false); + // router.reload(); + }} + > + 登録する + </PrimaryButton> + </div> + </Modal> + ); +}; + +export default OpenAddModal; diff --git a/view/next-project/src/components/year_periods/DeleteModal.tsx b/view/next-project/src/components/year_periods/DeleteModal.tsx new file mode 100644 index 000000000..0f81f0174 --- /dev/null +++ b/view/next-project/src/components/year_periods/DeleteModal.tsx @@ -0,0 +1,52 @@ +import { useRouter } from 'next/router'; +import React, { Dispatch, FC, SetStateAction } from 'react'; + +import { del } from '@api/api_methods'; +import { Modal, CloseButton, OutlinePrimaryButton, PrimaryButton } from '@components/common'; + +interface ModalProps { + setShowModal: Dispatch<SetStateAction<boolean>>; + children?: React.ReactNode; + id: number | string; +} + +const DeleteModal: FC<ModalProps> = (props) => { + const router = useRouter(); + + const closeModal = () => { + props.setShowModal(false); + router.reload(); + }; + + const deleteFundInformations = async (id: number | string) => { + const deletePurchaseReportUrl = process.env.CSR_API_URI + '/fund_informations/' + id; + await del(deletePurchaseReportUrl); + }; + + return ( + <Modal className='md:w-1/2'> + <div className='w-full'> + <div className='ml-auto w-fit'> + <CloseButton onClick={() => props.setShowModal(false)} /> + </div> + </div> + <div className='mx-auto mb-5 w-fit text-xl text-black-600'>募金の削除</div> + <div className='mx-auto my-5 w-fit text-xl'>削除しますか?</div> + <div className=''> + <div className='flex flex-row justify-center gap-5'> + <OutlinePrimaryButton onClick={closeModal}>戻る</OutlinePrimaryButton> + <PrimaryButton + onClick={() => { + deleteFundInformations(props.id); + closeModal(); + }} + > + 削除 + </PrimaryButton> + </div> + </div> + </Modal> + ); +}; + +export default DeleteModal; diff --git a/view/next-project/src/components/year_periods/EditModal.tsx b/view/next-project/src/components/year_periods/EditModal.tsx new file mode 100644 index 000000000..157c69fb6 --- /dev/null +++ b/view/next-project/src/components/year_periods/EditModal.tsx @@ -0,0 +1,164 @@ +import { useRouter } from 'next/router'; +import { Dispatch, SetStateAction, useEffect, useState, useMemo } from 'react'; + +import { Modal, Input, Select, CloseButton, PrimaryButton } from '../common'; +import { put } from '@api/fundInformations'; +import { BUREAUS } from '@constants/bureaus'; +import { FundInformation, Teacher, User, Department } from '@type/common'; + +interface ModalProps { + setShowModal: Dispatch<SetStateAction<boolean>>; + teachers: Teacher[]; + users: User[]; + departments: Department[]; + fundInformation: FundInformation; +} + +export default function EditModal(props: ModalProps) { + const router = useRouter(); + + const [formData, setFormData] = useState<FundInformation>({ + id: props.fundInformation.id, + userID: props.fundInformation.userID, + teacherID: props.fundInformation.teacherID, + price: props.fundInformation.price, + remark: props.fundInformation.remark, + isFirstCheck: false, + isLastCheck: false, + receivedAt: props.fundInformation.receivedAt, + }); + + const [departmentID, setDepartmentID] = useState<number | string>(1); + + useEffect(() => { + const teacher = props.teachers.find((teacher) => teacher.departmentID === departmentID); + if (teacher && teacher.id) { + setFormData({ ...formData, teacherID: teacher.id }); + } + }, [departmentID]); + + const handler = + (input: string) => + ( + e: + | React.ChangeEvent<HTMLInputElement> + | React.ChangeEvent<HTMLTextAreaElement> + | React.ChangeEvent<HTMLSelectElement>, + ) => { + setFormData({ ...formData, [input]: e.target.value }); + }; + + const submitFundInformation = async (data: FundInformation) => { + const submitFundInformationURL = process.env.CSR_API_URI + '/fund_informations/' + data.id; + await put(submitFundInformationURL, data); + router.reload(); + }; + + // 担当者を局でフィルタを適用 + const [bureauId, setBureauId] = useState<number>( + props.users.find((user) => { + return user.id === props.fundInformation.userID; + })?.bureauID || 1, + ); + const filteredUsers = useMemo(() => { + const res = props.users + .filter((user) => { + return user.bureauID === bureauId; + }) + .filter((user, index, self) => { + return self.findIndex((u) => u.name === user.name) === index; + }); + if (res.length !== 0) setFormData({ ...formData, userID: res[0].id }); + return res; + }, [bureauId]); + + return ( + <Modal className='md:w-1/2'> + <div className='w-full'> + <div className='ml-auto mr-5 w-fit'> + <CloseButton onClick={() => props.setShowModal(false)} /> + </div> + </div> + <h1 className='mx-auto mb-10 w-fit text-xl text-black-600'>募金の登録</h1> + <div className='my-6 grid grid-cols-5 items-center justify-items-center gap-4'> + <p className='col-span-1 text-black-600'>教員の所属</p> + <div className='col-span-4 w-full'> + <Select + className='w-full' + value={departmentID} + onChange={(e) => { + setDepartmentID(Number(e.target.value)); + }} + > + {props.departments.map((department) => ( + <option key={department.id} value={department.id}> + {department.name} + </option> + ))} + </Select> + </div> + <p className='col-span-1 text-black-600'>教員名</p> + <div className='col-span-4 w-full'> + <Select className='w-full' value={formData.teacherID} onChange={handler('teacherID')}> + {props.teachers + .filter((teacher) => teacher.departmentID === departmentID) + .map((teacher) => ( + <option key={teacher.id} value={teacher.id}> + {teacher.name} + </option> + ))} + </Select> + </div> + <p className='text-black-600'>担当者の局</p> + <div className='col-span-4 w-full'> + <Select value={bureauId} onChange={(e) => setBureauId(Number(e.target.value))}> + {BUREAUS.map((bureaus) => ( + <option key={bureaus.id} value={bureaus.id}> + {bureaus.name} + </option> + ))} + </Select> + </div> + <p className='col-span-1 text-black-600'>担当者</p> + <div className='col-span-4 w-full'> + <Select className='w-full' value={formData.userID} onChange={handler('userID')}> + {filteredUsers.map((user) => ( + <option key={user.id} value={user.id}> + {user.name} + </option> + ))} + </Select> + </div> + <p className='cols-span-1 text-black-600'>受け取り日時</p> + <div className='col-span-4 w-full'> + <Input + type='date' + value={formData.receivedAt} + onChange={handler('receivedAt')} + className='w-full' + /> + </div> + <p className='col-span-1 text-black-600'>金額</p> + <div className='col-span-4 w-full'> + <Input className='w-full' value={formData.price} onChange={handler('price')} /> + </div> + <p className='col-span-1 text-black-600'>備考</p> + <div className='col-span-4 w-full'> + <Input className='w-full' value={formData.remark} onChange={handler('remark')} /> + </div> + </div> + <div className='mx-auto mb-5 w-fit'> + <PrimaryButton + className={'mx-2'} + onClick={() => { + submitFundInformation(formData); + props.setShowModal(false); + router.reload(); + }} + > + 登録する + </PrimaryButton> + </div> + </Modal> + ); +} diff --git a/view/next-project/src/components/year_periods/OpenAddModalButton.tsx b/view/next-project/src/components/year_periods/OpenAddModalButton.tsx new file mode 100644 index 000000000..d9a3e8545 --- /dev/null +++ b/view/next-project/src/components/year_periods/OpenAddModalButton.tsx @@ -0,0 +1,27 @@ +import React, { useState } from 'react'; + +import OpenAddModal from './AddModal'; +import { AddButton } from '@components/common'; + +interface Props { + children?: React.ReactNode; +} + +export const OpenAddModalButton = (props: Props) => { + const [isOpen, setIsOpen] = useState<boolean>(false); + + return ( + <> + <AddButton + onClick={() => { + setIsOpen(true); + }} + > + {props.children} + </AddButton> + {isOpen && <OpenAddModal setShowModal={setIsOpen} />} + </> + ); +}; + +export default OpenAddModalButton; diff --git a/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx b/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx new file mode 100644 index 000000000..228efdcb2 --- /dev/null +++ b/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx @@ -0,0 +1,25 @@ +import React, { useState } from 'react'; + +import DeleteModal from './DeleteModal'; +import { DeleteButton } from '@components/common'; + +interface Props { + children?: React.ReactNode; + id: number; + isDisabled: boolean; +} + +const OpenDeleteModalButton: React.FC<Props> = (props) => { + const [isOpen, setIsOpen] = useState(false); + const onOpen = () => { + setIsOpen(true); + }; + return ( + <> + <DeleteButton onClick={onOpen} isDisabled={props.isDisabled} /> + {isOpen && <DeleteModal id={props.id} setShowModal={setIsOpen} />} + </> + ); +}; + +export default OpenDeleteModalButton; diff --git a/view/next-project/src/components/year_periods/OpenEditModalButton.tsx b/view/next-project/src/components/year_periods/OpenEditModalButton.tsx new file mode 100644 index 000000000..7dd948082 --- /dev/null +++ b/view/next-project/src/components/year_periods/OpenEditModalButton.tsx @@ -0,0 +1,39 @@ +import React, { useState } from 'react'; + +import EditModal from './EditModal'; +import { EditButton } from '@components/common'; +import { Teacher, Department, User, FundInformation } from '@type/common'; + +interface Props { + teachers: Teacher[]; + departments: Department[]; + users: User[]; + fundInformation: FundInformation; + isDisabled: boolean; +} + +export const OpenAddModalButton = (props: Props) => { + const [isOpen, setIsOpen] = useState<boolean>(false); + + return ( + <> + <EditButton + onClick={() => { + setIsOpen(true); + }} + isDisabled={props.isDisabled} + /> + {isOpen && ( + <EditModal + setShowModal={setIsOpen} + teachers={props.teachers} + departments={props.departments} + users={props.users} + fundInformation={props.fundInformation} + /> + )} + </> + ); +}; + +export default OpenAddModalButton; diff --git a/view/next-project/src/pages/year_periods/index.tsx b/view/next-project/src/pages/year_periods/index.tsx index f28096172..54f02d445 100644 --- a/view/next-project/src/pages/year_periods/index.tsx +++ b/view/next-project/src/pages/year_periods/index.tsx @@ -4,6 +4,7 @@ import { useRouter } from 'next/router'; import { useEffect, useState, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; +import OpenAddModalButton from '@/components/year_periods/OpenAddModalButton'; import { authAtom } from '@/store/atoms'; import { getCurrentUser } from '@/utils/api/currentUser'; import { get } from '@api/api_methods'; @@ -78,6 +79,9 @@ export default function Periods(props: Props) { <Title title={'年度一覧'} /> </div> </div> + <div className='hidden justify-end md:flex '> + <OpenAddModalButton>年度登録</OpenAddModalButton> + </div> <div className='mb-2 p-5'> <table className='mb-5 w-full table-auto border-collapse'> <thead> From eceb7563225739063b3ee12acdc4b5a33883b481 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Thu, 16 Nov 2023 00:19:03 +0900 Subject: [PATCH 09/54] =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=8B?= =?UTF-8?q?=E3=82=89=E5=B9=B4=E5=BA=A6=E3=81=AE=E8=BF=BD=E5=8A=A0=E3=81=8C?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/package-lock.json | 24 ++++++++++++ view/next-project/package.json | 1 + .../src/components/year_periods/AddModal.tsx | 37 +++++++++++++------ 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/view/next-project/package-lock.json b/view/next-project/package-lock.json index 7d70f4b89..0d9377177 100644 --- a/view/next-project/package-lock.json +++ b/view/next-project/package-lock.json @@ -14,6 +14,7 @@ "@pdf-lib/fontkit": "^1.1.1", "@types/react-select": "^5.0.1", "clsx": "^1.2.1", + "date-fns": "^2.30.0", "framer-motion": "^5.3.0", "lorem-ipsum": "^2.0.4", "next": "^13.0.5", @@ -2865,6 +2866,21 @@ "node": ">= 12" } }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", @@ -9102,6 +9118,14 @@ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" }, + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "requires": { + "@babel/runtime": "^7.21.0" + } + }, "debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", diff --git a/view/next-project/package.json b/view/next-project/package.json index 4c4229ea2..a913c6dcc 100644 --- a/view/next-project/package.json +++ b/view/next-project/package.json @@ -20,6 +20,7 @@ "@pdf-lib/fontkit": "^1.1.1", "@types/react-select": "^5.0.1", "clsx": "^1.2.1", + "date-fns": "^2.30.0", "framer-motion": "^5.3.0", "lorem-ipsum": "^2.0.4", "next": "^13.0.5", diff --git a/view/next-project/src/components/year_periods/AddModal.tsx b/view/next-project/src/components/year_periods/AddModal.tsx index d87f3a414..9afebcd94 100644 --- a/view/next-project/src/components/year_periods/AddModal.tsx +++ b/view/next-project/src/components/year_periods/AddModal.tsx @@ -1,10 +1,12 @@ +import { format } from 'date-fns'; import { useRouter } from 'next/router'; -import React, { Dispatch, FC, SetStateAction, useState, useMemo } from 'react'; +import React, { Dispatch, FC, SetStateAction, useState } from 'react'; import { useRecoilState } from 'recoil'; import { Modal, CloseButton, Input, PrimaryButton } from '../common'; import { userAtom } from '@/store/atoms'; import { YearRecords } from '@/type/common'; +import { post } from '@/utils/api/api_methods'; interface ModalProps { setShowModal: Dispatch<SetStateAction<boolean>>; @@ -16,12 +18,9 @@ const OpenAddModal: FC<ModalProps> = (props) => { const router = useRouter(); const [formData, setFormData] = useState<YearRecords>({ - id: 0, year: 0, startedAt: '', endedAt: '', - createdAt: '', - updatedAt: '', }); const handler = @@ -30,10 +29,25 @@ const OpenAddModal: FC<ModalProps> = (props) => { setFormData({ ...formData, [input]: e.target.value }); }; - // const addFundInformation = async (data: FundInformation) => { - // const addFundInformationUrl = process.env.CSR_API_URI + '/fund_informations'; - // await post(addFundInformationUrl, data); - // }; + const submit = async (data: YearRecords) => { + const startedAt = data.startedAt && new Date(data.startedAt); + const endedAt = data.endedAt && new Date(data.endedAt); + const formattedStartedAt = startedAt && format(startedAt, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + const formattedEndedAt = endedAt && format(endedAt, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + const submitData = { + ...data, + year: Number(data.year), + startedAt: formattedStartedAt, + endedAt: formattedEndedAt, + }; + await addYearPeriod(submitData); + }; + + const addYearPeriod = async (data: YearRecords) => { + const addPeriodUrl = process.env.CSR_API_URI + '/years/periods'; + console.log(data); + await post(addPeriodUrl, data); + }; return ( <Modal className='md:w-1/2'> @@ -46,7 +60,7 @@ const OpenAddModal: FC<ModalProps> = (props) => { <div className='my-6 grid grid-cols-5 items-center justify-items-center gap-4'> <p className='col-span-2 text-black-600'>年度</p> <div className='col-span-3 w-full'> - <Input className='w-full' onChange={handler('year')} placeholder='20XX' /> + <Input className='w-full' onChange={handler('year')} placeholder='20XX' type='number' /> </div> <p className='col-span-2 text-black-600'>開始日</p> <div className='col-span-3 w-full'> @@ -61,10 +75,9 @@ const OpenAddModal: FC<ModalProps> = (props) => { <PrimaryButton className={'mx-2'} onClick={() => { - // addFundInformation(formData); - console.log(formData); + submit(formData); props.setShowModal(false); - // router.reload(); + router.reload(); }} > 登録する From 0048bf34ba1a5b68f91e1476b3aa1e4cbebbba74 Mon Sep 17 00:00:00 2001 From: TkymHrt <s231053@stn.nagaokaut.ac.jp> Date: Fri, 17 Nov 2023 22:41:41 +0900 Subject: [PATCH 10/54] [feat] Add Donation-Amount Data-List --- .../src/constants/donationAmount.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 view/next-project/src/constants/donationAmount.ts diff --git a/view/next-project/src/constants/donationAmount.ts b/view/next-project/src/constants/donationAmount.ts new file mode 100644 index 000000000..c4875d88d --- /dev/null +++ b/view/next-project/src/constants/donationAmount.ts @@ -0,0 +1,18 @@ +export const DONATION_AMOUNT = [ + { + id: 1, + name: '1000' + }, + { + id: 2, + name: '2000' + }, + { + id: 3, + name: '5000' + }, + { + id: 4, + name: '10000' + }, +]; From 04572cd2b8c9bc1cecbb3b074551239891e09721 Mon Sep 17 00:00:00 2001 From: TkymHrt <s231053@stn.nagaokaut.ac.jp> Date: Fri, 17 Nov 2023 22:42:53 +0900 Subject: [PATCH 11/54] [feat] Add datalist --- .../src/components/common/Input/Input.tsx | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/view/next-project/src/components/common/Input/Input.tsx b/view/next-project/src/components/common/Input/Input.tsx index 00860de0a..81f0dea33 100644 --- a/view/next-project/src/components/common/Input/Input.tsx +++ b/view/next-project/src/components/common/Input/Input.tsx @@ -11,6 +11,9 @@ interface Props { onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void; children?: React.ReactNode; type?: string; + datalist?: { id: number; name: string }[]; + listKey?: string; + enableDatalist?: boolean; } function Input(props: Props): JSX.Element { @@ -18,16 +21,27 @@ function Input(props: Props): JSX.Element { 'rounded-full border border-primary-1 py-2 px-4' + (props.className ? ` ${props.className}` : ''); return ( - <input - className={clsx(s.input, className)} - placeholder={props.placeholder} - id={props.id} - value={props.value} - onChange={props.onChange} - type={props.type} - > - {props.children} - </input> + <div> + <input + className={clsx(s.input, className)} + placeholder={props.placeholder} + id={props.id} + value={props.value} + onChange={props.onChange} + type={props.type} + list={props.enableDatalist ? props.listKey : undefined} + > + {props.children} + </input> + {props.enableDatalist && ( + <datalist id={props.listKey}> + {props.datalist?.map((option) => ( + <option key={option.id} value={option.name} /> + ))} + </datalist> + )} + </div> + ); } From 2c34d4a98ce061c3ca4777416ff7915584c12933 Mon Sep 17 00:00:00 2001 From: TkymHrt <s231053@stn.nagaokaut.ac.jp> Date: Fri, 17 Nov 2023 22:45:50 +0900 Subject: [PATCH 12/54] [feat] Add attribute to AddModal --- .../src/components/fund_information/AddModal.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/view/next-project/src/components/fund_information/AddModal.tsx b/view/next-project/src/components/fund_information/AddModal.tsx index fbe14c544..574dcd323 100644 --- a/view/next-project/src/components/fund_information/AddModal.tsx +++ b/view/next-project/src/components/fund_information/AddModal.tsx @@ -6,6 +6,7 @@ import { Modal, CloseButton, Input, Select, PrimaryButton } from '../common'; import { userAtom } from '@/store/atoms'; import { post } from '@api/fundInformations'; import { BUREAUS } from '@constants/bureaus'; +import { DONATION_AMOUNT } from "@constants/donationAmount"; import { Department, FundInformation, Teacher, User } from '@type/common'; interface ModalProps { @@ -53,9 +54,9 @@ const OpenAddModal: FC<ModalProps> = (props) => { const handler = (input: string) => - (e: React.ChangeEvent<HTMLSelectElement> | React.ChangeEvent<HTMLInputElement>) => { - setFormData({ ...formData, [input]: e.target.value }); - }; + (e: React.ChangeEvent<HTMLSelectElement> | React.ChangeEvent<HTMLInputElement>) => { + setFormData({ ...formData, [input]: e.target.value }); + }; const handleDepartmentID = (e: React.ChangeEvent<HTMLSelectElement>) => { setDepartmentID(Number(e.target.value)); @@ -132,7 +133,14 @@ const OpenAddModal: FC<ModalProps> = (props) => { </div> <p className='col-span-1 text-black-600'>金額</p> <div className='col-span-4 w-full'> - <Input className='w-full' value={formData.price} onChange={handler('price')} /> + <Input + className='w-full' + value={formData.price} + onChange={handler('price')} + datalist={DONATION_AMOUNT} + listKey='amoutOptions' + enableDatalist={true} + /> </div> <p className='col-span-1 text-black-600'>備考</p> <div className='col-span-4 w-full'> From 9ea1599d899b7fe0ab79c71f7d09898a0ff70169 Mon Sep 17 00:00:00 2001 From: TkymHrt <s231053@stn.nagaokaut.ac.jp> Date: Fri, 17 Nov 2023 22:46:12 +0900 Subject: [PATCH 13/54] [feat] Add attribute to EditModal --- .../components/fund_information/EditModal.tsx | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/view/next-project/src/components/fund_information/EditModal.tsx b/view/next-project/src/components/fund_information/EditModal.tsx index 157c69fb6..40340705c 100644 --- a/view/next-project/src/components/fund_information/EditModal.tsx +++ b/view/next-project/src/components/fund_information/EditModal.tsx @@ -4,6 +4,7 @@ import { Dispatch, SetStateAction, useEffect, useState, useMemo } from 'react'; import { Modal, Input, Select, CloseButton, PrimaryButton } from '../common'; import { put } from '@api/fundInformations'; import { BUREAUS } from '@constants/bureaus'; +import { DONATION_AMOUNT } from "@constants/donationAmount"; import { FundInformation, Teacher, User, Department } from '@type/common'; interface ModalProps { @@ -39,14 +40,14 @@ export default function EditModal(props: ModalProps) { const handler = (input: string) => - ( - e: - | React.ChangeEvent<HTMLInputElement> - | React.ChangeEvent<HTMLTextAreaElement> - | React.ChangeEvent<HTMLSelectElement>, - ) => { - setFormData({ ...formData, [input]: e.target.value }); - }; + ( + e: + | React.ChangeEvent<HTMLInputElement> + | React.ChangeEvent<HTMLTextAreaElement> + | React.ChangeEvent<HTMLSelectElement>, + ) => { + setFormData({ ...formData, [input]: e.target.value }); + }; const submitFundInformation = async (data: FundInformation) => { const submitFundInformationURL = process.env.CSR_API_URI + '/fund_informations/' + data.id; @@ -140,7 +141,14 @@ export default function EditModal(props: ModalProps) { </div> <p className='col-span-1 text-black-600'>金額</p> <div className='col-span-4 w-full'> - <Input className='w-full' value={formData.price} onChange={handler('price')} /> + <Input + className='w-full' + value={formData.price} + onChange={handler('price')} + datalist={DONATION_AMOUNT} + listKey='amoutOptions' + enableDatalist={true} + /> </div> <p className='col-span-1 text-black-600'>備考</p> <div className='col-span-4 w-full'> From 02bfca54341a44e32120fc650c9b4cce5c6ce34f Mon Sep 17 00:00:00 2001 From: TkymHrt <TkymHrt@users.noreply.github.com> Date: Fri, 17 Nov 2023 14:21:15 +0000 Subject: [PATCH 14/54] formatted by workflow --- .../src/components/common/Input/Input.tsx | 1 - .../components/fund_information/AddModal.tsx | 8 ++++---- .../components/fund_information/EditModal.tsx | 18 +++++++++--------- .../src/constants/donationAmount.ts | 8 ++++---- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/view/next-project/src/components/common/Input/Input.tsx b/view/next-project/src/components/common/Input/Input.tsx index 81f0dea33..32cddbc94 100644 --- a/view/next-project/src/components/common/Input/Input.tsx +++ b/view/next-project/src/components/common/Input/Input.tsx @@ -41,7 +41,6 @@ function Input(props: Props): JSX.Element { </datalist> )} </div> - ); } diff --git a/view/next-project/src/components/fund_information/AddModal.tsx b/view/next-project/src/components/fund_information/AddModal.tsx index 574dcd323..4db77e873 100644 --- a/view/next-project/src/components/fund_information/AddModal.tsx +++ b/view/next-project/src/components/fund_information/AddModal.tsx @@ -6,7 +6,7 @@ import { Modal, CloseButton, Input, Select, PrimaryButton } from '../common'; import { userAtom } from '@/store/atoms'; import { post } from '@api/fundInformations'; import { BUREAUS } from '@constants/bureaus'; -import { DONATION_AMOUNT } from "@constants/donationAmount"; +import { DONATION_AMOUNT } from '@constants/donationAmount'; import { Department, FundInformation, Teacher, User } from '@type/common'; interface ModalProps { @@ -54,9 +54,9 @@ const OpenAddModal: FC<ModalProps> = (props) => { const handler = (input: string) => - (e: React.ChangeEvent<HTMLSelectElement> | React.ChangeEvent<HTMLInputElement>) => { - setFormData({ ...formData, [input]: e.target.value }); - }; + (e: React.ChangeEvent<HTMLSelectElement> | React.ChangeEvent<HTMLInputElement>) => { + setFormData({ ...formData, [input]: e.target.value }); + }; const handleDepartmentID = (e: React.ChangeEvent<HTMLSelectElement>) => { setDepartmentID(Number(e.target.value)); diff --git a/view/next-project/src/components/fund_information/EditModal.tsx b/view/next-project/src/components/fund_information/EditModal.tsx index 40340705c..397683d7c 100644 --- a/view/next-project/src/components/fund_information/EditModal.tsx +++ b/view/next-project/src/components/fund_information/EditModal.tsx @@ -4,7 +4,7 @@ import { Dispatch, SetStateAction, useEffect, useState, useMemo } from 'react'; import { Modal, Input, Select, CloseButton, PrimaryButton } from '../common'; import { put } from '@api/fundInformations'; import { BUREAUS } from '@constants/bureaus'; -import { DONATION_AMOUNT } from "@constants/donationAmount"; +import { DONATION_AMOUNT } from '@constants/donationAmount'; import { FundInformation, Teacher, User, Department } from '@type/common'; interface ModalProps { @@ -40,14 +40,14 @@ export default function EditModal(props: ModalProps) { const handler = (input: string) => - ( - e: - | React.ChangeEvent<HTMLInputElement> - | React.ChangeEvent<HTMLTextAreaElement> - | React.ChangeEvent<HTMLSelectElement>, - ) => { - setFormData({ ...formData, [input]: e.target.value }); - }; + ( + e: + | React.ChangeEvent<HTMLInputElement> + | React.ChangeEvent<HTMLTextAreaElement> + | React.ChangeEvent<HTMLSelectElement>, + ) => { + setFormData({ ...formData, [input]: e.target.value }); + }; const submitFundInformation = async (data: FundInformation) => { const submitFundInformationURL = process.env.CSR_API_URI + '/fund_informations/' + data.id; diff --git a/view/next-project/src/constants/donationAmount.ts b/view/next-project/src/constants/donationAmount.ts index c4875d88d..e1c24180e 100644 --- a/view/next-project/src/constants/donationAmount.ts +++ b/view/next-project/src/constants/donationAmount.ts @@ -1,18 +1,18 @@ export const DONATION_AMOUNT = [ { id: 1, - name: '1000' + name: '1000', }, { id: 2, - name: '2000' + name: '2000', }, { id: 3, - name: '5000' + name: '5000', }, { id: 4, - name: '10000' + name: '10000', }, ]; From 1f962014ab673a3b961dcb27fabecff388fc954d Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sat, 18 Nov 2023 00:46:31 +0900 Subject: [PATCH 15/54] =?UTF-8?q?=E5=B9=B4=E5=BA=A6=E3=81=AE=E3=83=87?= =?UTF-8?q?=E3=83=BC=E3=82=BF=E3=82=92=E5=8F=96=E5=BE=97=E3=81=97=E3=80=81?= =?UTF-8?q?=E6=9C=80=E6=96=B0=E3=81=AE=E5=B9=B4=E5=BA=A6=E3=81=8C=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=81=95=E3=82=8C=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/purchaseorders/index.tsx | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/view/next-project/src/pages/purchaseorders/index.tsx b/view/next-project/src/pages/purchaseorders/index.tsx index 9f1e80690..053417fea 100644 --- a/view/next-project/src/pages/purchaseorders/index.tsx +++ b/view/next-project/src/pages/purchaseorders/index.tsx @@ -14,17 +14,28 @@ import DetailModal from '@components/purchaseorders/DetailModal'; import OpenAddModalButton from '@components/purchaseorders/OpenAddModalButton'; import OpenDeleteModalButton from '@components/purchaseorders/OpenDeleteModalButton'; import OpenEditModalButton from '@components/purchaseorders/OpenEditModalButton'; -import { PurchaseItem, PurchaseOrder, User, PurchaseOrderView, Expense } from '@type/common'; +import { + PurchaseItem, + PurchaseOrder, + User, + PurchaseOrderView, + Expense, + YearRecords, +} from '@type/common'; interface Props { user: User; purchaseOrderView: PurchaseOrderView[]; expenses: Expense[]; + yearRecords: YearRecords[]; } export async function getServerSideProps() { - const currentYear = '2024'; + const getPeriodsUrl = process.env.SSR_API_URI + '/years/periods'; + const periodsRes = await get(getPeriodsUrl); const getPurchaseOrderViewUrl = - process.env.SSR_API_URI + '/purchaseorders/details/' + currentYear; + process.env.SSR_API_URI + + '/purchaseorders/details/' + + String(periodsRes[periodsRes.length - 1].year); const getExpenseUrl = process.env.SSR_API_URI + '/expenses'; const purchaseOrderViewRes = await get(getPurchaseOrderViewUrl); const expenseRes = await get(getExpenseUrl); @@ -32,6 +43,7 @@ export async function getServerSideProps() { props: { purchaseOrderView: purchaseOrderViewRes, expenses: expenseRes, + yearRecords: periodsRes, }, }; } @@ -65,7 +77,10 @@ export default function PurchaseOrders(props: Props) { return datetime2; }; - const [selectedYear, setSelectedYear] = useState<string>('2024'); + const yearRecords = props.yearRecords; + const [selectedYear, setSelectedYear] = useState<string>( + yearRecords ? String(yearRecords[yearRecords.length - 1].year) : '2024', + ); const getPurchaseOrders = async () => { const getPurchaseOrderViewUrlByYear = @@ -165,14 +180,20 @@ export default function PurchaseOrders(props: Props) { <div className='flex gap-4'> <Title title={'購入申請一覧'} /> <select - className='w-100 ' + className='w-100' defaultValue={selectedYear} onChange={async (e) => { setSelectedYear(e.target.value); }} > - <option value='2023'>2023年度</option> - <option value='2024'>2024年度</option> + {props.yearRecords && + props.yearRecords.map((year) => { + return ( + <option value={year.year} key={year.id}> + {year.year}年度 + </option> + ); + })} </select> <PrimaryButton className='hidden md:block' @@ -331,7 +352,7 @@ export default function PurchaseOrders(props: Props) { </td> </tr> ))} - {purchaseOrderViews.length > 0 && ( + {purchaseOrderViews && purchaseOrderViews.length > 0 && ( <tr className='border-b border-primary-1'> <td className='px-1 py-3' colSpan={5}> <div className='flex justify-end'> @@ -345,7 +366,7 @@ export default function PurchaseOrders(props: Props) { </td> </tr> )} - {!purchaseOrderViews.length && ( + {!purchaseOrderViews && ( <tr className='border-b border-primary-1'> <td className='px-1 py-3' colSpan={7}> <div className='flex justify-center'> From 18ded8d63a6ae3a34b556b5dc420742b4933d020 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sat, 18 Nov 2023 01:38:32 +0900 Subject: [PATCH 16/54] =?UTF-8?q?=E6=9B=B4=E6=96=B0API=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/controller/year_controller.go | 15 ++++++ api/externals/repository/year_repository.go | 53 +++++++++++++++++++-- api/internals/usecase/year_usecase.go | 20 ++++++++ api/router/router.go | 1 + 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/api/externals/controller/year_controller.go b/api/externals/controller/year_controller.go index 94bd5d507..f89f444bb 100644 --- a/api/externals/controller/year_controller.go +++ b/api/externals/controller/year_controller.go @@ -24,6 +24,7 @@ type YearController interface { DestroyYear(echo.Context) error IndexYearPeriods(echo.Context) error CreateYearPeriod(echo.Context) error + UpdateYearPeriod(echo.Context) error } func NewYearController(u usecase.YearUseCase) YearController { @@ -101,3 +102,17 @@ func (y *yearController) CreateYearPeriod(c echo.Context) error { return c.JSON(http.StatusCreated, latestYearPeriod) } +func (y *yearController) UpdateYearPeriod(c echo.Context) error { + id := c.Param("id") + print(id) + yearPeriod := new(domain.YearPeriod) + if err := c.Bind(yearPeriod); err != nil { + fmt.Println("err") + return err + } + updateYearPeriod, err := y.u.UpdateYearPeriod(c.Request().Context(), id , strconv.Itoa(yearPeriod.Year), yearPeriod.StartedAt.Format(Layout), yearPeriod.EndedAt.Format(Layout)) + if err != nil { + return err + } + return c.JSON(http.StatusCreated, updateYearPeriod) +} diff --git a/api/externals/repository/year_repository.go b/api/externals/repository/year_repository.go index 5bb970756..253980439 100644 --- a/api/externals/repository/year_repository.go +++ b/api/externals/repository/year_repository.go @@ -24,6 +24,8 @@ type YearRepository interface { AllYearPeriods(context.Context) (*sql.Rows, error) CreateYearPeriod(context.Context, string, string, string) error FindPeriodLatestRecord(context.Context) (*sql.Row, error) + FindYearPeriodByID(context.Context, string) (*sql.Row, error) + UpdateYearPeriod(context.Context, string, string, string, string) error } func NewYearRepository(c db.Client, ac abstract.Crud) YearRepository { @@ -84,7 +86,7 @@ func (y *yearRepository) FindPeriodLatestRecord(c context.Context) (*sql.Row, er func (y *yearRepository) AllYearPeriods(c context.Context) (*sql.Rows, error) { query := ` SELECT - years.id, + year_records.id, years.year, year_records.started_at, year_records.ended_at, @@ -100,9 +102,9 @@ func (y *yearRepository) AllYearPeriods(c context.Context) (*sql.Rows, error) { } func (y *yearRepository) CreateYearPeriod(c context.Context, year string, startedAt string, endedAt string) error { - query := `INSERT INTO years (year) VALUES (` + year + ");" + query := `INSERT INTO years (year) SELECT ` +year +` WHERE NOT EXISTS ( SELECT * FROM years WHERE year = `+year+` );` y.crud.UpdateDB(c, query) - query = `SELECT LAST_INSERT_ID() AS last_id;` + query = `SELECT id FROM years WHERE year = `+ year +";" row, err := y.crud.ReadByID(c, query) last_id := 0 err = row.Scan( @@ -111,14 +113,55 @@ func (y *yearRepository) CreateYearPeriod(c context.Context, year string, starte if err != nil { return err } - print(last_id) query = ` INSERT INTO year_records (year_id, started_at, ended_at) VALUES (`+strconv.Itoa(last_id)+", '"+startedAt+"', '" +endedAt+"');" - print(query) return y.crud.UpdateDB(c, query) } +func (y *yearRepository) UpdateYearPeriod(c context.Context,id string, year string, startedAt string, endedAt string) error { + query := `INSERT INTO years (year) SELECT ` +year +` WHERE NOT EXISTS ( SELECT * FROM years WHERE year = `+year+` );` + y.crud.UpdateDB(c, query) + query = `SELECT id FROM years WHERE year = `+ year +";" + row, err := y.crud.ReadByID(c, query) + last_id := 0 + err = row.Scan( + &last_id, + ) + if err != nil { + return err + } + query = ` + UPDATE + year_records + SET + year_id = ` + strconv.Itoa(last_id) + + ", started_at = '" + startedAt + + "', ended_at = '"+ endedAt + + "' WHERE id = "+ id +";" + return y.crud.UpdateDB(c, query) +} + +func (y *yearRepository) FindYearPeriodByID(c context.Context, id string) (*sql.Row, error) { + query := ` + SELECT + year_records.id, + years.year, + year_records.started_at, + year_records.ended_at, + year_records.created_at, + year_records.updated_at + FROM + years + INNER JOIN + year_records + ON + years.id = year_records.year_id + WHERE year_records.id = `+id+";" + return y.crud.ReadByID(c, query) +} + + diff --git a/api/internals/usecase/year_usecase.go b/api/internals/usecase/year_usecase.go index cb8f66550..893f53118 100644 --- a/api/internals/usecase/year_usecase.go +++ b/api/internals/usecase/year_usecase.go @@ -20,6 +20,7 @@ type YearUseCase interface { DestroyYear(context.Context, string) error GetYearPeriods(context.Context) ([]domain.YearPeriod, error) CreateYearPeriod(context.Context, string, string, string) (domain.YearPeriod, error) + UpdateYearPeriod(context.Context, string, string, string, string) (domain.YearPeriod, error) } func NewYearUseCase(rep rep.YearRepository) YearUseCase { @@ -154,3 +155,22 @@ func (y *yearUseCase) CreateYearPeriod(c context.Context, year string, startAt s } return latestYearPeriod, nil } + +func (y *yearUseCase) UpdateYearPeriod(c context.Context, id string, year string, startAt string, endedAt string) (domain.YearPeriod, error) { + updateYearPeriod := domain.YearPeriod{} + err := y.rep.UpdateYearPeriod(c, id, year, startAt, endedAt) + row, err := y.rep.FindYearPeriodByID(c, id) + err = row.Scan( + &updateYearPeriod.ID, + &updateYearPeriod.Year, + &updateYearPeriod.StartedAt, + &updateYearPeriod.EndedAt, + &updateYearPeriod.CreatedAt, + &updateYearPeriod.UpdatedAt, + ) + if err != nil { + return updateYearPeriod, err + } + return updateYearPeriod, nil +} + diff --git a/api/router/router.go b/api/router/router.go index 4849b031c..2bd7b2e9b 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -215,5 +215,6 @@ func (r router) ProvideRouter(e *echo.Echo) { // year_periods e.GET("/years/periods", r.yearController.IndexYearPeriods) e.POST("/years/periods", r.yearController.CreateYearPeriod) + e.PUT("/years/periods/:id", r.yearController.UpdateYearPeriod) } From 92a73b38b7a95a8fe0528c1332e85e2afb536bd1 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sat, 18 Nov 2023 02:14:14 +0900 Subject: [PATCH 17/54] =?UTF-8?q?=E5=B9=B4=E5=BA=A6=E3=83=9A=E3=83=BC?= =?UTF-8?q?=E3=82=B8=E3=81=AE=E4=BF=AE=E6=AD=A3=E3=83=BB=E5=89=8A=E9=99=A4?= =?UTF-8?q?=E3=83=9C=E3=82=BF=E3=83=B3=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/year_periods/DeleteModal.tsx | 13 +- .../src/components/year_periods/EditModal.tsx | 149 ++++++------------ .../year_periods/OpenDeleteModalButton.tsx | 6 +- .../year_periods/OpenEditModalButton.tsx | 23 +-- .../src/pages/year_periods/index.tsx | 13 +- 5 files changed, 75 insertions(+), 129 deletions(-) diff --git a/view/next-project/src/components/year_periods/DeleteModal.tsx b/view/next-project/src/components/year_periods/DeleteModal.tsx index 0f81f0174..bd8f682a6 100644 --- a/view/next-project/src/components/year_periods/DeleteModal.tsx +++ b/view/next-project/src/components/year_periods/DeleteModal.tsx @@ -1,6 +1,7 @@ import { useRouter } from 'next/router'; import React, { Dispatch, FC, SetStateAction } from 'react'; +import { YearRecords } from '@/type/common'; import { del } from '@api/api_methods'; import { Modal, CloseButton, OutlinePrimaryButton, PrimaryButton } from '@components/common'; @@ -8,6 +9,7 @@ interface ModalProps { setShowModal: Dispatch<SetStateAction<boolean>>; children?: React.ReactNode; id: number | string; + yearRecord: YearRecords; } const DeleteModal: FC<ModalProps> = (props) => { @@ -18,9 +20,9 @@ const DeleteModal: FC<ModalProps> = (props) => { router.reload(); }; - const deleteFundInformations = async (id: number | string) => { - const deletePurchaseReportUrl = process.env.CSR_API_URI + '/fund_informations/' + id; - await del(deletePurchaseReportUrl); + const deleteYearPeriod = async (id: number | string) => { + const deleteYearPeriodUrl = process.env.CSR_API_URI + '/years/periods/' + id; + await del(deleteYearPeriodUrl); }; return ( @@ -30,14 +32,15 @@ const DeleteModal: FC<ModalProps> = (props) => { <CloseButton onClick={() => props.setShowModal(false)} /> </div> </div> - <div className='mx-auto mb-5 w-fit text-xl text-black-600'>募金の削除</div> + <div className='mx-auto mb-5 w-fit text-xl text-black-600'>年度の削除</div> + <div className='mx-auto my-5 w-fit text-xl text-black-600'>{props.yearRecord.year}年度</div> <div className='mx-auto my-5 w-fit text-xl'>削除しますか?</div> <div className=''> <div className='flex flex-row justify-center gap-5'> <OutlinePrimaryButton onClick={closeModal}>戻る</OutlinePrimaryButton> <PrimaryButton onClick={() => { - deleteFundInformations(props.id); + deleteYearPeriod(props.id); closeModal(); }} > diff --git a/view/next-project/src/components/year_periods/EditModal.tsx b/view/next-project/src/components/year_periods/EditModal.tsx index 157c69fb6..c7d8fc2eb 100644 --- a/view/next-project/src/components/year_periods/EditModal.tsx +++ b/view/next-project/src/components/year_periods/EditModal.tsx @@ -1,42 +1,26 @@ +import { format } from 'date-fns'; import { useRouter } from 'next/router'; -import { Dispatch, SetStateAction, useEffect, useState, useMemo } from 'react'; +import { Dispatch, SetStateAction, useState } from 'react'; -import { Modal, Input, Select, CloseButton, PrimaryButton } from '../common'; -import { put } from '@api/fundInformations'; -import { BUREAUS } from '@constants/bureaus'; -import { FundInformation, Teacher, User, Department } from '@type/common'; +import { Modal, Input, CloseButton, PrimaryButton } from '../common'; +import { put } from '@api/api_methods'; +import { YearRecords } from '@type/common'; interface ModalProps { setShowModal: Dispatch<SetStateAction<boolean>>; - teachers: Teacher[]; - users: User[]; - departments: Department[]; - fundInformation: FundInformation; + yearRecords: YearRecords; } export default function EditModal(props: ModalProps) { const router = useRouter(); - const [formData, setFormData] = useState<FundInformation>({ - id: props.fundInformation.id, - userID: props.fundInformation.userID, - teacherID: props.fundInformation.teacherID, - price: props.fundInformation.price, - remark: props.fundInformation.remark, - isFirstCheck: false, - isLastCheck: false, - receivedAt: props.fundInformation.receivedAt, + const [formData, setFormData] = useState<YearRecords>({ + id: props.yearRecords.id, + year: props.yearRecords.year, + startedAt: props.yearRecords.startedAt, + endedAt: props.yearRecords.endedAt, }); - const [departmentID, setDepartmentID] = useState<number | string>(1); - - useEffect(() => { - const teacher = props.teachers.find((teacher) => teacher.departmentID === departmentID); - if (teacher && teacher.id) { - setFormData({ ...formData, teacherID: teacher.id }); - } - }, [departmentID]); - const handler = (input: string) => ( @@ -48,30 +32,23 @@ export default function EditModal(props: ModalProps) { setFormData({ ...formData, [input]: e.target.value }); }; - const submitFundInformation = async (data: FundInformation) => { - const submitFundInformationURL = process.env.CSR_API_URI + '/fund_informations/' + data.id; - await put(submitFundInformationURL, data); - router.reload(); + const submitYearRecords = async (data: YearRecords) => { + const submitYearRecordsURL = process.env.CSR_API_URI + '/years/periods/' + data.id; + const startedAt = data.startedAt && new Date(data.startedAt); + const endedAt = data.endedAt && new Date(data.endedAt); + const formattedStartedAt = startedAt && format(startedAt, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + const formattedEndedAt = endedAt && format(endedAt, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + const submitData = { + ...data, + year: Number(data.year), + startedAt: formattedStartedAt, + endedAt: formattedEndedAt, + }; + console.log(data); + console.log(submitData); + await put(submitYearRecordsURL, submitData); }; - // 担当者を局でフィルタを適用 - const [bureauId, setBureauId] = useState<number>( - props.users.find((user) => { - return user.id === props.fundInformation.userID; - })?.bureauID || 1, - ); - const filteredUsers = useMemo(() => { - const res = props.users - .filter((user) => { - return user.bureauID === bureauId; - }) - .filter((user, index, self) => { - return self.findIndex((u) => u.name === user.name) === index; - }); - if (res.length !== 0) setFormData({ ...formData, userID: res[0].id }); - return res; - }, [bureauId]); - return ( <Modal className='md:w-1/2'> <div className='w-full'> @@ -79,79 +56,41 @@ export default function EditModal(props: ModalProps) { <CloseButton onClick={() => props.setShowModal(false)} /> </div> </div> - <h1 className='mx-auto mb-10 w-fit text-xl text-black-600'>募金の登録</h1> + <h1 className='mx-auto mb-10 w-fit text-xl text-black-600'>年度の編集</h1> <div className='my-6 grid grid-cols-5 items-center justify-items-center gap-4'> - <p className='col-span-1 text-black-600'>教員の所属</p> + <p className='col-span-1 text-black-600'>年度</p> <div className='col-span-4 w-full'> - <Select + <Input className='w-full' - value={departmentID} - onChange={(e) => { - setDepartmentID(Number(e.target.value)); - }} - > - {props.departments.map((department) => ( - <option key={department.id} value={department.id}> - {department.name} - </option> - ))} - </Select> - </div> - <p className='col-span-1 text-black-600'>教員名</p> - <div className='col-span-4 w-full'> - <Select className='w-full' value={formData.teacherID} onChange={handler('teacherID')}> - {props.teachers - .filter((teacher) => teacher.departmentID === departmentID) - .map((teacher) => ( - <option key={teacher.id} value={teacher.id}> - {teacher.name} - </option> - ))} - </Select> - </div> - <p className='text-black-600'>担当者の局</p> - <div className='col-span-4 w-full'> - <Select value={bureauId} onChange={(e) => setBureauId(Number(e.target.value))}> - {BUREAUS.map((bureaus) => ( - <option key={bureaus.id} value={bureaus.id}> - {bureaus.name} - </option> - ))} - </Select> - </div> - <p className='col-span-1 text-black-600'>担当者</p> - <div className='col-span-4 w-full'> - <Select className='w-full' value={formData.userID} onChange={handler('userID')}> - {filteredUsers.map((user) => ( - <option key={user.id} value={user.id}> - {user.name} - </option> - ))} - </Select> + onChange={handler('year')} + value={formData.year} + type='number' + /> </div> - <p className='cols-span-1 text-black-600'>受け取り日時</p> + <p className='col-span-1 text-black-600'>開始日</p> <div className='col-span-4 w-full'> <Input type='date' - value={formData.receivedAt} - onChange={handler('receivedAt')} + onChange={handler('startedAt')} className='w-full' + value={formData.startedAt && format(new Date(formData.startedAt), 'yyyy-MM-dd')} /> </div> - <p className='col-span-1 text-black-600'>金額</p> - <div className='col-span-4 w-full'> - <Input className='w-full' value={formData.price} onChange={handler('price')} /> - </div> - <p className='col-span-1 text-black-600'>備考</p> + <p className='text-black-600'>終了日</p> <div className='col-span-4 w-full'> - <Input className='w-full' value={formData.remark} onChange={handler('remark')} /> + <Input + type='date' + onChange={handler('endedAt')} + className='w-full' + value={formData.endedAt && format(new Date(formData.endedAt), 'yyyy-MM-dd')} + /> </div> </div> <div className='mx-auto mb-5 w-fit'> <PrimaryButton className={'mx-2'} onClick={() => { - submitFundInformation(formData); + submitYearRecords(formData); props.setShowModal(false); router.reload(); }} diff --git a/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx b/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx index 228efdcb2..8b7a89a2c 100644 --- a/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx +++ b/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx @@ -1,12 +1,14 @@ import React, { useState } from 'react'; import DeleteModal from './DeleteModal'; +import { YearRecords } from '@/type/common'; import { DeleteButton } from '@components/common'; interface Props { children?: React.ReactNode; id: number; isDisabled: boolean; + yearRecord: YearRecords; } const OpenDeleteModalButton: React.FC<Props> = (props) => { @@ -17,7 +19,9 @@ const OpenDeleteModalButton: React.FC<Props> = (props) => { return ( <> <DeleteButton onClick={onOpen} isDisabled={props.isDisabled} /> - {isOpen && <DeleteModal id={props.id} setShowModal={setIsOpen} />} + {isOpen && ( + <DeleteModal id={props.id} setShowModal={setIsOpen} yearRecord={props.yearRecord} /> + )} </> ); }; diff --git a/view/next-project/src/components/year_periods/OpenEditModalButton.tsx b/view/next-project/src/components/year_periods/OpenEditModalButton.tsx index 7dd948082..8a6b79609 100644 --- a/view/next-project/src/components/year_periods/OpenEditModalButton.tsx +++ b/view/next-project/src/components/year_periods/OpenEditModalButton.tsx @@ -2,17 +2,14 @@ import React, { useState } from 'react'; import EditModal from './EditModal'; import { EditButton } from '@components/common'; -import { Teacher, Department, User, FundInformation } from '@type/common'; +import { YearRecords } from '@type/common'; interface Props { - teachers: Teacher[]; - departments: Department[]; - users: User[]; - fundInformation: FundInformation; - isDisabled: boolean; + yearRecords: YearRecords; + isDisabled?: boolean; } -export const OpenAddModalButton = (props: Props) => { +export const OpenEditModalButton = (props: Props) => { const [isOpen, setIsOpen] = useState<boolean>(false); return ( @@ -23,17 +20,9 @@ export const OpenAddModalButton = (props: Props) => { }} isDisabled={props.isDisabled} /> - {isOpen && ( - <EditModal - setShowModal={setIsOpen} - teachers={props.teachers} - departments={props.departments} - users={props.users} - fundInformation={props.fundInformation} - /> - )} + {isOpen && <EditModal setShowModal={setIsOpen} yearRecords={props.yearRecords} />} </> ); }; -export default OpenAddModalButton; +export default OpenEditModalButton; diff --git a/view/next-project/src/pages/year_periods/index.tsx b/view/next-project/src/pages/year_periods/index.tsx index 54f02d445..c4dcf9122 100644 --- a/view/next-project/src/pages/year_periods/index.tsx +++ b/view/next-project/src/pages/year_periods/index.tsx @@ -5,6 +5,8 @@ import { useEffect, useState, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import OpenAddModalButton from '@/components/year_periods/OpenAddModalButton'; +import OpenDeleteModalButton from '@/components/year_periods/OpenDeleteModalButton'; +import OpenEditModalButton from '@/components/year_periods/OpenEditModalButton'; import { authAtom } from '@/store/atoms'; import { getCurrentUser } from '@/utils/api/currentUser'; import { get } from '@api/api_methods'; @@ -145,7 +147,16 @@ export default function Periods(props: Props) { index === 0 ? 'pb-3 pt-4' : 'py-3', index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', )} - ></td> + > + <div className='flex gap-2'> + <OpenEditModalButton yearRecords={yearRecord} /> + <OpenDeleteModalButton + id={yearRecord.id || 0} + isDisabled={false} + yearRecord={yearRecord} + /> + </div> + </td> </tr> ))} </tbody> From 20aa7eb7d4f222519d9dcd4039b68121338f8ace Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sat, 18 Nov 2023 12:12:28 +0900 Subject: [PATCH 18/54] =?UTF-8?q?=E5=B9=B4=E5=BA=A6=E3=83=86=E3=83=BC?= =?UTF-8?q?=E3=83=96=E3=83=AB=E5=89=8A=E9=99=A4API=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/controller/year_controller.go | 10 ++++++++++ api/externals/repository/year_repository.go | 5 +++++ api/internals/usecase/year_usecase.go | 5 +++++ api/router/router.go | 2 +- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/api/externals/controller/year_controller.go b/api/externals/controller/year_controller.go index f89f444bb..873bb4db6 100644 --- a/api/externals/controller/year_controller.go +++ b/api/externals/controller/year_controller.go @@ -25,6 +25,7 @@ type YearController interface { IndexYearPeriods(echo.Context) error CreateYearPeriod(echo.Context) error UpdateYearPeriod(echo.Context) error + DestroyYearRecords(echo.Context) error } func NewYearController(u usecase.YearUseCase) YearController { @@ -116,3 +117,12 @@ func (y *yearController) UpdateYearPeriod(c echo.Context) error { } return c.JSON(http.StatusCreated, updateYearPeriod) } + +func (y *yearController) DestroyYearRecords(c echo.Context) error { + id := c.Param("id") + err := y.u.DestroyYearRecords(c.Request().Context(), id) + if err != nil { + return err + } + return c.String(http.StatusOK, "Destroy Year Records") +} diff --git a/api/externals/repository/year_repository.go b/api/externals/repository/year_repository.go index 253980439..c7b235648 100644 --- a/api/externals/repository/year_repository.go +++ b/api/externals/repository/year_repository.go @@ -26,6 +26,7 @@ type YearRepository interface { FindPeriodLatestRecord(context.Context) (*sql.Row, error) FindYearPeriodByID(context.Context, string) (*sql.Row, error) UpdateYearPeriod(context.Context, string, string, string, string) error + DestroyYearRecords(context.Context, string) error } func NewYearRepository(c db.Client, ac abstract.Crud) YearRepository { @@ -164,4 +165,8 @@ func (y *yearRepository) FindYearPeriodByID(c context.Context, id string) (*sql. return y.crud.ReadByID(c, query) } +func (y *yearRepository) DestroyYearRecords(c context.Context, id string) error { + query := "DELETE FROM year_records WHERE id = " + id + return y.crud.UpdateDB(c, query) +} diff --git a/api/internals/usecase/year_usecase.go b/api/internals/usecase/year_usecase.go index 893f53118..595d0dc00 100644 --- a/api/internals/usecase/year_usecase.go +++ b/api/internals/usecase/year_usecase.go @@ -21,6 +21,7 @@ type YearUseCase interface { GetYearPeriods(context.Context) ([]domain.YearPeriod, error) CreateYearPeriod(context.Context, string, string, string) (domain.YearPeriod, error) UpdateYearPeriod(context.Context, string, string, string, string) (domain.YearPeriod, error) + DestroyYearRecords(context.Context, string) error } func NewYearUseCase(rep rep.YearRepository) YearUseCase { @@ -174,3 +175,7 @@ func (y *yearUseCase) UpdateYearPeriod(c context.Context, id string, year string return updateYearPeriod, nil } +func (y *yearUseCase) DestroyYearRecords(c context.Context, id string) error { + err := y.rep.DestroyYearRecords(c, id) + return err +} diff --git a/api/router/router.go b/api/router/router.go index 2bd7b2e9b..0e9c730b3 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -216,5 +216,5 @@ func (r router) ProvideRouter(e *echo.Echo) { e.GET("/years/periods", r.yearController.IndexYearPeriods) e.POST("/years/periods", r.yearController.CreateYearPeriod) e.PUT("/years/periods/:id", r.yearController.UpdateYearPeriod) - + e.DELETE("/years/periods/:id", r.yearController.DestroyYearRecords) } From a5f6c55d4dea4276a81b25afe4547b81e2892a8f Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sat, 18 Nov 2023 12:52:01 +0900 Subject: [PATCH 19/54] =?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/year_repository.go | 6 +- mysql/db/purcahse_items.sql | 2 + mysql/db/purchase_orders.sql | 16 +- mysql/db/year_records.sql | 4 +- mysql/db/years.sql | 1 - .../src/pages/year_periods/index.tsx | 141 ++++++++++-------- 6 files changed, 92 insertions(+), 78 deletions(-) diff --git a/api/externals/repository/year_repository.go b/api/externals/repository/year_repository.go index c7b235648..46666213a 100644 --- a/api/externals/repository/year_repository.go +++ b/api/externals/repository/year_repository.go @@ -107,9 +107,9 @@ func (y *yearRepository) CreateYearPeriod(c context.Context, year string, starte y.crud.UpdateDB(c, query) query = `SELECT id FROM years WHERE year = `+ year +";" row, err := y.crud.ReadByID(c, query) - last_id := 0 + id := 0 err = row.Scan( - &last_id, + &id, ) if err != nil { return err @@ -119,7 +119,7 @@ func (y *yearRepository) CreateYearPeriod(c context.Context, year string, starte year_records (year_id, started_at, ended_at) VALUES - (`+strconv.Itoa(last_id)+", '"+startedAt+"', '" +endedAt+"');" + (`+strconv.Itoa(id)+", '"+startedAt+"', '" +endedAt+"');" return y.crud.UpdateDB(c, query) } diff --git a/mysql/db/purcahse_items.sql b/mysql/db/purcahse_items.sql index 01fe8faab..9c0bdafaf 100644 --- a/mysql/db/purcahse_items.sql +++ b/mysql/db/purcahse_items.sql @@ -21,5 +21,7 @@ INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_i INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('机', 20000, 2, 'test-detail2', 'https://nutfes.net', 3, true); INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('椅子', 30000, 3, 'test-detail3', 'https://nutfes.net', 3, false); INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('酒', 10000, 10, 'test-detail', 'https://nutfes.net', 4, true); +INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('封筒', 100, 100, 'test-detail2', 'https://nutfes.net', 5, false); +INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('領収書', 100, 50, 'test-detail3', 'https://nutfes.net', 6, true); INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('封筒', 100, 100, 'test-detail2', 'https://nutfes.net', 8, false); INSERT into purchase_items (item, price, quantity, detail, url, purchase_order_id, finance_check )values ('領収書', 100, 50, 'test-detail3', 'https://nutfes.net', 7, true); diff --git a/mysql/db/purchase_orders.sql b/mysql/db/purchase_orders.sql index 96cc8531a..730ba6a5e 100644 --- a/mysql/db/purchase_orders.sql +++ b/mysql/db/purchase_orders.sql @@ -11,11 +11,11 @@ CREATE TABLE purchase_orders ( PRIMARY KEY (id) ); -INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2022-2-22', 1, 1, true); -INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2022-3-28', 1, 1, true); -INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2022-4-6', 1, 2, true); -INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2022-3-28', 1, 3, false); -INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2022-4-6', 1, 4, true); -INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2022-4-6', 1, 5, true); -INSERT into purchase_orders (deadline, user_id, expense_id, finance_check, created_at, updated_at) values ('2024-4-6', 1, 4, true, '2023-11-16 00:00:00', '2023-11-16 00:00:00'); -INSERT into purchase_orders (deadline, user_id, expense_id, finance_check, created_at, updated_at) values ('2024-4-6', 1, 5, true, '2023-11-16 00:00:00', '2023-11-16 00:00:00'); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2024-2-22', 1, 1, true); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2024-3-28', 1, 1, true); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2024-4-6', 1, 2, true); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2024-3-28', 1, 3, false); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2024-4-6', 1, 4, true); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check) values ('2024-4-6', 1, 5, true); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check, created_at, updated_at) values ('2023-4-6', 1, 4, true, '2022-11-16 00:00:00', '2022-11-16 00:00:00'); +INSERT into purchase_orders (deadline, user_id, expense_id, finance_check, created_at, updated_at) values ('2023-4-6', 1, 5, true, '2022-11-16 00:00:00', '2022-11-16 00:00:00'); diff --git a/mysql/db/year_records.sql b/mysql/db/year_records.sql index 0d9cb396c..cd2483306 100644 --- a/mysql/db/year_records.sql +++ b/mysql/db/year_records.sql @@ -10,5 +10,5 @@ CREATE TABLE year_records ( PRIMARY KEY (id) ); -INSERT INTO year_records (year_id, started_at, ended_at) values (2, '2022-01-01 00:00:00', '2023-11-15 00:00:00'); -INSERT INTO year_records (year_id, started_at, ended_at) values (3, '2023-11-15 00:00:00', '2024-11-15 00:00:00'); +INSERT INTO year_records (year_id, started_at, ended_at) values (1, '2022-11-15 00:00:00', '2023-11-15 00:00:00'); +INSERT INTO year_records (year_id, started_at, ended_at) values (2, '2023-11-15 00:00:00', '2024-11-15 00:00:00'); diff --git a/mysql/db/years.sql b/mysql/db/years.sql index df6d3a45e..d1c8f8871 100644 --- a/mysql/db/years.sql +++ b/mysql/db/years.sql @@ -8,6 +8,5 @@ CREATE TABLE years ( PRIMARY KEY (id) ); -INSERT into years (year) values (2022); INSERT into years (year) values (2023); INSERT into years (year) values (2024); diff --git a/view/next-project/src/pages/year_periods/index.tsx b/view/next-project/src/pages/year_periods/index.tsx index c4dcf9122..34c01ce88 100644 --- a/view/next-project/src/pages/year_periods/index.tsx +++ b/view/next-project/src/pages/year_periods/index.tsx @@ -36,13 +36,15 @@ export default function Periods(props: Props) { const auth = useRecoilValue(authAtom); const [currentUser, setCurrentUser] = useState<User>(); - const formatYearRecords = yearRecords.map((yearRecord) => { - return { - ...yearRecord, - startedAt: yearRecord.startedAt && new Date(yearRecord.startedAt).toLocaleDateString('ja'), - endedAt: yearRecord.endedAt && new Date(yearRecord.endedAt).toLocaleDateString('ja'), - }; - }); + const formatYearRecords = + yearRecords && + yearRecords.map((yearRecord) => { + return { + ...yearRecord, + startedAt: yearRecord.startedAt && new Date(yearRecord.startedAt).toLocaleDateString('ja'), + endedAt: yearRecord.endedAt && new Date(yearRecord.endedAt).toLocaleDateString('ja'), + }; + }); useEffect(() => { const getUser = async () => { @@ -53,8 +55,8 @@ export default function Periods(props: Props) { }, []); // ログイン中のユーザの権限 - const isDeveloper = useMemo(() => { - if (currentUser?.roleID === 2) { + const isDeveloperOrAdimin = useMemo(() => { + if (currentUser?.roleID === 2 || currentUser?.roleID === 3) { return true; } else { return false; @@ -63,10 +65,10 @@ export default function Periods(props: Props) { useEffect(() => { if (!currentUser?.roleID) return; - if (!isDeveloper) { + if (!isDeveloperOrAdimin) { router.push('/purchaseorders'); } - }, [isDeveloper, currentUser?.roleID]); + }, [isDeveloperOrAdimin, currentUser?.roleID]); return ( <MainLayout> @@ -100,65 +102,76 @@ export default function Periods(props: Props) { <th className='w-1/4 border border-x-white-0 border-b-primary-1 border-t-white-0 py-3'> <p className='text-center text-sm text-black-600'>終了日</p> </th> + <th className='w-1/4 border border-x-white-0 border-b-primary-1 border-t-white-0 py-3'></th> </tr> </thead> <tbody className='border border-x-white-0 border-b-primary-1 border-t-white-0'> - {formatYearRecords.map((yearRecord: YearRecords, index) => ( - <tr key={yearRecord.id}> - <td - className={clsx( - 'px-1 py-3', - index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', - )} - > - <p className='text-center text-sm text-black-600'>{yearRecord.id}</p> - </td> - <td - className={clsx( - 'px-1', - index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', - )} - > - <p className='text-center text-sm text-black-600'>{yearRecord.year}</p> - </td> - <td - className={clsx( - 'px-1', - index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', - )} - > - <p className='text-center text-sm text-black-600'>{yearRecord.startedAt}</p> - </td> - <td - className={clsx( - 'px-1', - index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', - )} - > - <p className='text-center text-sm text-black-600'>{yearRecord.endedAt}</p> - </td> - <td - className={clsx( - 'px-1', - index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', - )} - > - <div className='flex gap-2'> - <OpenEditModalButton yearRecords={yearRecord} /> - <OpenDeleteModalButton - id={yearRecord.id || 0} - isDisabled={false} - yearRecord={yearRecord} - /> + {formatYearRecords && + formatYearRecords.map((yearRecord: YearRecords, index) => ( + <tr key={yearRecord.id}> + <td + className={clsx( + 'px-1 py-3', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + > + <p className='text-center text-sm text-black-600'>{yearRecord.id}</p> + </td> + <td + className={clsx( + 'px-1', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + > + <p className='text-center text-sm text-black-600'>{yearRecord.year}</p> + </td> + <td + className={clsx( + 'px-1', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + > + <p className='text-center text-sm text-black-600'>{yearRecord.startedAt}</p> + </td> + <td + className={clsx( + 'px-1', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + > + <p className='text-center text-sm text-black-600'>{yearRecord.endedAt}</p> + </td> + <td + className={clsx( + 'px-1', + index === 0 ? 'pb-3 pt-4' : 'py-3', + index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + )} + > + <div className='flex gap-2'> + <OpenEditModalButton yearRecords={yearRecord} /> + <OpenDeleteModalButton + id={yearRecord.id || 0} + isDisabled={false} + yearRecord={yearRecord} + /> + </div> + </td> + </tr> + ))} + {!formatYearRecords && ( + <tr className='border-b border-primary-1'> + <td className='px-1 py-3' colSpan={4}> + <div className='flex justify-center'> + <div className='text-sm text-black-600'>データがありません</div> </div> </td> </tr> - ))} + )} </tbody> </table> </div> From 309911e50a69ae9bdd67b07d43a3561b5c9b2ad2 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sat, 18 Nov 2023 13:05:23 +0900 Subject: [PATCH 20/54] =?UTF-8?q?=E3=82=AA=E3=83=96=E3=82=B8=E3=82=A7?= =?UTF-8?q?=E3=82=AF=E3=83=88=E5=90=8D=E3=82=92yearPeriod=E3=81=A7?= =?UTF-8?q?=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/year_periods/AddModal.tsx | 8 +-- .../components/year_periods/DeleteModal.tsx | 6 +-- .../src/components/year_periods/EditModal.tsx | 16 +++--- .../year_periods/OpenDeleteModalButton.tsx | 6 +-- .../year_periods/OpenEditModalButton.tsx | 6 +-- .../src/pages/purchaseorders/index.tsx | 14 ++--- .../src/pages/year_periods/index.tsx | 52 +++++++++---------- view/next-project/src/type/common.ts | 2 +- 8 files changed, 55 insertions(+), 55 deletions(-) diff --git a/view/next-project/src/components/year_periods/AddModal.tsx b/view/next-project/src/components/year_periods/AddModal.tsx index 9afebcd94..0069e8440 100644 --- a/view/next-project/src/components/year_periods/AddModal.tsx +++ b/view/next-project/src/components/year_periods/AddModal.tsx @@ -5,7 +5,7 @@ import { useRecoilState } from 'recoil'; import { Modal, CloseButton, Input, PrimaryButton } from '../common'; import { userAtom } from '@/store/atoms'; -import { YearRecords } from '@/type/common'; +import { YearPeriods } from '@/type/common'; import { post } from '@/utils/api/api_methods'; interface ModalProps { @@ -17,7 +17,7 @@ const OpenAddModal: FC<ModalProps> = (props) => { const router = useRouter(); - const [formData, setFormData] = useState<YearRecords>({ + const [formData, setFormData] = useState<YearPeriods>({ year: 0, startedAt: '', endedAt: '', @@ -29,7 +29,7 @@ const OpenAddModal: FC<ModalProps> = (props) => { setFormData({ ...formData, [input]: e.target.value }); }; - const submit = async (data: YearRecords) => { + const submit = async (data: YearPeriods) => { const startedAt = data.startedAt && new Date(data.startedAt); const endedAt = data.endedAt && new Date(data.endedAt); const formattedStartedAt = startedAt && format(startedAt, "yyyy-MM-dd'T'HH:mm:ss'Z'"); @@ -43,7 +43,7 @@ const OpenAddModal: FC<ModalProps> = (props) => { await addYearPeriod(submitData); }; - const addYearPeriod = async (data: YearRecords) => { + const addYearPeriod = async (data: YearPeriods) => { const addPeriodUrl = process.env.CSR_API_URI + '/years/periods'; console.log(data); await post(addPeriodUrl, data); diff --git a/view/next-project/src/components/year_periods/DeleteModal.tsx b/view/next-project/src/components/year_periods/DeleteModal.tsx index bd8f682a6..4f83c8b4b 100644 --- a/view/next-project/src/components/year_periods/DeleteModal.tsx +++ b/view/next-project/src/components/year_periods/DeleteModal.tsx @@ -1,7 +1,7 @@ import { useRouter } from 'next/router'; import React, { Dispatch, FC, SetStateAction } from 'react'; -import { YearRecords } from '@/type/common'; +import { YearPeriods } from '@/type/common'; import { del } from '@api/api_methods'; import { Modal, CloseButton, OutlinePrimaryButton, PrimaryButton } from '@components/common'; @@ -9,7 +9,7 @@ interface ModalProps { setShowModal: Dispatch<SetStateAction<boolean>>; children?: React.ReactNode; id: number | string; - yearRecord: YearRecords; + yearPeriod: YearPeriods; } const DeleteModal: FC<ModalProps> = (props) => { @@ -33,7 +33,7 @@ const DeleteModal: FC<ModalProps> = (props) => { </div> </div> <div className='mx-auto mb-5 w-fit text-xl text-black-600'>年度の削除</div> - <div className='mx-auto my-5 w-fit text-xl text-black-600'>{props.yearRecord.year}年度</div> + <div className='mx-auto my-5 w-fit text-xl text-black-600'>{props.yearPeriod.year}年度</div> <div className='mx-auto my-5 w-fit text-xl'>削除しますか?</div> <div className=''> <div className='flex flex-row justify-center gap-5'> diff --git a/view/next-project/src/components/year_periods/EditModal.tsx b/view/next-project/src/components/year_periods/EditModal.tsx index c7d8fc2eb..e5faa43dd 100644 --- a/view/next-project/src/components/year_periods/EditModal.tsx +++ b/view/next-project/src/components/year_periods/EditModal.tsx @@ -4,21 +4,21 @@ import { Dispatch, SetStateAction, useState } from 'react'; import { Modal, Input, CloseButton, PrimaryButton } from '../common'; import { put } from '@api/api_methods'; -import { YearRecords } from '@type/common'; +import { YearPeriods } from '@type/common'; interface ModalProps { setShowModal: Dispatch<SetStateAction<boolean>>; - yearRecords: YearRecords; + yearPeriod: YearPeriods; } export default function EditModal(props: ModalProps) { const router = useRouter(); - const [formData, setFormData] = useState<YearRecords>({ - id: props.yearRecords.id, - year: props.yearRecords.year, - startedAt: props.yearRecords.startedAt, - endedAt: props.yearRecords.endedAt, + const [formData, setFormData] = useState<YearPeriods>({ + id: props.yearPeriod.id, + year: props.yearPeriod.year, + startedAt: props.yearPeriod.startedAt, + endedAt: props.yearPeriod.endedAt, }); const handler = @@ -32,7 +32,7 @@ export default function EditModal(props: ModalProps) { setFormData({ ...formData, [input]: e.target.value }); }; - const submitYearRecords = async (data: YearRecords) => { + const submitYearRecords = async (data: YearPeriods) => { const submitYearRecordsURL = process.env.CSR_API_URI + '/years/periods/' + data.id; const startedAt = data.startedAt && new Date(data.startedAt); const endedAt = data.endedAt && new Date(data.endedAt); diff --git a/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx b/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx index 8b7a89a2c..8b8e4b064 100644 --- a/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx +++ b/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx @@ -1,14 +1,14 @@ import React, { useState } from 'react'; import DeleteModal from './DeleteModal'; -import { YearRecords } from '@/type/common'; +import { YearPeriods } from '@/type/common'; import { DeleteButton } from '@components/common'; interface Props { children?: React.ReactNode; id: number; isDisabled: boolean; - yearRecord: YearRecords; + yearPeriod: YearPeriods; } const OpenDeleteModalButton: React.FC<Props> = (props) => { @@ -20,7 +20,7 @@ const OpenDeleteModalButton: React.FC<Props> = (props) => { <> <DeleteButton onClick={onOpen} isDisabled={props.isDisabled} /> {isOpen && ( - <DeleteModal id={props.id} setShowModal={setIsOpen} yearRecord={props.yearRecord} /> + <DeleteModal id={props.id} setShowModal={setIsOpen} yearPeriod={props.yearPeriod} /> )} </> ); diff --git a/view/next-project/src/components/year_periods/OpenEditModalButton.tsx b/view/next-project/src/components/year_periods/OpenEditModalButton.tsx index 8a6b79609..d89b4a344 100644 --- a/view/next-project/src/components/year_periods/OpenEditModalButton.tsx +++ b/view/next-project/src/components/year_periods/OpenEditModalButton.tsx @@ -2,10 +2,10 @@ import React, { useState } from 'react'; import EditModal from './EditModal'; import { EditButton } from '@components/common'; -import { YearRecords } from '@type/common'; +import { YearPeriods } from '@type/common'; interface Props { - yearRecords: YearRecords; + yearPeriod: YearPeriods; isDisabled?: boolean; } @@ -20,7 +20,7 @@ export const OpenEditModalButton = (props: Props) => { }} isDisabled={props.isDisabled} /> - {isOpen && <EditModal setShowModal={setIsOpen} yearRecords={props.yearRecords} />} + {isOpen && <EditModal setShowModal={setIsOpen} yearPeriod={props.yearPeriod} />} </> ); }; diff --git a/view/next-project/src/pages/purchaseorders/index.tsx b/view/next-project/src/pages/purchaseorders/index.tsx index 053417fea..a2e68a61d 100644 --- a/view/next-project/src/pages/purchaseorders/index.tsx +++ b/view/next-project/src/pages/purchaseorders/index.tsx @@ -20,14 +20,14 @@ import { User, PurchaseOrderView, Expense, - YearRecords, + YearPeriods, } from '@type/common'; interface Props { user: User; purchaseOrderView: PurchaseOrderView[]; expenses: Expense[]; - yearRecords: YearRecords[]; + yearPeriods: YearPeriods[]; } export async function getServerSideProps() { const getPeriodsUrl = process.env.SSR_API_URI + '/years/periods'; @@ -43,7 +43,7 @@ export async function getServerSideProps() { props: { purchaseOrderView: purchaseOrderViewRes, expenses: expenseRes, - yearRecords: periodsRes, + yearPeriods: periodsRes, }, }; } @@ -77,9 +77,9 @@ export default function PurchaseOrders(props: Props) { return datetime2; }; - const yearRecords = props.yearRecords; + const yearPeriods = props.yearPeriods; const [selectedYear, setSelectedYear] = useState<string>( - yearRecords ? String(yearRecords[yearRecords.length - 1].year) : '2024', + yearPeriods ? String(yearPeriods[yearPeriods.length - 1].year) : '2024', ); const getPurchaseOrders = async () => { @@ -186,8 +186,8 @@ export default function PurchaseOrders(props: Props) { setSelectedYear(e.target.value); }} > - {props.yearRecords && - props.yearRecords.map((year) => { + {props.yearPeriods && + props.yearPeriods.map((year) => { return ( <option value={year.year} key={year.id}> {year.year}年度 diff --git a/view/next-project/src/pages/year_periods/index.tsx b/view/next-project/src/pages/year_periods/index.tsx index 34c01ce88..ba57654f6 100644 --- a/view/next-project/src/pages/year_periods/index.tsx +++ b/view/next-project/src/pages/year_periods/index.tsx @@ -12,10 +12,10 @@ import { getCurrentUser } from '@/utils/api/currentUser'; import { get } from '@api/api_methods'; import { Card, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout/MainLayout'; -import { YearRecords, User } from '@type/common'; +import { YearPeriods, User } from '@type/common'; interface Props { - yearRecords: YearRecords[]; + yearPeriods: YearPeriods[]; } export const getServerSideProps = async () => { @@ -24,25 +24,25 @@ export const getServerSideProps = async () => { return { props: { - yearRecords: periodsRes, + yearPeriods: periodsRes, }, }; }; export default function Periods(props: Props) { - const { yearRecords } = props; + const { yearPeriods } = props; const router = useRouter(); const auth = useRecoilValue(authAtom); const [currentUser, setCurrentUser] = useState<User>(); - const formatYearRecords = - yearRecords && - yearRecords.map((yearRecord) => { + const formatYearPeriods = + yearPeriods && + yearPeriods.map((yearPeriod) => { return { - ...yearRecord, - startedAt: yearRecord.startedAt && new Date(yearRecord.startedAt).toLocaleDateString('ja'), - endedAt: yearRecord.endedAt && new Date(yearRecord.endedAt).toLocaleDateString('ja'), + ...yearPeriod, + startedAt: yearPeriod.startedAt && new Date(yearPeriod.startedAt).toLocaleDateString('ja'), + endedAt: yearPeriod.endedAt && new Date(yearPeriod.endedAt).toLocaleDateString('ja'), }; }); @@ -106,64 +106,64 @@ export default function Periods(props: Props) { </tr> </thead> <tbody className='border border-x-white-0 border-b-primary-1 border-t-white-0'> - {formatYearRecords && - formatYearRecords.map((yearRecord: YearRecords, index) => ( - <tr key={yearRecord.id}> + {formatYearPeriods && + formatYearPeriods.map((yearPeriod: YearPeriods, index) => ( + <tr key={yearPeriod.id}> <td className={clsx( 'px-1 py-3', index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + index === formatYearPeriods.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', )} > - <p className='text-center text-sm text-black-600'>{yearRecord.id}</p> + <p className='text-center text-sm text-black-600'>{yearPeriod.id}</p> </td> <td className={clsx( 'px-1', index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + index === formatYearPeriods.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', )} > - <p className='text-center text-sm text-black-600'>{yearRecord.year}</p> + <p className='text-center text-sm text-black-600'>{yearPeriod.year}</p> </td> <td className={clsx( 'px-1', index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + index === formatYearPeriods.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', )} > - <p className='text-center text-sm text-black-600'>{yearRecord.startedAt}</p> + <p className='text-center text-sm text-black-600'>{yearPeriod.startedAt}</p> </td> <td className={clsx( 'px-1', index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + index === formatYearPeriods.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', )} > - <p className='text-center text-sm text-black-600'>{yearRecord.endedAt}</p> + <p className='text-center text-sm text-black-600'>{yearPeriod.endedAt}</p> </td> <td className={clsx( 'px-1', index === 0 ? 'pb-3 pt-4' : 'py-3', - index === yearRecords.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', + index === formatYearPeriods.length - 1 ? 'pb-4 pt-3' : 'border-b py-3', )} > <div className='flex gap-2'> - <OpenEditModalButton yearRecords={yearRecord} /> + <OpenEditModalButton yearPeriod={yearPeriod} /> <OpenDeleteModalButton - id={yearRecord.id || 0} + id={yearPeriod.id || 0} isDisabled={false} - yearRecord={yearRecord} + yearPeriod={yearPeriod} /> </div> </td> </tr> ))} - {!formatYearRecords && ( + {!formatYearPeriods && ( <tr className='border-b border-primary-1'> <td className='px-1 py-3' colSpan={4}> <div className='flex justify-center'> diff --git a/view/next-project/src/type/common.ts b/view/next-project/src/type/common.ts index fdef5df92..3ccc744eb 100644 --- a/view/next-project/src/type/common.ts +++ b/view/next-project/src/type/common.ts @@ -234,7 +234,7 @@ export interface PurchaseReportView { } // // Year(年度) -export interface YearRecords { +export interface YearPeriods { id?: number; year: number; startedAt?: string; From 0e562afdbf58e2d592e6e200a8baaf6366c5b394 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sat, 18 Nov 2023 13:16:10 +0900 Subject: [PATCH 21/54] =?UTF-8?q?yearPeriod=E3=81=A7=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/externals/controller/year_controller.go | 6 +-- .../repository/purchase_order_repository.go | 8 +-- api/externals/repository/year_repository.go | 54 +++++++++---------- api/internals/usecase/year_usecase.go | 6 +-- api/router/router.go | 2 +- .../db/{year_records.sql => year_periods.sql} | 6 +-- 6 files changed, 41 insertions(+), 41 deletions(-) rename mysql/db/{year_records.sql => year_periods.sql} (73%) diff --git a/api/externals/controller/year_controller.go b/api/externals/controller/year_controller.go index 873bb4db6..a6bd268fe 100644 --- a/api/externals/controller/year_controller.go +++ b/api/externals/controller/year_controller.go @@ -25,7 +25,7 @@ type YearController interface { IndexYearPeriods(echo.Context) error CreateYearPeriod(echo.Context) error UpdateYearPeriod(echo.Context) error - DestroyYearRecords(echo.Context) error + DestroyYearPeriod(echo.Context) error } func NewYearController(u usecase.YearUseCase) YearController { @@ -118,9 +118,9 @@ func (y *yearController) UpdateYearPeriod(c echo.Context) error { return c.JSON(http.StatusCreated, updateYearPeriod) } -func (y *yearController) DestroyYearRecords(c echo.Context) error { +func (y *yearController) DestroyYearPeriod(c echo.Context) error { id := c.Param("id") - err := y.u.DestroyYearRecords(c.Request().Context(), id) + err := y.u.DestroyYearPeriod(c.Request().Context(), id) if err != nil { return err } diff --git a/api/externals/repository/purchase_order_repository.go b/api/externals/repository/purchase_order_repository.go index f4e6ea99e..960a6d7b0 100644 --- a/api/externals/repository/purchase_order_repository.go +++ b/api/externals/repository/purchase_order_repository.go @@ -185,15 +185,15 @@ func (p *purchaseOrderRepository) AllUserInfoByYear(c context.Context, year stri ON purchase_orders.user_id = users.id INNER JOIN - year_records + year_periods ON - purchase_orders.created_at > year_records.started_at + purchase_orders.created_at > year_periods.started_at AND - purchase_orders.created_at < year_records.ended_at + purchase_orders.created_at < year_periods.ended_at INNER JOIN years ON - year_records.year_id = years.id + year_periods.year_id = years.id WHERE years.year = ` + year + " ORDER BY purchase_orders.id" diff --git a/api/externals/repository/year_repository.go b/api/externals/repository/year_repository.go index 46666213a..4970c5dfc 100644 --- a/api/externals/repository/year_repository.go +++ b/api/externals/repository/year_repository.go @@ -26,7 +26,7 @@ type YearRepository interface { FindPeriodLatestRecord(context.Context) (*sql.Row, error) FindYearPeriodByID(context.Context, string) (*sql.Row, error) UpdateYearPeriod(context.Context, string, string, string, string) error - DestroyYearRecords(context.Context, string) error + DestroyYearPeriod(context.Context, string) error } func NewYearRepository(c db.Client, ac abstract.Crud) YearRepository { @@ -68,18 +68,18 @@ func (y *yearRepository) FindPeriodLatestRecord(c context.Context) (*sql.Row, er SELECT years.id, years.year, - year_records.started_at, - year_records.ended_at, - year_records.created_at, - year_records.updated_at + year_periods.started_at, + year_periods.ended_at, + year_periods.created_at, + year_periods.updated_at FROM years INNER JOIN - year_records + year_periods ON - years.id = year_records.year_id + years.id = year_periods.year_id ORDER BY - year_records.id + year_periods.id DESC LIMIT 1` return y.crud.ReadByID(c, query) } @@ -87,18 +87,18 @@ func (y *yearRepository) FindPeriodLatestRecord(c context.Context) (*sql.Row, er func (y *yearRepository) AllYearPeriods(c context.Context) (*sql.Rows, error) { query := ` SELECT - year_records.id, + year_periods.id, years.year, - year_records.started_at, - year_records.ended_at, - year_records.created_at, - year_records.updated_at + year_periods.started_at, + year_periods.ended_at, + year_periods.created_at, + year_periods.updated_at FROM years INNER JOIN - year_records + year_periods ON - years.id = year_records.year_id` + years.id = year_periods.year_id` return y.crud.Read(c, query) } @@ -116,7 +116,7 @@ func (y *yearRepository) CreateYearPeriod(c context.Context, year string, starte } query = ` INSERT INTO - year_records + year_periods (year_id, started_at, ended_at) VALUES (`+strconv.Itoa(id)+", '"+startedAt+"', '" +endedAt+"');" @@ -137,7 +137,7 @@ func (y *yearRepository) UpdateYearPeriod(c context.Context,id string, year stri } query = ` UPDATE - year_records + year_periods SET year_id = ` + strconv.Itoa(last_id) + ", started_at = '" + startedAt + @@ -149,24 +149,24 @@ func (y *yearRepository) UpdateYearPeriod(c context.Context,id string, year stri func (y *yearRepository) FindYearPeriodByID(c context.Context, id string) (*sql.Row, error) { query := ` SELECT - year_records.id, + year_periods.id, years.year, - year_records.started_at, - year_records.ended_at, - year_records.created_at, - year_records.updated_at + year_periods.started_at, + year_periods.ended_at, + year_periods.created_at, + year_periods.updated_at FROM years INNER JOIN - year_records + year_periods ON - years.id = year_records.year_id - WHERE year_records.id = `+id+";" + years.id = year_periods.year_id + WHERE year_periods.id = `+id+";" return y.crud.ReadByID(c, query) } -func (y *yearRepository) DestroyYearRecords(c context.Context, id string) error { - query := "DELETE FROM year_records WHERE id = " + id +func (y *yearRepository) DestroyYearPeriod(c context.Context, id string) error { + query := "DELETE FROM year_periods WHERE id = " + id return y.crud.UpdateDB(c, query) } diff --git a/api/internals/usecase/year_usecase.go b/api/internals/usecase/year_usecase.go index 595d0dc00..0c38c247d 100644 --- a/api/internals/usecase/year_usecase.go +++ b/api/internals/usecase/year_usecase.go @@ -21,7 +21,7 @@ type YearUseCase interface { GetYearPeriods(context.Context) ([]domain.YearPeriod, error) CreateYearPeriod(context.Context, string, string, string) (domain.YearPeriod, error) UpdateYearPeriod(context.Context, string, string, string, string) (domain.YearPeriod, error) - DestroyYearRecords(context.Context, string) error + DestroyYearPeriod(context.Context, string) error } func NewYearUseCase(rep rep.YearRepository) YearUseCase { @@ -175,7 +175,7 @@ func (y *yearUseCase) UpdateYearPeriod(c context.Context, id string, year string return updateYearPeriod, nil } -func (y *yearUseCase) DestroyYearRecords(c context.Context, id string) error { - err := y.rep.DestroyYearRecords(c, id) +func (y *yearUseCase) DestroyYearPeriod(c context.Context, id string) error { + err := y.rep.DestroyYearPeriod(c, id) return err } diff --git a/api/router/router.go b/api/router/router.go index 0e9c730b3..c85dfb9a6 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -216,5 +216,5 @@ func (r router) ProvideRouter(e *echo.Echo) { e.GET("/years/periods", r.yearController.IndexYearPeriods) e.POST("/years/periods", r.yearController.CreateYearPeriod) e.PUT("/years/periods/:id", r.yearController.UpdateYearPeriod) - e.DELETE("/years/periods/:id", r.yearController.DestroyYearRecords) + e.DELETE("/years/periods/:id", r.yearController.DestroyYearPeriod) } diff --git a/mysql/db/year_records.sql b/mysql/db/year_periods.sql similarity index 73% rename from mysql/db/year_records.sql rename to mysql/db/year_periods.sql index cd2483306..0cb6ce15f 100644 --- a/mysql/db/year_records.sql +++ b/mysql/db/year_periods.sql @@ -1,6 +1,6 @@ use finansu_db; -CREATE TABLE year_records ( +CREATE TABLE year_periods ( id int(10) unsigned not null auto_increment, year_id int(10) not null, started_at datetime not null, @@ -10,5 +10,5 @@ CREATE TABLE year_records ( PRIMARY KEY (id) ); -INSERT INTO year_records (year_id, started_at, ended_at) values (1, '2022-11-15 00:00:00', '2023-11-15 00:00:00'); -INSERT INTO year_records (year_id, started_at, ended_at) values (2, '2023-11-15 00:00:00', '2024-11-15 00:00:00'); +INSERT INTO year_periods (year_id, started_at, ended_at) values (1, '2022-11-15 00:00:00', '2023-11-15 00:00:00'); +INSERT INTO year_periods (year_id, started_at, ended_at) values (2, '2023-11-15 00:00:00', '2024-11-15 00:00:00'); From 8f85c41d416725d0e2bda3c42e9b04e238fa9012 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sat, 18 Nov 2023 13:30:35 +0900 Subject: [PATCH 22/54] =?UTF-8?q?swagger=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/docs/docs.go | 116 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/api/docs/docs.go b/api/docs/docs.go index e59421d5e..872d77019 100644 --- a/api/docs/docs.go +++ b/api/docs/docs.go @@ -1220,6 +1220,26 @@ const docTemplate = `{ } }, }, + "/purchaseorders/details/{year}": { + "get": { + tags: ["purchase_order"], + "description": "年度で指定されたpurchase_orderに紐づくuserとpurchase_itemを取得", + "parameters": [ + { + "name": "year", + "in": "path", + "description": "year", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "IDで指定されたpurchase_orderに紐づくuserとpurchase_itemを取得", + } + } + }, + }, "/purchasereports": { "get": { tags: ["purchase_report"], @@ -1991,6 +2011,80 @@ const docTemplate = `{ }, }, }, + "/years/periods": { + "get": { + tags: ["year_periods"], + "description": "年度一覧の取得", + "responses": { + "200": { + "description": "year_periodsの一覧を取得", + } + } + }, + "post": { + tags: ["year_periods"], + "description": "year_periodsの作成", + responses: { + "200": { + "description": "作成されたyear_periodsが返ってくる", + } + }, + "parameters": [ + { + "in": "body", + "name": "year_periods", + "schema":{ + "$ref": "#/definitions/year_periods" + }, + }, + ], + }, + }, + "/years/periods/{id}": { + "put": { + tags: ["year_periods"], + "description": "year_periodsの更新", + responses: { + "200": { + "description": "更新されたyear_periodsが返ってくる", + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "id", + "required": true, + "type": "integer" + }, + { + "in": "body", + "name": "year_periods", + "schema":{ + "$ref": "#/definitions/year_periods" + }, + }, + ], + }, + "delete": { + tags: ["year_periods"], + "description": "IDを指定してyear_periodsの削除", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "id", + "required": true, + "type": "integer" + } + ], + responses: { + "200": { + "description": "year_periodsの削除完了", + }, + }, + }, + }, }, "definitions":{ "activity":{ @@ -2150,6 +2244,28 @@ const docTemplate = `{ "purchaseOrderID" }, }, + "year_periods":{ + "properties":{ + "year":{ + "type": "int", + "example": 2024, + + }, + "startedAt":{ + "type": "string", + "example": "0000-00-00T00:00:00Z", + }, + "endedAt":{ + "type": "string", + "example": "0000-00-00T00:00:00Z", + }, + }, + "required":{ + "year", + "startedAt", + "endedAt" + }, + }, }, }` From 6fec28d53ff82b88d27fa93e25837dd96cb5ebba Mon Sep 17 00:00:00 2001 From: TkymHrt <s231053@stn.nagaokaut.ac.jp> Date: Mon, 20 Nov 2023 19:54:18 +0900 Subject: [PATCH 23/54] =?UTF-8?q?[fix]=20=E4=B8=80=E9=83=A8=E3=81=AEprops?= =?UTF-8?q?=E3=82=92datalist=E3=81=AB=E7=B5=B1=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/common/Input/Input.tsx | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/view/next-project/src/components/common/Input/Input.tsx b/view/next-project/src/components/common/Input/Input.tsx index 32cddbc94..daf1b7631 100644 --- a/view/next-project/src/components/common/Input/Input.tsx +++ b/view/next-project/src/components/common/Input/Input.tsx @@ -11,9 +11,10 @@ interface Props { onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void; children?: React.ReactNode; type?: string; - datalist?: { id: number; name: string }[]; - listKey?: string; - enableDatalist?: boolean; + datalist?: { + key: string; + data: { id:number; name: string}[]; + } } function Input(props: Props): JSX.Element { @@ -29,16 +30,16 @@ function Input(props: Props): JSX.Element { value={props.value} onChange={props.onChange} type={props.type} - list={props.enableDatalist ? props.listKey : undefined} + list={props.datalist?.key} > {props.children} </input> - {props.enableDatalist && ( - <datalist id={props.listKey}> - {props.datalist?.map((option) => ( - <option key={option.id} value={option.name} /> - ))} - </datalist> + {props.datalist?.key && props.datalist?.data && ( + <datalist id={props.datalist.key}> + {props.datalist.data.map((option) => ( + <option key={option.id} value={option.name} /> + ))} + </datalist> )} </div> ); From 2d6851e3861001f9c87b0f9e03178003eb227235 Mon Sep 17 00:00:00 2001 From: TkymHrt <s231053@stn.nagaokaut.ac.jp> Date: Mon, 20 Nov 2023 19:54:55 +0900 Subject: [PATCH 24/54] =?UTF-8?q?[fix]=20=E7=B5=B1=E5=90=88=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=81=9Fprops=E3=81=8B=E3=82=89=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E5=80=A4=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/fund_information/AddModal.tsx | 7 ++++--- .../src/components/fund_information/EditModal.tsx | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/view/next-project/src/components/fund_information/AddModal.tsx b/view/next-project/src/components/fund_information/AddModal.tsx index 4db77e873..0cb8b81bf 100644 --- a/view/next-project/src/components/fund_information/AddModal.tsx +++ b/view/next-project/src/components/fund_information/AddModal.tsx @@ -137,9 +137,10 @@ const OpenAddModal: FC<ModalProps> = (props) => { className='w-full' value={formData.price} onChange={handler('price')} - datalist={DONATION_AMOUNT} - listKey='amoutOptions' - enableDatalist={true} + datalist={{ + key: "amoutOptions", + data: DONATION_AMOUNT, + }} /> </div> <p className='col-span-1 text-black-600'>備考</p> diff --git a/view/next-project/src/components/fund_information/EditModal.tsx b/view/next-project/src/components/fund_information/EditModal.tsx index 397683d7c..301fd848d 100644 --- a/view/next-project/src/components/fund_information/EditModal.tsx +++ b/view/next-project/src/components/fund_information/EditModal.tsx @@ -145,9 +145,10 @@ export default function EditModal(props: ModalProps) { className='w-full' value={formData.price} onChange={handler('price')} - datalist={DONATION_AMOUNT} - listKey='amoutOptions' - enableDatalist={true} + datalist={{ + key: "amoutOptions", + data: DONATION_AMOUNT, + }} /> </div> <p className='col-span-1 text-black-600'>備考</p> From 4e8efc89d7c8af94628ba5a465fd7909313c53c3 Mon Sep 17 00:00:00 2001 From: TkymHrt <TkymHrt@users.noreply.github.com> Date: Mon, 20 Nov 2023 10:56:03 +0000 Subject: [PATCH 25/54] formatted by workflow --- .../src/components/common/Input/Input.tsx | 12 ++++++------ .../src/components/fund_information/AddModal.tsx | 2 +- .../src/components/fund_information/EditModal.tsx | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/view/next-project/src/components/common/Input/Input.tsx b/view/next-project/src/components/common/Input/Input.tsx index daf1b7631..2bc392043 100644 --- a/view/next-project/src/components/common/Input/Input.tsx +++ b/view/next-project/src/components/common/Input/Input.tsx @@ -13,8 +13,8 @@ interface Props { type?: string; datalist?: { key: string; - data: { id:number; name: string}[]; - } + data: { id: number; name: string }[]; + }; } function Input(props: Props): JSX.Element { @@ -36,10 +36,10 @@ function Input(props: Props): JSX.Element { </input> {props.datalist?.key && props.datalist?.data && ( <datalist id={props.datalist.key}> - {props.datalist.data.map((option) => ( - <option key={option.id} value={option.name} /> - ))} - </datalist> + {props.datalist.data.map((option) => ( + <option key={option.id} value={option.name} /> + ))} + </datalist> )} </div> ); diff --git a/view/next-project/src/components/fund_information/AddModal.tsx b/view/next-project/src/components/fund_information/AddModal.tsx index 0cb8b81bf..b295659a6 100644 --- a/view/next-project/src/components/fund_information/AddModal.tsx +++ b/view/next-project/src/components/fund_information/AddModal.tsx @@ -138,7 +138,7 @@ const OpenAddModal: FC<ModalProps> = (props) => { value={formData.price} onChange={handler('price')} datalist={{ - key: "amoutOptions", + key: 'amoutOptions', data: DONATION_AMOUNT, }} /> diff --git a/view/next-project/src/components/fund_information/EditModal.tsx b/view/next-project/src/components/fund_information/EditModal.tsx index 301fd848d..651e00355 100644 --- a/view/next-project/src/components/fund_information/EditModal.tsx +++ b/view/next-project/src/components/fund_information/EditModal.tsx @@ -146,7 +146,7 @@ export default function EditModal(props: ModalProps) { value={formData.price} onChange={handler('price')} datalist={{ - key: "amoutOptions", + key: 'amoutOptions', data: DONATION_AMOUNT, }} /> From 946c4254fdcefcee0658b6f34e52fea07cab1303 Mon Sep 17 00:00:00 2001 From: TkymHrt <s231053@stn.nagaokaut.ac.jp> Date: Tue, 21 Nov 2023 16:18:17 +0900 Subject: [PATCH 26/54] =?UTF-8?q?[fix]=20datalist=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E5=88=A4=E5=AE=9A=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/src/components/common/Input/Input.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/next-project/src/components/common/Input/Input.tsx b/view/next-project/src/components/common/Input/Input.tsx index 2bc392043..c80dfad84 100644 --- a/view/next-project/src/components/common/Input/Input.tsx +++ b/view/next-project/src/components/common/Input/Input.tsx @@ -34,7 +34,7 @@ function Input(props: Props): JSX.Element { > {props.children} </input> - {props.datalist?.key && props.datalist?.data && ( + {props.datalist && ( <datalist id={props.datalist.key}> {props.datalist.data.map((option) => ( <option key={option.id} value={option.name} /> From 0668b50cd8e3e3ab0a9718d1adb9bcbb8d3be4bd Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Thu, 23 Nov 2023 23:04:48 +0900 Subject: [PATCH 27/54] =?UTF-8?q?[fix]type=E5=90=8D=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/src/type/common.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/view/next-project/src/type/common.ts b/view/next-project/src/type/common.ts index 3ccc744eb..ba82cf406 100644 --- a/view/next-project/src/type/common.ts +++ b/view/next-project/src/type/common.ts @@ -234,11 +234,11 @@ export interface PurchaseReportView { } // // Year(年度) -export interface YearPeriods { - id?: number; +export interface YearPeriod { + id: number; year: number; - startedAt?: string; - endedAt?: string; + startedAt: string; + endedAt: string; createdAt?: string; updatedAt?: string; } From 4e4e0d002abb90ca58a57f6b80894ade19be8473 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Thu, 23 Nov 2023 23:05:52 +0900 Subject: [PATCH 28/54] =?UTF-8?q?[fix]type=E5=A4=89=E6=9B=B4=E3=81=AB?= =?UTF-8?q?=E4=BC=B4=E3=81=86=E5=B9=B4=E5=BA=A6=E4=B8=80=E8=A6=A7=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/year_periods/index.tsx | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/view/next-project/src/pages/year_periods/index.tsx b/view/next-project/src/pages/year_periods/index.tsx index ba57654f6..d5f9d9653 100644 --- a/view/next-project/src/pages/year_periods/index.tsx +++ b/view/next-project/src/pages/year_periods/index.tsx @@ -12,10 +12,10 @@ import { getCurrentUser } from '@/utils/api/currentUser'; import { get } from '@api/api_methods'; import { Card, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout/MainLayout'; -import { YearPeriods, User } from '@type/common'; +import { YearPeriod, User } from '@type/common'; interface Props { - yearPeriods: YearPeriods[]; + yearPeriods: YearPeriod[]; } export const getServerSideProps = async () => { @@ -36,15 +36,13 @@ export default function Periods(props: Props) { const auth = useRecoilValue(authAtom); const [currentUser, setCurrentUser] = useState<User>(); - const formatYearPeriods = - yearPeriods && - yearPeriods.map((yearPeriod) => { - return { - ...yearPeriod, - startedAt: yearPeriod.startedAt && new Date(yearPeriod.startedAt).toLocaleDateString('ja'), - endedAt: yearPeriod.endedAt && new Date(yearPeriod.endedAt).toLocaleDateString('ja'), - }; - }); + const formatYearPeriods = yearPeriods.map((yearPeriod) => { + return { + ...yearPeriod, + startedAt: new Date(yearPeriod.startedAt).toLocaleDateString('ja'), + endedAt: new Date(yearPeriod.endedAt).toLocaleDateString('ja'), + }; + }); useEffect(() => { const getUser = async () => { @@ -107,7 +105,7 @@ export default function Periods(props: Props) { </thead> <tbody className='border border-x-white-0 border-b-primary-1 border-t-white-0'> {formatYearPeriods && - formatYearPeriods.map((yearPeriod: YearPeriods, index) => ( + formatYearPeriods.map((yearPeriod: YearPeriod, index) => ( <tr key={yearPeriod.id}> <td className={clsx( From 2f29a6c71b8aa27d174ccac85925bca655872157 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Thu, 23 Nov 2023 23:14:21 +0900 Subject: [PATCH 29/54] =?UTF-8?q?[fix]=E3=83=AC=E3=82=B3=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=8C0=E3=81=AE=E5=A0=B4=E5=90=88=E3=81=AE=E5=87=A6?= =?UTF-8?q?=E7=90=86=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/year_periods/index.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/view/next-project/src/pages/year_periods/index.tsx b/view/next-project/src/pages/year_periods/index.tsx index d5f9d9653..e3379ae5b 100644 --- a/view/next-project/src/pages/year_periods/index.tsx +++ b/view/next-project/src/pages/year_periods/index.tsx @@ -36,13 +36,15 @@ export default function Periods(props: Props) { const auth = useRecoilValue(authAtom); const [currentUser, setCurrentUser] = useState<User>(); - const formatYearPeriods = yearPeriods.map((yearPeriod) => { - return { - ...yearPeriod, - startedAt: new Date(yearPeriod.startedAt).toLocaleDateString('ja'), - endedAt: new Date(yearPeriod.endedAt).toLocaleDateString('ja'), - }; - }); + const formatYearPeriods = + yearPeriods && + yearPeriods.map((yearPeriod) => { + return { + ...yearPeriod, + startedAt: new Date(yearPeriod.startedAt).toLocaleDateString('ja'), + endedAt: new Date(yearPeriod.endedAt).toLocaleDateString('ja'), + }; + }); useEffect(() => { const getUser = async () => { From ee39f86b603d4b383cecf4bd94bdf2a1be37edc9 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Thu, 23 Nov 2023 23:16:18 +0900 Subject: [PATCH 30/54] =?UTF-8?q?[fix]=E5=B9=B4=E5=BA=A6=E3=83=AC=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=81=8C=E3=81=AA=E3=81=84=E9=9A=9B=E3=81=AE?= =?UTF-8?q?=E3=82=A8=E3=83=B3=E3=83=89=E3=83=9D=E3=82=A4=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=82=92=E5=8B=95=E7=9A=84=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next-project/src/pages/purchaseorders/index.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/view/next-project/src/pages/purchaseorders/index.tsx b/view/next-project/src/pages/purchaseorders/index.tsx index a2e68a61d..8c8c54b59 100644 --- a/view/next-project/src/pages/purchaseorders/index.tsx +++ b/view/next-project/src/pages/purchaseorders/index.tsx @@ -20,22 +20,25 @@ import { User, PurchaseOrderView, Expense, - YearPeriods, + YearPeriod, } from '@type/common'; interface Props { user: User; purchaseOrderView: PurchaseOrderView[]; expenses: Expense[]; - yearPeriods: YearPeriods[]; + yearPeriods: YearPeriod[]; } + +const date = new Date(); + export async function getServerSideProps() { const getPeriodsUrl = process.env.SSR_API_URI + '/years/periods'; const periodsRes = await get(getPeriodsUrl); const getPurchaseOrderViewUrl = process.env.SSR_API_URI + '/purchaseorders/details/' + - String(periodsRes[periodsRes.length - 1].year); + (periodsRes ? String(periodsRes[periodsRes.length - 1].year) : String(date.getFullYear())); const getExpenseUrl = process.env.SSR_API_URI + '/expenses'; const purchaseOrderViewRes = await get(getPurchaseOrderViewUrl); const expenseRes = await get(getExpenseUrl); @@ -79,7 +82,7 @@ export default function PurchaseOrders(props: Props) { const yearPeriods = props.yearPeriods; const [selectedYear, setSelectedYear] = useState<string>( - yearPeriods ? String(yearPeriods[yearPeriods.length - 1].year) : '2024', + yearPeriods ? String(yearPeriods[yearPeriods.length - 1].year) : String(date.getFullYear()), ); const getPurchaseOrders = async () => { @@ -203,7 +206,7 @@ export default function PurchaseOrders(props: Props) { purchaseOrderViews, props.expenses, ), - fileName: `購入申請一覧(${selectedYear})_${formatYYYYMMDD(new Date())}.csv`, + fileName: `購入申請一覧(${selectedYear})_${formatYYYYMMDD(date)}.csv`, isBomAdded: true, }); }} From 8da8ebd6d37eaa71fb7d58014a3db8a0eecacaf9 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Thu, 23 Nov 2023 23:22:02 +0900 Subject: [PATCH 31/54] =?UTF-8?q?[fix]=E5=A4=89=E6=95=B0=E5=90=8D=E3=81=AE?= =?UTF-8?q?=E5=A4=89=E6=9B=B4=E3=81=A8=E3=83=87=E3=82=A3=E3=83=AC=E3=82=AF?= =?UTF-8?q?=E3=83=88=E3=83=AA=E5=90=8D=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/{year_periods => yearperiods}/AddModal.tsx | 8 ++++---- .../{year_periods => yearperiods}/DeleteModal.tsx | 4 ++-- .../{year_periods => yearperiods}/EditModal.tsx | 8 ++++---- .../{year_periods => yearperiods}/OpenAddModalButton.tsx | 0 .../OpenDeleteModalButton.tsx | 4 ++-- .../{year_periods => yearperiods}/OpenEditModalButton.tsx | 4 ++-- .../src/pages/{year_periods => yearperiods}/index.tsx | 6 +++--- view/next-project/src/type/common.ts | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) rename view/next-project/src/components/{year_periods => yearperiods}/AddModal.tsx (93%) rename view/next-project/src/components/{year_periods => yearperiods}/DeleteModal.tsx (95%) rename view/next-project/src/components/{year_periods => yearperiods}/EditModal.tsx (94%) rename view/next-project/src/components/{year_periods => yearperiods}/OpenAddModalButton.tsx (100%) rename view/next-project/src/components/{year_periods => yearperiods}/OpenDeleteModalButton.tsx (89%) rename view/next-project/src/components/{year_periods => yearperiods}/OpenEditModalButton.tsx (88%) rename view/next-project/src/pages/{year_periods => yearperiods}/index.tsx (96%) diff --git a/view/next-project/src/components/year_periods/AddModal.tsx b/view/next-project/src/components/yearperiods/AddModal.tsx similarity index 93% rename from view/next-project/src/components/year_periods/AddModal.tsx rename to view/next-project/src/components/yearperiods/AddModal.tsx index 0069e8440..31eed75e7 100644 --- a/view/next-project/src/components/year_periods/AddModal.tsx +++ b/view/next-project/src/components/yearperiods/AddModal.tsx @@ -5,7 +5,7 @@ import { useRecoilState } from 'recoil'; import { Modal, CloseButton, Input, PrimaryButton } from '../common'; import { userAtom } from '@/store/atoms'; -import { YearPeriods } from '@/type/common'; +import { YearPeriod } from '@/type/common'; import { post } from '@/utils/api/api_methods'; interface ModalProps { @@ -17,7 +17,7 @@ const OpenAddModal: FC<ModalProps> = (props) => { const router = useRouter(); - const [formData, setFormData] = useState<YearPeriods>({ + const [formData, setFormData] = useState<YearPeriod>({ year: 0, startedAt: '', endedAt: '', @@ -29,7 +29,7 @@ const OpenAddModal: FC<ModalProps> = (props) => { setFormData({ ...formData, [input]: e.target.value }); }; - const submit = async (data: YearPeriods) => { + const submit = async (data: YearPeriod) => { const startedAt = data.startedAt && new Date(data.startedAt); const endedAt = data.endedAt && new Date(data.endedAt); const formattedStartedAt = startedAt && format(startedAt, "yyyy-MM-dd'T'HH:mm:ss'Z'"); @@ -43,7 +43,7 @@ const OpenAddModal: FC<ModalProps> = (props) => { await addYearPeriod(submitData); }; - const addYearPeriod = async (data: YearPeriods) => { + const addYearPeriod = async (data: YearPeriod) => { const addPeriodUrl = process.env.CSR_API_URI + '/years/periods'; console.log(data); await post(addPeriodUrl, data); diff --git a/view/next-project/src/components/year_periods/DeleteModal.tsx b/view/next-project/src/components/yearperiods/DeleteModal.tsx similarity index 95% rename from view/next-project/src/components/year_periods/DeleteModal.tsx rename to view/next-project/src/components/yearperiods/DeleteModal.tsx index 4f83c8b4b..82e687287 100644 --- a/view/next-project/src/components/year_periods/DeleteModal.tsx +++ b/view/next-project/src/components/yearperiods/DeleteModal.tsx @@ -1,7 +1,7 @@ import { useRouter } from 'next/router'; import React, { Dispatch, FC, SetStateAction } from 'react'; -import { YearPeriods } from '@/type/common'; +import { YearPeriod } from '@/type/common'; import { del } from '@api/api_methods'; import { Modal, CloseButton, OutlinePrimaryButton, PrimaryButton } from '@components/common'; @@ -9,7 +9,7 @@ interface ModalProps { setShowModal: Dispatch<SetStateAction<boolean>>; children?: React.ReactNode; id: number | string; - yearPeriod: YearPeriods; + yearPeriod: YearPeriod; } const DeleteModal: FC<ModalProps> = (props) => { diff --git a/view/next-project/src/components/year_periods/EditModal.tsx b/view/next-project/src/components/yearperiods/EditModal.tsx similarity index 94% rename from view/next-project/src/components/year_periods/EditModal.tsx rename to view/next-project/src/components/yearperiods/EditModal.tsx index e5faa43dd..b56034768 100644 --- a/view/next-project/src/components/year_periods/EditModal.tsx +++ b/view/next-project/src/components/yearperiods/EditModal.tsx @@ -4,17 +4,17 @@ import { Dispatch, SetStateAction, useState } from 'react'; import { Modal, Input, CloseButton, PrimaryButton } from '../common'; import { put } from '@api/api_methods'; -import { YearPeriods } from '@type/common'; +import { YearPeriod } from '@type/common'; interface ModalProps { setShowModal: Dispatch<SetStateAction<boolean>>; - yearPeriod: YearPeriods; + yearPeriod: YearPeriod; } export default function EditModal(props: ModalProps) { const router = useRouter(); - const [formData, setFormData] = useState<YearPeriods>({ + const [formData, setFormData] = useState<YearPeriod>({ id: props.yearPeriod.id, year: props.yearPeriod.year, startedAt: props.yearPeriod.startedAt, @@ -32,7 +32,7 @@ export default function EditModal(props: ModalProps) { setFormData({ ...formData, [input]: e.target.value }); }; - const submitYearRecords = async (data: YearPeriods) => { + const submitYearRecords = async (data: YearPeriod) => { const submitYearRecordsURL = process.env.CSR_API_URI + '/years/periods/' + data.id; const startedAt = data.startedAt && new Date(data.startedAt); const endedAt = data.endedAt && new Date(data.endedAt); diff --git a/view/next-project/src/components/year_periods/OpenAddModalButton.tsx b/view/next-project/src/components/yearperiods/OpenAddModalButton.tsx similarity index 100% rename from view/next-project/src/components/year_periods/OpenAddModalButton.tsx rename to view/next-project/src/components/yearperiods/OpenAddModalButton.tsx diff --git a/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx b/view/next-project/src/components/yearperiods/OpenDeleteModalButton.tsx similarity index 89% rename from view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx rename to view/next-project/src/components/yearperiods/OpenDeleteModalButton.tsx index 8b8e4b064..e2cc67b16 100644 --- a/view/next-project/src/components/year_periods/OpenDeleteModalButton.tsx +++ b/view/next-project/src/components/yearperiods/OpenDeleteModalButton.tsx @@ -1,14 +1,14 @@ import React, { useState } from 'react'; import DeleteModal from './DeleteModal'; -import { YearPeriods } from '@/type/common'; +import { YearPeriod } from '@/type/common'; import { DeleteButton } from '@components/common'; interface Props { children?: React.ReactNode; id: number; isDisabled: boolean; - yearPeriod: YearPeriods; + yearPeriod: YearPeriod; } const OpenDeleteModalButton: React.FC<Props> = (props) => { diff --git a/view/next-project/src/components/year_periods/OpenEditModalButton.tsx b/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx similarity index 88% rename from view/next-project/src/components/year_periods/OpenEditModalButton.tsx rename to view/next-project/src/components/yearperiods/OpenEditModalButton.tsx index d89b4a344..ca09bbc95 100644 --- a/view/next-project/src/components/year_periods/OpenEditModalButton.tsx +++ b/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx @@ -2,10 +2,10 @@ import React, { useState } from 'react'; import EditModal from './EditModal'; import { EditButton } from '@components/common'; -import { YearPeriods } from '@type/common'; +import { YearPeriod } from '@type/common'; interface Props { - yearPeriod: YearPeriods; + yearPeriod: YearPeriod; isDisabled?: boolean; } diff --git a/view/next-project/src/pages/year_periods/index.tsx b/view/next-project/src/pages/yearperiods/index.tsx similarity index 96% rename from view/next-project/src/pages/year_periods/index.tsx rename to view/next-project/src/pages/yearperiods/index.tsx index e3379ae5b..43743f714 100644 --- a/view/next-project/src/pages/year_periods/index.tsx +++ b/view/next-project/src/pages/yearperiods/index.tsx @@ -4,9 +4,9 @@ import { useRouter } from 'next/router'; import { useEffect, useState, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; -import OpenAddModalButton from '@/components/year_periods/OpenAddModalButton'; -import OpenDeleteModalButton from '@/components/year_periods/OpenDeleteModalButton'; -import OpenEditModalButton from '@/components/year_periods/OpenEditModalButton'; +import OpenAddModalButton from '@/components/yearperiods/OpenAddModalButton'; +import OpenDeleteModalButton from '@/components/yearperiods/OpenDeleteModalButton'; +import OpenEditModalButton from '@/components/yearperiods/OpenEditModalButton'; import { authAtom } from '@/store/atoms'; import { getCurrentUser } from '@/utils/api/currentUser'; import { get } from '@api/api_methods'; diff --git a/view/next-project/src/type/common.ts b/view/next-project/src/type/common.ts index ba82cf406..aa0d215bc 100644 --- a/view/next-project/src/type/common.ts +++ b/view/next-project/src/type/common.ts @@ -235,7 +235,7 @@ export interface PurchaseReportView { // // Year(年度) export interface YearPeriod { - id: number; + id?: number; year: number; startedAt: string; endedAt: string; From cc2a241cfd4bc020594de9ee40e6d303125a974c Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Thu, 23 Nov 2023 23:23:38 +0900 Subject: [PATCH 32/54] =?UTF-8?q?[fix]=E3=82=BF=E3=82=A4=E3=83=9D=E3=83=9F?= =?UTF-8?q?=E3=82=B9=E4=BF=AE=E6=AD=A3=20=E5=8B=9F=E9=87=91=E2=86=92?= =?UTF-8?q?=E5=B9=B4=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/src/components/yearperiods/AddModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/next-project/src/components/yearperiods/AddModal.tsx b/view/next-project/src/components/yearperiods/AddModal.tsx index 31eed75e7..146a8d359 100644 --- a/view/next-project/src/components/yearperiods/AddModal.tsx +++ b/view/next-project/src/components/yearperiods/AddModal.tsx @@ -56,7 +56,7 @@ const OpenAddModal: FC<ModalProps> = (props) => { <CloseButton onClick={() => props.setShowModal(false)} /> </div> </div> - <h1 className='mx-auto mb-10 w-fit text-xl text-black-600'>募金の登録</h1> + <h1 className='mx-auto mb-10 w-fit text-xl text-black-600'>年度の登録</h1> <div className='my-6 grid grid-cols-5 items-center justify-items-center gap-4'> <p className='col-span-2 text-black-600'>年度</p> <div className='col-span-3 w-full'> From 69d779566c379698428acf2d977a330cb9f9b896 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Fri, 24 Nov 2023 00:04:45 +0900 Subject: [PATCH 33/54] =?UTF-8?q?[feat]=E7=99=BB=E9=8C=B2=E3=83=A2?= =?UTF-8?q?=E3=83=BC=E3=83=80=E3=83=AB=E3=81=AE=E7=99=BB=E9=8C=B2=E6=B8=88?= =?UTF-8?q?=E3=81=BF=E3=81=AE=E5=B9=B4=E5=BA=A6=E3=81=AE=E3=83=90=E3=83=AA?= =?UTF-8?q?=E3=83=87=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/yearperiods/AddModal.tsx | 16 +++++++++++----- .../yearperiods/OpenAddModalButton.tsx | 4 +++- .../next-project/src/pages/yearperiods/index.tsx | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/view/next-project/src/components/yearperiods/AddModal.tsx b/view/next-project/src/components/yearperiods/AddModal.tsx index 146a8d359..9e67841f2 100644 --- a/view/next-project/src/components/yearperiods/AddModal.tsx +++ b/view/next-project/src/components/yearperiods/AddModal.tsx @@ -10,10 +10,12 @@ import { post } from '@/utils/api/api_methods'; interface ModalProps { setShowModal: Dispatch<SetStateAction<boolean>>; + yearPeriods?: YearPeriod[]; } const OpenAddModal: FC<ModalProps> = (props) => { const [user] = useRecoilState(userAtom); + const [flashMessage, setFlashMessage] = useState<string>(''); const router = useRouter(); @@ -40,13 +42,18 @@ const OpenAddModal: FC<ModalProps> = (props) => { startedAt: formattedStartedAt, endedAt: formattedEndedAt, }; - await addYearPeriod(submitData); + props.yearPeriods + ? props.yearPeriods.some((yearPeriod) => yearPeriod.year === Number(formData.year)) + ? setFlashMessage('既に年度が登録されています') + : await addYearPeriod(submitData) + : await addYearPeriod(submitData); }; const addYearPeriod = async (data: YearPeriod) => { const addPeriodUrl = process.env.CSR_API_URI + '/years/periods'; - console.log(data); await post(addPeriodUrl, data); + props.setShowModal(false); + router.reload(); }; return ( @@ -59,8 +66,9 @@ const OpenAddModal: FC<ModalProps> = (props) => { <h1 className='mx-auto mb-10 w-fit text-xl text-black-600'>年度の登録</h1> <div className='my-6 grid grid-cols-5 items-center justify-items-center gap-4'> <p className='col-span-2 text-black-600'>年度</p> - <div className='col-span-3 w-full'> + <div className='col-span-3 h-12 w-full'> <Input className='w-full' onChange={handler('year')} placeholder='20XX' type='number' /> + <p className='text-xs text-red-500'>{flashMessage}</p> </div> <p className='col-span-2 text-black-600'>開始日</p> <div className='col-span-3 w-full'> @@ -76,8 +84,6 @@ const OpenAddModal: FC<ModalProps> = (props) => { className={'mx-2'} onClick={() => { submit(formData); - props.setShowModal(false); - router.reload(); }} > 登録する diff --git a/view/next-project/src/components/yearperiods/OpenAddModalButton.tsx b/view/next-project/src/components/yearperiods/OpenAddModalButton.tsx index d9a3e8545..5c39ae429 100644 --- a/view/next-project/src/components/yearperiods/OpenAddModalButton.tsx +++ b/view/next-project/src/components/yearperiods/OpenAddModalButton.tsx @@ -1,10 +1,12 @@ import React, { useState } from 'react'; import OpenAddModal from './AddModal'; +import { YearPeriod } from '@/type/common'; import { AddButton } from '@components/common'; interface Props { children?: React.ReactNode; + yearPeriods?: YearPeriod[]; } export const OpenAddModalButton = (props: Props) => { @@ -19,7 +21,7 @@ export const OpenAddModalButton = (props: Props) => { > {props.children} </AddButton> - {isOpen && <OpenAddModal setShowModal={setIsOpen} />} + {isOpen && <OpenAddModal setShowModal={setIsOpen} yearPeriods={props.yearPeriods} />} </> ); }; diff --git a/view/next-project/src/pages/yearperiods/index.tsx b/view/next-project/src/pages/yearperiods/index.tsx index 43743f714..26f9e13df 100644 --- a/view/next-project/src/pages/yearperiods/index.tsx +++ b/view/next-project/src/pages/yearperiods/index.tsx @@ -84,7 +84,7 @@ export default function Periods(props: Props) { </div> </div> <div className='hidden justify-end md:flex '> - <OpenAddModalButton>年度登録</OpenAddModalButton> + <OpenAddModalButton yearPeriods={props.yearPeriods}>年度登録</OpenAddModalButton> </div> <div className='mb-2 p-5'> <table className='mb-5 w-full table-auto border-collapse'> From 3e309a6afa9397ff18b7c9d9625a84e5c1da85a8 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Fri, 24 Nov 2023 00:20:27 +0900 Subject: [PATCH 34/54] =?UTF-8?q?[fix]=E7=B7=A8=E9=9B=86=E3=83=A2=E3=83=BC?= =?UTF-8?q?=E3=83=80=E3=83=AB=E3=82=82=E5=B9=B4=E5=BA=A6=E3=81=AE=E3=83=90?= =?UTF-8?q?=E3=83=AA=E3=83=87=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/yearperiods/EditModal.tsx | 26 ++++++++++++++----- .../yearperiods/OpenEditModalButton.tsx | 3 ++- .../src/pages/yearperiods/index.tsx | 2 +- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/view/next-project/src/components/yearperiods/EditModal.tsx b/view/next-project/src/components/yearperiods/EditModal.tsx index b56034768..f6d285208 100644 --- a/view/next-project/src/components/yearperiods/EditModal.tsx +++ b/view/next-project/src/components/yearperiods/EditModal.tsx @@ -9,10 +9,12 @@ import { YearPeriod } from '@type/common'; interface ModalProps { setShowModal: Dispatch<SetStateAction<boolean>>; yearPeriod: YearPeriod; + yearPeriods: YearPeriod[]; } export default function EditModal(props: ModalProps) { const router = useRouter(); + const [flashMessage, setFlashMessage] = useState<string>(''); const [formData, setFormData] = useState<YearPeriod>({ id: props.yearPeriod.id, @@ -32,8 +34,11 @@ export default function EditModal(props: ModalProps) { setFormData({ ...formData, [input]: e.target.value }); }; + const filterYearRecords = props.yearPeriods.filter((yearPeriodData) => { + return yearPeriodData.id !== props.yearPeriod.id; + }); + const submitYearRecords = async (data: YearPeriod) => { - const submitYearRecordsURL = process.env.CSR_API_URI + '/years/periods/' + data.id; const startedAt = data.startedAt && new Date(data.startedAt); const endedAt = data.endedAt && new Date(data.endedAt); const formattedStartedAt = startedAt && format(startedAt, "yyyy-MM-dd'T'HH:mm:ss'Z'"); @@ -44,9 +49,17 @@ export default function EditModal(props: ModalProps) { startedAt: formattedStartedAt, endedAt: formattedEndedAt, }; - console.log(data); - console.log(submitData); - await put(submitYearRecordsURL, submitData); + + filterYearRecords.some((yearPeriod) => yearPeriod.year === Number(formData.year)) + ? setFlashMessage('既に年度が登録されています') + : await editYearPeriod(submitData); + }; + + const editYearPeriod = async (data: YearPeriod) => { + const submitYearRecordsURL = process.env.CSR_API_URI + '/years/periods/' + data.id; + await put(submitYearRecordsURL, data); + props.setShowModal(false); + router.reload(); }; return ( @@ -59,13 +72,14 @@ export default function EditModal(props: ModalProps) { <h1 className='mx-auto mb-10 w-fit text-xl text-black-600'>年度の編集</h1> <div className='my-6 grid grid-cols-5 items-center justify-items-center gap-4'> <p className='col-span-1 text-black-600'>年度</p> - <div className='col-span-4 w-full'> + <div className='col-span-4 h-12 w-full'> <Input className='w-full' onChange={handler('year')} value={formData.year} type='number' /> + <p className='text-xs text-red-500'>{flashMessage}</p> </div> <p className='col-span-1 text-black-600'>開始日</p> <div className='col-span-4 w-full'> @@ -91,8 +105,6 @@ export default function EditModal(props: ModalProps) { className={'mx-2'} onClick={() => { submitYearRecords(formData); - props.setShowModal(false); - router.reload(); }} > 登録する diff --git a/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx b/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx index ca09bbc95..20b2223d3 100644 --- a/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx +++ b/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx @@ -7,6 +7,7 @@ import { YearPeriod } from '@type/common'; interface Props { yearPeriod: YearPeriod; isDisabled?: boolean; + yearPeriods: YearPeriod[]; } export const OpenEditModalButton = (props: Props) => { @@ -20,7 +21,7 @@ export const OpenEditModalButton = (props: Props) => { }} isDisabled={props.isDisabled} /> - {isOpen && <EditModal setShowModal={setIsOpen} yearPeriod={props.yearPeriod} />} + {isOpen && <EditModal setShowModal={setIsOpen} yearPeriod={props.yearPeriod} yearPeriods={props.yearPeriods}/>} </> ); }; diff --git a/view/next-project/src/pages/yearperiods/index.tsx b/view/next-project/src/pages/yearperiods/index.tsx index 26f9e13df..fa21915dd 100644 --- a/view/next-project/src/pages/yearperiods/index.tsx +++ b/view/next-project/src/pages/yearperiods/index.tsx @@ -153,7 +153,7 @@ export default function Periods(props: Props) { )} > <div className='flex gap-2'> - <OpenEditModalButton yearPeriod={yearPeriod} /> + <OpenEditModalButton yearPeriod={yearPeriod} yearPeriods={yearPeriods} /> <OpenDeleteModalButton id={yearPeriod.id || 0} isDisabled={false} From 2320679b98ff76d039b21e9dfcba6492a96c6879 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Fri, 24 Nov 2023 00:35:52 +0900 Subject: [PATCH 35/54] =?UTF-8?q?[feat]=E7=99=BB=E9=8C=B2=E3=83=BB?= =?UTF-8?q?=E7=B7=A8=E9=9B=86=E3=83=A2=E3=83=BC=E3=83=80=E3=83=AB=20?= =?UTF-8?q?=E3=83=90=E3=83=AA=E3=83=87=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/src/components/yearperiods/AddModal.tsx | 3 +++ view/next-project/src/components/yearperiods/EditModal.tsx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/view/next-project/src/components/yearperiods/AddModal.tsx b/view/next-project/src/components/yearperiods/AddModal.tsx index 9e67841f2..827e2afa1 100644 --- a/view/next-project/src/components/yearperiods/AddModal.tsx +++ b/view/next-project/src/components/yearperiods/AddModal.tsx @@ -85,6 +85,9 @@ const OpenAddModal: FC<ModalProps> = (props) => { onClick={() => { submit(formData); }} + disabled={ + String(formData.year) === '' || formData.startedAt === '' || formData.endedAt === '' + } > 登録する </PrimaryButton> diff --git a/view/next-project/src/components/yearperiods/EditModal.tsx b/view/next-project/src/components/yearperiods/EditModal.tsx index f6d285208..921083f20 100644 --- a/view/next-project/src/components/yearperiods/EditModal.tsx +++ b/view/next-project/src/components/yearperiods/EditModal.tsx @@ -106,6 +106,9 @@ export default function EditModal(props: ModalProps) { onClick={() => { submitYearRecords(formData); }} + disabled={ + String(formData.year) === '' || formData.startedAt === '' || formData.endedAt === '' + } > 登録する </PrimaryButton> From 347d6056d0167c49129e433b30188dfc85b31461 Mon Sep 17 00:00:00 2001 From: Kubosaka <Kubosaka@users.noreply.github.com> Date: Thu, 23 Nov 2023 15:39:00 +0000 Subject: [PATCH 36/54] formatted by workflow --- .../src/components/yearperiods/OpenEditModalButton.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx b/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx index 20b2223d3..5aec9fc81 100644 --- a/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx +++ b/view/next-project/src/components/yearperiods/OpenEditModalButton.tsx @@ -21,7 +21,13 @@ export const OpenEditModalButton = (props: Props) => { }} isDisabled={props.isDisabled} /> - {isOpen && <EditModal setShowModal={setIsOpen} yearPeriod={props.yearPeriod} yearPeriods={props.yearPeriods}/>} + {isOpen && ( + <EditModal + setShowModal={setIsOpen} + yearPeriod={props.yearPeriod} + yearPeriods={props.yearPeriods} + /> + )} </> ); }; From 22d1d3402417dabc0df24336f7e14f6234cce25d Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Mon, 11 Dec 2023 18:50:31 +0000 Subject: [PATCH 37/54] [feat] add item validation --- .../src/components/purchasereports/PurchaseReportAddModal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx b/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx index bc5700ee5..d50557fc7 100644 --- a/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx +++ b/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx @@ -336,6 +336,7 @@ export default function PurchaseReportAddModal(props: ModalProps) { } isFinanceCheckHandler(formDataList[activeStep - 1].id, true); }} + disabled={formDataList[activeStep - 1].item.trim() === ''} > <div className='flex'> {activeStep === steps.length From c43d4c64c1a933859bfc40f0ff121a1365745e7f Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Tue, 12 Dec 2023 20:30:10 +0900 Subject: [PATCH 38/54] =?UTF-8?q?[feat]=E8=B3=BC=E5=85=A5=E5=A0=B1?= =?UTF-8?q?=E5=91=8A=E3=81=AE=E5=B9=B4=E5=BA=A6=E5=8F=96=E5=BE=97api?= =?UTF-8?q?=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/docs/docs.go | 20 ++++++ .../controller/purchase_report_controller.go | 10 +++ .../repository/purchase_report_repository.go | 69 ++++++++++++++++++ .../usecase/purchase_report_usecase.go | 71 +++++++++++++++++++ api/router/router.go | 1 + 5 files changed, 171 insertions(+) diff --git a/api/docs/docs.go b/api/docs/docs.go index 872d77019..deac96a02 100644 --- a/api/docs/docs.go +++ b/api/docs/docs.go @@ -1363,6 +1363,26 @@ const docTemplate = `{ } }, }, + "/purchasereports/details/{year}": { + "get": { + tags: ["purchase_report"], + "description": "年度で指定されたpurchase_reportsに紐づくデータを取得", + "parameters": [ + { + "name": "year", + "in": "path", + "description": "year", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "年度で指定されたpurchase_reportsに紐づくデータを取得", + } + } + }, + }, "/sources": { "get": { tags: ["source"], diff --git a/api/externals/controller/purchase_report_controller.go b/api/externals/controller/purchase_report_controller.go index 21d19eb4e..7fe8ec52d 100644 --- a/api/externals/controller/purchase_report_controller.go +++ b/api/externals/controller/purchase_report_controller.go @@ -21,6 +21,7 @@ type PurchaseReportController interface { DestroyPurchaseReport(echo.Context) error IndexPurchaseReportDetails(echo.Context) error ShowPurchaseReportDetail(echo.Context) error + IndexPurchaseReportDetailsByYear(echo.Context) error } func NewPurchaseReportController(u usecase.PurchaseReportUseCase) PurchaseReportController { @@ -99,3 +100,12 @@ func (p *purchaseReportController) ShowPurchaseReportDetail(c echo.Context) erro } return c.JSON(http.StatusOK, purchaseReportDetail) } + +func (p *purchaseReportController) IndexPurchaseReportDetailsByYear(c echo.Context) error { + year := c.Param("year") + purchaseReportDetails, err := p.u.GetPurchaseReportDetailsByYear(c.Request().Context(), year) + if err != nil { + return err + } + return c.JSON(http.StatusOK, purchaseReportDetails) +} diff --git a/api/externals/repository/purchase_report_repository.go b/api/externals/repository/purchase_report_repository.go index e683f42fa..9b73562cf 100644 --- a/api/externals/repository/purchase_report_repository.go +++ b/api/externals/repository/purchase_report_repository.go @@ -23,6 +23,7 @@ type PurchaseReportRepository interface { FindDetail(context.Context, string) (*sql.Row, error) AllItemInfo(context.Context, string) (*sql.Rows, error) FindNewRecord(context.Context) (*sql.Row, error) + AllDetailsForPeriods(context.Context, string) (*sql.Rows, error) } func NewPurchaseReportRepository(c db.Client, ac abstract.Crud) PurchaseReportRepository { @@ -159,3 +160,71 @@ func (ppr *purchaseReportRepository) FindNewRecord(c context.Context) (*sql.Row, query := "SELECT * FROM purchase_reports ORDER BY id DESC LIMIT 1" return ppr.crud.ReadByID(c, query) } + + +// Purchase_reportに紐づく、Purchase_orderからPurchase_itemsの取得 +func (ppr *purchaseReportRepository) AllDetailsForPeriods(c context.Context, year string) (*sql.Rows, error) { + query := ` + SELECT + purchase_reports.id, + purchase_reports.user_id, + purchase_reports.discount, + purchase_reports.addition, + purchase_reports.finance_check, + purchase_reports.purchase_order_id, + purchase_reports.remark, + purchase_reports.buyer, + purchase_reports.created_at, + purchase_reports.updated_at, + report_user.id, + report_user.name, + report_user.bureau_id, + report_user.role_id, + report_user.created_at, + report_user.updated_at, + purchase_orders.id, + purchase_orders.deadline, + purchase_orders.user_id, + purchase_orders.expense_id, + purchase_orders.finance_check, + purchase_orders.created_at, + purchase_orders.updated_at, + order_user.id, + order_user.name, + order_user.bureau_id, + order_user.role_id, + order_user.created_at, + order_user.updated_at + FROM + purchase_reports + INNER JOIN + users + AS + report_user + ON + purchase_reports.user_id = report_user.id + INNER JOIN + purchase_orders + ON + purchase_reports.purchase_order_id = purchase_orders.id + INNER JOIN + users + AS + order_user + ON + purchase_orders.user_id = order_user.id + INNER JOIN + year_periods + ON + purchase_reports.created_at > year_periods.started_at + AND + purchase_reports.created_at < year_periods.ended_at + INNER JOIN + years + ON + year_periods.year_id = years.id + WHERE + years.year = ` + year + + " ORDER BY purchase_reports.id" + return ppr.crud.Read(c, query) +} diff --git a/api/internals/usecase/purchase_report_usecase.go b/api/internals/usecase/purchase_report_usecase.go index 98238ccff..7ac2b7dd2 100644 --- a/api/internals/usecase/purchase_report_usecase.go +++ b/api/internals/usecase/purchase_report_usecase.go @@ -20,6 +20,7 @@ type PurchaseReportUseCase interface { DestroyPurchaseReport(context.Context, string) error GetPurchaseReportDetails(context.Context) ([]domain.PurchaseReportDetails, error) GetPurchaseReportDetailByID(context.Context, string) (domain.PurchaseReportDetails, error) + GetPurchaseReportDetailsByYear(context.Context, string) ([]domain.PurchaseReportDetails, error) } func NewPurchaseReportUseCase(rep rep.PurchaseReportRepository) PurchaseReportUseCase { @@ -285,3 +286,73 @@ func (p *purchaseReportUseCase) GetPurchaseReportDetailByID(c context.Context, i return purchaseReportDetail, nil } +//Purchase_reportに紐づく、Purchase_orderからPurchase_itemsの取得(GETS) +func (p *purchaseReportUseCase) GetPurchaseReportDetailsByYear(c context.Context, year string) ([]domain.PurchaseReportDetails, error) { + purchaseReportDetail:= domain.PurchaseReportDetails{} + var purchaseReportDetails []domain.PurchaseReportDetails + purchaseItem := domain.PurchaseItem{} + var purchaseItems []domain.PurchaseItem + rows, err := p.rep.AllDetailsForPeriods(c, year) + if err != nil { + return nil, err + } + for rows.Next() { + err := rows.Scan( + &purchaseReportDetail.PurchaseReport.ID, + &purchaseReportDetail.PurchaseReport.UserID, + &purchaseReportDetail.PurchaseReport.Discount, + &purchaseReportDetail.PurchaseReport.Addition, + &purchaseReportDetail.PurchaseReport.FinanceCheck, + &purchaseReportDetail.PurchaseReport.PurchaseOrderID, + &purchaseReportDetail.PurchaseReport.Remark, + &purchaseReportDetail.PurchaseReport.Buyer, + &purchaseReportDetail.PurchaseReport.CreatedAt, + &purchaseReportDetail.PurchaseReport.UpdatedAt, + &purchaseReportDetail.ReportUser.ID, + &purchaseReportDetail.ReportUser.Name, + &purchaseReportDetail.ReportUser.BureauID, + &purchaseReportDetail.ReportUser.RoleID, + &purchaseReportDetail.ReportUser.CreatedAt, + &purchaseReportDetail.ReportUser.UpdatedAt, + &purchaseReportDetail.PurchaseOrder.ID, + &purchaseReportDetail.PurchaseOrder.DeadLine, + &purchaseReportDetail.PurchaseOrder.UserID, + &purchaseReportDetail.PurchaseOrder.ExpenseID, + &purchaseReportDetail.PurchaseOrder.FinanceCheck, + &purchaseReportDetail.PurchaseOrder.CreatedAt, + &purchaseReportDetail.PurchaseOrder.UpdatedAt, + &purchaseReportDetail.OrderUser.ID, + &purchaseReportDetail.OrderUser.Name, + &purchaseReportDetail.OrderUser.BureauID, + &purchaseReportDetail.OrderUser.RoleID, + &purchaseReportDetail.OrderUser.CreatedAt, + &purchaseReportDetail.OrderUser.UpdatedAt, + ) + if err != nil { + return nil, err + } + rows, err := p.rep.AllItemInfo(c, strconv.Itoa(int(purchaseReportDetail.PurchaseReport.PurchaseOrderID))) + for rows.Next() { + err := rows.Scan( + &purchaseItem.ID, + &purchaseItem.Item, + &purchaseItem.Price, + &purchaseItem.Quantity, + &purchaseItem.Detail, + &purchaseItem.Url, + &purchaseItem.PurchaseOrderID, + &purchaseItem.FinanceCheck, + &purchaseItem.CreatedAt, + &purchaseItem.UpdatedAt, + ) + if err != nil { + return nil, err + } + purchaseItems = append(purchaseItems, purchaseItem) + } + purchaseReportDetail.PurchaseItems = purchaseItems + purchaseReportDetails = append(purchaseReportDetails, purchaseReportDetail) + purchaseItems = nil + } + return purchaseReportDetails, nil +} diff --git a/api/router/router.go b/api/router/router.go index c85dfb9a6..feacb5514 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -169,6 +169,7 @@ func (r router) ProvideRouter(e *echo.Echo) { e.DELETE("/purchasereports/:id", r.purchaseReportController.DestroyPurchaseReport) e.GET("/purchasereports/details", r.purchaseReportController.IndexPurchaseReportDetails) e.GET("/purchasereports/:id/details", r.purchaseReportController.ShowPurchaseReportDetail) + e.GET("/purchasereports/details/:year", r.purchaseReportController.IndexPurchaseReportDetailsByYear) // sources e.GET("/sources", r.sourceController.IndexSource) From b9bd49a64dc2bb05ea1d2286558702a2193c9ec6 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Tue, 23 Jan 2024 12:44:39 +0000 Subject: [PATCH 39/54] =?UTF-8?q?[feat]=20=E5=B9=B4=E5=BA=A6=E5=88=A5?= =?UTF-8?q?=E3=81=AEfund=5Finformations=E3=82=92=E5=8F=96=E5=BE=97?= =?UTF-8?q?=E3=81=99=E3=82=8BAPI=E3=81=AE=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/docs/docs.go | 20 +++++++ .../controller/fund_information_controller.go | 11 ++++ .../repository/fund_information_repository.go | 43 ++++++++++++++- .../usecase/fund_information_usecase.go | 53 +++++++++++++++++++ api/router/router.go | 1 + 5 files changed, 126 insertions(+), 2 deletions(-) diff --git a/api/docs/docs.go b/api/docs/docs.go index 872d77019..1a04fa47a 100644 --- a/api/docs/docs.go +++ b/api/docs/docs.go @@ -870,6 +870,26 @@ const docTemplate = `{ } }, }, + "/fund_informations/details/{year}": { + "get": { + tags: ["fund_information"], + "description": "年度で指定されたfund_informationsに紐づくデータを取得", + "parameters": [ + { + "name": "year", + "in": "path", + "description": "year", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "年度で指定されたfund_informationsに紐づくデータを取得", + } + } + }, + }, "/purchaseitems": { "get": { tags: ["purchase_item"], diff --git a/api/externals/controller/fund_information_controller.go b/api/externals/controller/fund_information_controller.go index eb7b91add..21ca7523d 100644 --- a/api/externals/controller/fund_information_controller.go +++ b/api/externals/controller/fund_information_controller.go @@ -19,6 +19,7 @@ type FundInformationController interface { DestroyFundInformation(echo.Context) error IndexFundInformationDetails(echo.Context) error ShowFundInformationDetailByID(echo.Context) error + IndexFundInformationDetailsByYear(echo.Context) error } func NewFundInformationController(u usecase.FundInformationUseCase) FundInformationController { @@ -106,3 +107,13 @@ func (f *fundInformationController) ShowFundInformationDetailByID(c echo.Context } return c.JSON(http.StatusOK, fundinforuserandteacher) } + +// IndexFundInformationDetailsByYear +func (f *fundInformationController) IndexFundInformationDetailsByYear(c echo.Context) error { + year := c.Param("year") + fundInformationDetailsByYear, err := f.u.GetFundInformationDetailsByYear(c.Request().Context(), year) + if err != nil { + return err + } + return c.JSON(http.StatusOK, fundInformationDetailsByYear) +} diff --git a/api/externals/repository/fund_information_repository.go b/api/externals/repository/fund_information_repository.go index 31ffa7b70..620bf6d57 100644 --- a/api/externals/repository/fund_information_repository.go +++ b/api/externals/repository/fund_information_repository.go @@ -22,6 +22,7 @@ type FundInformationRepository interface { FindDetails(context.Context) (*sql.Rows, error) FindDetailByID(context.Context, string) (*sql.Row, error) FindLatestRecord(context.Context) (*sql.Row, error) + AllDetailsForPeriods(context.Context, string) (*sql.Rows, error) } func NewFundInformationRepository(c db.Client, ac abstract.Crud) FundInformationRepository { @@ -66,7 +67,7 @@ func (fir *fundInformationRepository) Create( "," + price + ",'" + remark + "'," + isFirstCheck + - "," + isLastCheck + + "," + isLastCheck + "," + receivedAt + ")" return fir.crud.UpdateDB(c, query) } @@ -93,7 +94,7 @@ func (fir *fundInformationRepository) Update( ", remark ='" + remark + "', is_first_check = " + isFirstCheck + ", is_last_check = " + isLastCheck + - ", received_at = " + receivedAt + + ", received_at = " + receivedAt + " WHERE id = " + id return fir.crud.UpdateDB(c, query) } @@ -162,3 +163,41 @@ func (fir *fundInformationRepository) FindLatestRecord(c context.Context) (*sql. ` return fir.crud.ReadByID(c, query) } + +// 年度別のfund_informationに紐づくuserとteacherを取得する +func (fir *fundInformationRepository) AllDetailsForPeriods(c context.Context, year string) (*sql.Rows, error) { + query := ` + SELECT + fund_informations.*, + users.*, + teachers.*, + departments.* + FROM + fund_informations + INNER JOIN + users + ON + fund_informations.user_id = users.id + INNER JOIN + teachers + ON + fund_informations.teacher_id = teachers.id + INNER JOIN + departments + ON + teachers.department_id = departments.id + INNER JOIN + year_periods + ON + fund_informations.created_at > year_periods.started_at + AND + fund_informations.created_at < year_periods.ended_at + INNER JOIN + years + ON + year_periods.year_id = years.id + WHERE + years.year = ` + year + + " ORDER BY fund_informations.id;" + return fir.crud.Read(c, query) +} diff --git a/api/internals/usecase/fund_information_usecase.go b/api/internals/usecase/fund_information_usecase.go index bb7fc2756..086dcfff1 100644 --- a/api/internals/usecase/fund_information_usecase.go +++ b/api/internals/usecase/fund_information_usecase.go @@ -19,6 +19,7 @@ type FundInformationUseCase interface { DestroyFundInformation(context.Context, string) error GetFundInformationDetails(context.Context) ([]domain.FundInformationDetail, error) GetFundInformationDetailByID(context.Context, string) (domain.FundInformationDetail, error) + GetFundInformationDetailsByYear(context.Context, string) ([]domain.FundInformationDetail, error) } func NewFundInformationUseCase(rep rep.FundInformationRepository) FundInformationUseCase { @@ -194,6 +195,7 @@ func (f *fundInformationUseCase) GetFundInformationDetails(c context.Context) ([ return nil, err } fundInformationDetails = append(fundInformationDetails, fundInformationDetail) + } return fundInformationDetails, nil } @@ -240,3 +242,54 @@ func (f *fundInformationUseCase) GetFundInformationDetailByID(c context.Context, } return fundInformationDetail, nil } + +//fund_informations_byyear-api(GETS) +func (f *fundInformationUseCase) GetFundInformationDetailsByYear(c context.Context, year string) ([]domain.FundInformationDetail, error) { + fundInformationDetail:= domain.FundInformationDetail{} + var fundInformationDetails []domain.FundInformationDetail + + rows, err := f.rep.AllDetailsForPeriods(c, year) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + err := rows.Scan( + &fundInformationDetail.FundInformation.ID, + &fundInformationDetail.FundInformation.UserID, + &fundInformationDetail.FundInformation.TeacherID, + &fundInformationDetail.FundInformation.Price, + &fundInformationDetail.FundInformation.Remark, + &fundInformationDetail.FundInformation.IsFirstCheck, + &fundInformationDetail.FundInformation.IsLastCheck, + &fundInformationDetail.FundInformation.ReceivedAt, + &fundInformationDetail.FundInformation.CreatedAt, + &fundInformationDetail.FundInformation.UpdatedAt, + &fundInformationDetail.User.ID, + &fundInformationDetail.User.Name, + &fundInformationDetail.User.BureauID, + &fundInformationDetail.User.RoleID, + &fundInformationDetail.User.CreatedAt, + &fundInformationDetail.User.UpdatedAt, + &fundInformationDetail.Teacher.ID, + &fundInformationDetail.Teacher.Name, + &fundInformationDetail.Teacher.Position, + &fundInformationDetail.Teacher.DepartmentID, + &fundInformationDetail.Teacher.Room, + &fundInformationDetail.Teacher.IsBlack, + &fundInformationDetail.Teacher.Remark, + &fundInformationDetail.Teacher.CreatedAt, + &fundInformationDetail.Teacher.UpdatedAt, + &fundInformationDetail.Department.ID, + &fundInformationDetail.Department.Name, + &fundInformationDetail.Department.CreatedAt, + &fundInformationDetail.Department.UpdatedAt, + ) + if err != nil { + return nil, err + } + fundInformationDetails = append(fundInformationDetails, fundInformationDetail) + } + return fundInformationDetails, nil +} diff --git a/api/router/router.go b/api/router/router.go index c85dfb9a6..efe683c3b 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -135,6 +135,7 @@ func (r router) ProvideRouter(e *echo.Echo) { e.DELETE("/fund_informations/:id", r.fundInformationController.DestroyFundInformation) e.GET("/fund_informations/details", r.fundInformationController.IndexFundInformationDetails) e.GET("/fund_informations/:id/details", r.fundInformationController.ShowFundInformationDetailByID) + e.GET("/fund_informations/details/:year", r.fundInformationController.IndexFundInformationDetailsByYear) // mail auth e.POST("/mail_auth/signup", r.mailAuthController.SignUp) From 91e8ac42b86dbf588161b2ea29035dc1682362e8 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sun, 28 Jan 2024 17:23:11 +0900 Subject: [PATCH 40/54] =?UTF-8?q?[fix]=E3=82=AF=E3=82=A8=E3=83=AA=E3=82=92?= =?UTF-8?q?=E7=9F=AD=E7=B8=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/purchase_report_repository.go | 33 +++---------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/api/externals/repository/purchase_report_repository.go b/api/externals/repository/purchase_report_repository.go index 9b73562cf..11ad10046 100644 --- a/api/externals/repository/purchase_report_repository.go +++ b/api/externals/repository/purchase_report_repository.go @@ -166,35 +166,10 @@ func (ppr *purchaseReportRepository) FindNewRecord(c context.Context) (*sql.Row, func (ppr *purchaseReportRepository) AllDetailsForPeriods(c context.Context, year string) (*sql.Rows, error) { query := ` SELECT - purchase_reports.id, - purchase_reports.user_id, - purchase_reports.discount, - purchase_reports.addition, - purchase_reports.finance_check, - purchase_reports.purchase_order_id, - purchase_reports.remark, - purchase_reports.buyer, - purchase_reports.created_at, - purchase_reports.updated_at, - report_user.id, - report_user.name, - report_user.bureau_id, - report_user.role_id, - report_user.created_at, - report_user.updated_at, - purchase_orders.id, - purchase_orders.deadline, - purchase_orders.user_id, - purchase_orders.expense_id, - purchase_orders.finance_check, - purchase_orders.created_at, - purchase_orders.updated_at, - order_user.id, - order_user.name, - order_user.bureau_id, - order_user.role_id, - order_user.created_at, - order_user.updated_at + purchase_reports.*, + report_user.*, + purchase_orders.*, + order_user.* FROM purchase_reports INNER JOIN From da7cc2ea682b1a92283cc3b6055c65fd83e3d970 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Sun, 28 Jan 2024 18:24:48 +0900 Subject: [PATCH 41/54] =?UTF-8?q?[=E6=94=AF=E5=87=BA]=E5=B9=B4=E5=BA=A6?= =?UTF-8?q?=E5=88=A5=E5=8F=96=E5=BE=97API=E3=81=AE=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/docs/docs.go | 20 +++++ .../controller/expense_controller.go | 14 ++++ .../repository/expense_repository.go | 17 ++++ api/internals/domain/expense.go | 6 ++ api/internals/usecase/expense_usecase.go | 83 +++++++++++++++++++ api/router/router.go | 1 + 6 files changed, 141 insertions(+) diff --git a/api/docs/docs.go b/api/docs/docs.go index deac96a02..158ced16e 100644 --- a/api/docs/docs.go +++ b/api/docs/docs.go @@ -671,6 +671,26 @@ const docTemplate = `{ } }, }, + "/expenses/details/{year}": { + "get": { + tags: ["expense"], + "description": "年度で指定されたexpenseに紐づく購入申請と購入報告を取得", + "parameters": [ + { + "name": "year", + "in": "path", + "description": "year", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "yearで指定されたexpenseに紐づく購入申請と購入報告を取得", + } + } + }, + }, "/fund_informations": { "get": { tags: ["fund_information"], diff --git a/api/externals/controller/expense_controller.go b/api/externals/controller/expense_controller.go index a0e51b73b..5fa2e0138 100644 --- a/api/externals/controller/expense_controller.go +++ b/api/externals/controller/expense_controller.go @@ -20,6 +20,7 @@ type ExpenseController interface { UpdateExpenseTP(echo.Context) error IndexExpenseDetails(echo.Context) error ShowExpenseDetail(echo.Context) error + IndexExpenseDetailsByPeriod(echo.Context) error } func NewExpenseController(u usecase.ExpenseUseCase) ExpenseController { @@ -105,3 +106,16 @@ func (e *expenseController) ShowExpenseDetail(c echo.Context) error { } return c.JSON(http.StatusOK, expenseDetail) } + +func (e *expenseController) IndexExpenseDetailsByPeriod(c echo.Context) error { + year := c.Param("year") + err := e.u.UpdateExpenseTP(c.Request().Context()) + if err != nil { + return err + } + expenseDetails, err := e.u.GetExpenseDetailsByPeriod(c.Request().Context(), year) + if err != nil { + return err + } + return c.JSON(http.StatusOK, expenseDetails) +} diff --git a/api/externals/repository/expense_repository.go b/api/externals/repository/expense_repository.go index d7383a304..788e4a869 100644 --- a/api/externals/repository/expense_repository.go +++ b/api/externals/repository/expense_repository.go @@ -23,6 +23,7 @@ type ExpenseRepository interface { FindLatestRecord(context.Context) (*sql.Row, error) AllItemInfo(context.Context, string) (*sql.Rows, error) AllOrderAndReportInfo(context.Context, string) (*sql.Rows, error) + AllByPeriod(context.Context, string) (*sql.Rows, error) } func NewExpenseRepository(c db.Client, ac abstract.Crud) ExpenseRepository { @@ -107,3 +108,19 @@ func (er *expenseRepository) AllOrderAndReportInfo(c context.Context, expenseID ` return er.crud.Read(c, query) } + +func (er *expenseRepository) AllByPeriod(c context.Context, year string) (*sql.Rows, error) { + query := ` + SELECT + * + FROM + expense + INNER JOIN + years + ON + expense.yearID = years.id + WHERE + years.year = ` + year + + " ORDER BY expense.id;" + return er.crud.Read(c, query) +} diff --git a/api/internals/domain/expense.go b/api/internals/domain/expense.go index e46da2ba1..60055f9bd 100644 --- a/api/internals/domain/expense.go +++ b/api/internals/domain/expense.go @@ -23,3 +23,9 @@ type PurchaseDetail struct { PurchaseReport PurchaseReport `json:"purchaseReport"` PurchaseItems []PurchaseItem `json:"purchaseItems"` } + +type ExpenseDetailsByperiod struct { + Expense Expense `json:"expense"` + Year Year `json:"year"` + PurchaseDetails []PurchaseDetail `json:"purchaseDetails"` +} diff --git a/api/internals/usecase/expense_usecase.go b/api/internals/usecase/expense_usecase.go index 7f3a77fc3..cedb75c87 100644 --- a/api/internals/usecase/expense_usecase.go +++ b/api/internals/usecase/expense_usecase.go @@ -22,6 +22,7 @@ type ExpenseUseCase interface { UpdateExpenseTP(context.Context) error GetExpenseDetails(context.Context) ([]domain.ExpenseDetails, error) GetExpenseDetailByID(context.Context, string) (domain.ExpenseDetails, error) + GetExpenseDetailsByPeriod(context.Context, string) ([]domain.ExpenseDetailsByperiod, error) } func NewExpenseUseCase(rep rep.ExpenseRepository) ExpenseUseCase { @@ -267,3 +268,85 @@ func (e *expenseUseCase) GetExpenseDetailByID(c context.Context, id string) (dom expenseDetail.PurchaseDetails = purchaseDetails return expenseDetail, nil } + +func (e *expenseUseCase) GetExpenseDetailsByPeriod(c context.Context, year string) ([]domain.ExpenseDetailsByperiod, error) { + expenseDetail := domain.ExpenseDetailsByperiod{} + var expenseDetails []domain.ExpenseDetailsByperiod + purchaseDetail := domain.PurchaseDetail{} + var purchaseDetails []domain.PurchaseDetail + purchaseItem := domain.PurchaseItem{} + var purchaseItems []domain.PurchaseItem + + rows, err := e.rep.AllByPeriod(c, year) + if err != nil { + return nil, err + } + for rows.Next() { + err := rows.Scan( + &expenseDetail.Expense.ID, + &expenseDetail.Expense.Name, + &expenseDetail.Expense.TotalPrice, + &expenseDetail.Expense.YearID, + &expenseDetail.Expense.CreatedAt, + &expenseDetail.Expense.UpdatedAt, + &expenseDetail.Year.ID, + &expenseDetail.Year.Year, + &expenseDetail.Year.CreatedAt, + &expenseDetail.Year.UpdatedAt, + ) + if err != nil { + return nil, err + } + rows, err := e.rep.AllOrderAndReportInfo(c, strconv.Itoa(int(expenseDetail.Expense.ID))) + for rows.Next() { + err := rows.Scan( + &purchaseDetail.PurchaseReport.ID, + &purchaseDetail.PurchaseReport.UserID, + &purchaseDetail.PurchaseReport.Discount, + &purchaseDetail.PurchaseReport.Addition, + &purchaseDetail.PurchaseReport.FinanceCheck, + &purchaseDetail.PurchaseReport.PurchaseOrderID, + &purchaseDetail.PurchaseReport.Remark, + &purchaseDetail.PurchaseReport.Buyer, + &purchaseDetail.PurchaseReport.CreatedAt, + &purchaseDetail.PurchaseReport.UpdatedAt, + &purchaseDetail.PurchaseOrder.ID, + &purchaseDetail.PurchaseOrder.DeadLine, + &purchaseDetail.PurchaseOrder.UserID, + &purchaseDetail.PurchaseOrder.ExpenseID, + &purchaseDetail.PurchaseOrder.FinanceCheck, + &purchaseDetail.PurchaseOrder.CreatedAt, + &purchaseDetail.PurchaseOrder.UpdatedAt, + ) + if err != nil { + return nil, err + } + rows, err := e.rep.AllItemInfo(c, strconv.Itoa(int(purchaseDetail.PurchaseOrder.ID))) + for rows.Next() { + err := rows.Scan( + &purchaseItem.ID, + &purchaseItem.Item, + &purchaseItem.Price, + &purchaseItem.Quantity, + &purchaseItem.Detail, + &purchaseItem.Url, + &purchaseItem.PurchaseOrderID, + &purchaseItem.FinanceCheck, + &purchaseItem.CreatedAt, + &purchaseItem.UpdatedAt, + ) + if err != nil { + return nil, err + } + purchaseItems = append(purchaseItems, purchaseItem) + } + purchaseDetail.PurchaseItems = purchaseItems + purchaseItems = nil + purchaseDetails = append(purchaseDetails, purchaseDetail) + } + expenseDetail.PurchaseDetails = purchaseDetails + purchaseDetails = nil + expenseDetails = append(expenseDetails, expenseDetail) + } + return expenseDetails, nil +} diff --git a/api/router/router.go b/api/router/router.go index feacb5514..4d3720996 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -121,6 +121,7 @@ func (r router) ProvideRouter(e *echo.Echo) { e.GET("/expenses", r.expenseController.IndexExpense) e.GET("/expenses/updateTP", r.expenseController.UpdateExpenseTP) e.GET("/expenses/details", r.expenseController.IndexExpenseDetails) + e.GET("/expenses/details/:year", r.expenseController.IndexExpenseDetailsByPeriod) e.GET("/expenses/:id", r.expenseController.ShowExpense) e.GET("/expenses/:id/details", r.expenseController.ShowExpenseDetail) e.POST("/expenses", r.expenseController.CreateExpense) From 9948ef6f66855879b159837bcb0e2260e06fc96e Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Tue, 30 Jan 2024 06:24:31 +0000 Subject: [PATCH 42/54] =?UTF-8?q?[mod]=20=E3=83=A1=E3=82=BD=E3=83=83?= =?UTF-8?q?=E3=83=89=E5=90=8D=E3=82=92ByPeriod=E3=81=AB=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/fund_information_controller.go | 10 +++++----- .../repository/fund_information_repository.go | 4 ++-- api/internals/usecase/fund_information_usecase.go | 8 ++++---- api/router/router.go | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/api/externals/controller/fund_information_controller.go b/api/externals/controller/fund_information_controller.go index 21ca7523d..138dbf011 100644 --- a/api/externals/controller/fund_information_controller.go +++ b/api/externals/controller/fund_information_controller.go @@ -19,7 +19,7 @@ type FundInformationController interface { DestroyFundInformation(echo.Context) error IndexFundInformationDetails(echo.Context) error ShowFundInformationDetailByID(echo.Context) error - IndexFundInformationDetailsByYear(echo.Context) error + IndexFundInformationDetailsByPeriod(echo.Context) error } func NewFundInformationController(u usecase.FundInformationUseCase) FundInformationController { @@ -108,12 +108,12 @@ func (f *fundInformationController) ShowFundInformationDetailByID(c echo.Context return c.JSON(http.StatusOK, fundinforuserandteacher) } -// IndexFundInformationDetailsByYear -func (f *fundInformationController) IndexFundInformationDetailsByYear(c echo.Context) error { +// IndexFundInformationDetailsByPeriod +func (f *fundInformationController) IndexFundInformationDetailsByPeriod(c echo.Context) error { year := c.Param("year") - fundInformationDetailsByYear, err := f.u.GetFundInformationDetailsByYear(c.Request().Context(), year) + fundInformationDetailsByPeriod, err := f.u.GetFundInformationDetailsByPeriod(c.Request().Context(), year) if err != nil { return err } - return c.JSON(http.StatusOK, fundInformationDetailsByYear) + return c.JSON(http.StatusOK, fundInformationDetailsByPeriod) } diff --git a/api/externals/repository/fund_information_repository.go b/api/externals/repository/fund_information_repository.go index 620bf6d57..8eb67305c 100644 --- a/api/externals/repository/fund_information_repository.go +++ b/api/externals/repository/fund_information_repository.go @@ -22,7 +22,7 @@ type FundInformationRepository interface { FindDetails(context.Context) (*sql.Rows, error) FindDetailByID(context.Context, string) (*sql.Row, error) FindLatestRecord(context.Context) (*sql.Row, error) - AllDetailsForPeriods(context.Context, string) (*sql.Rows, error) + AllDetailsByPeriod(context.Context, string) (*sql.Rows, error) } func NewFundInformationRepository(c db.Client, ac abstract.Crud) FundInformationRepository { @@ -165,7 +165,7 @@ func (fir *fundInformationRepository) FindLatestRecord(c context.Context) (*sql. } // 年度別のfund_informationに紐づくuserとteacherを取得する -func (fir *fundInformationRepository) AllDetailsForPeriods(c context.Context, year string) (*sql.Rows, error) { +func (fir *fundInformationRepository) AllDetailsByPeriod(c context.Context, year string) (*sql.Rows, error) { query := ` SELECT fund_informations.*, diff --git a/api/internals/usecase/fund_information_usecase.go b/api/internals/usecase/fund_information_usecase.go index 086dcfff1..083097c58 100644 --- a/api/internals/usecase/fund_information_usecase.go +++ b/api/internals/usecase/fund_information_usecase.go @@ -19,7 +19,7 @@ type FundInformationUseCase interface { DestroyFundInformation(context.Context, string) error GetFundInformationDetails(context.Context) ([]domain.FundInformationDetail, error) GetFundInformationDetailByID(context.Context, string) (domain.FundInformationDetail, error) - GetFundInformationDetailsByYear(context.Context, string) ([]domain.FundInformationDetail, error) + GetFundInformationDetailsByPeriod(context.Context, string) ([]domain.FundInformationDetail, error) } func NewFundInformationUseCase(rep rep.FundInformationRepository) FundInformationUseCase { @@ -244,16 +244,16 @@ func (f *fundInformationUseCase) GetFundInformationDetailByID(c context.Context, } //fund_informations_byyear-api(GETS) -func (f *fundInformationUseCase) GetFundInformationDetailsByYear(c context.Context, year string) ([]domain.FundInformationDetail, error) { +func (f *fundInformationUseCase) GetFundInformationDetailsByPeriod(c context.Context, year string) ([]domain.FundInformationDetail, error) { fundInformationDetail:= domain.FundInformationDetail{} var fundInformationDetails []domain.FundInformationDetail - rows, err := f.rep.AllDetailsForPeriods(c, year) + rows, err := f.rep.AllDetailsByPeriod(c, year) if err != nil { return nil, err } defer rows.Close() - + for rows.Next() { err := rows.Scan( &fundInformationDetail.FundInformation.ID, diff --git a/api/router/router.go b/api/router/router.go index efe683c3b..5ae249932 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -135,7 +135,7 @@ func (r router) ProvideRouter(e *echo.Echo) { e.DELETE("/fund_informations/:id", r.fundInformationController.DestroyFundInformation) e.GET("/fund_informations/details", r.fundInformationController.IndexFundInformationDetails) e.GET("/fund_informations/:id/details", r.fundInformationController.ShowFundInformationDetailByID) - e.GET("/fund_informations/details/:year", r.fundInformationController.IndexFundInformationDetailsByYear) + e.GET("/fund_informations/details/:year", r.fundInformationController.IndexFundInformationDetailsByPeriod) // mail auth e.POST("/mail_auth/signup", r.mailAuthController.SignUp) From 87600bb55186b5b4b9c660f0d3352dc160695ab2 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Tue, 30 Jan 2024 12:32:12 +0000 Subject: [PATCH 43/54] =?UTF-8?q?[feat]=20=E5=B9=B4=E5=BA=A6=E5=88=A5?= =?UTF-8?q?=E3=81=AB=E5=8D=94=E8=B3=9B=E6=B4=BB=E5=8B=95=E3=82=92=E5=8F=96?= =?UTF-8?q?=E5=BE=97=E3=81=99=E3=82=8BAPI=E3=81=AE=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/docs/docs.go | 20 +++++ .../controller/activity_controller.go | 11 +++ .../repository/activity_repository.go | 37 ++++++++++ api/internals/usecase/activity_usecase.go | 74 ++++++++++++++++++- api/router/router.go | 1 + 5 files changed, 142 insertions(+), 1 deletion(-) diff --git a/api/docs/docs.go b/api/docs/docs.go index deac96a02..3a73b410a 100644 --- a/api/docs/docs.go +++ b/api/docs/docs.go @@ -56,6 +56,26 @@ const docTemplate = `{ } }, }, + "/activities/details/{year}": { + "get": { + tags: ["activity"], + "description": "年度で指定されたactivitiesとsponsor,sponsorStyle,userの一覧を取得", + "parameters": [ + { + "name": "year", + "in": "path", + "description": "year", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "年度で指定されたactivitiesとsponsor,sponsorStyle,userの一覧を取得", + } + } + }, + }, "/activities/{id}": { "get": { tags: ["activity"], diff --git a/api/externals/controller/activity_controller.go b/api/externals/controller/activity_controller.go index 0aa4a781f..c4060f66c 100644 --- a/api/externals/controller/activity_controller.go +++ b/api/externals/controller/activity_controller.go @@ -21,6 +21,7 @@ type ActivityController interface { UpdateActivity(echo.Context) error DestroyActivity(echo.Context) error IndexActivityDetail(echo.Context) error + IndexActivityDetailsByPeriod(echo.Context) error } func NewActivityController(u usecase.ActivityUseCase) ActivityController { @@ -93,3 +94,13 @@ func (a *activityController) IndexActivityDetail(c echo.Context) error { } return c.JSON(http.StatusOK, activities) } + +// 年度で指定されたactivitiesとsponsor,sponsorStyle,userの一覧を取得 +func (a *activityController) IndexActivityDetailsByPeriod(c echo.Context) error { + year := c.Param("year") + activities, err := a.u.GetActivityDetailsByPeriod(c.Request().Context(), year) + if err != nil { + return err + } + return c.JSON(http.StatusOK, activities) +} diff --git a/api/externals/repository/activity_repository.go b/api/externals/repository/activity_repository.go index 3d4475994..a201b2755 100644 --- a/api/externals/repository/activity_repository.go +++ b/api/externals/repository/activity_repository.go @@ -22,6 +22,7 @@ type ActivityRepository interface { FindDetail(context.Context) (*sql.Rows, error) FindLatestRecord(c context.Context) (*sql.Row, error) FindSponsorStyle(context.Context, string) (*sql.Rows, error) + AllDetailsByPeriod(context.Context, string) (*sql.Rows, error) } func NewActivityRepository(c db.Client, ac abstract.Crud) ActivityRepository { @@ -98,6 +99,7 @@ func (ar *activityRepository) Destroy(c context.Context, id string) error { return ar.crud.UpdateDB(c, query) } +// activityに紐づくsponserとusersを取得する func (ar *activityRepository) FindDetail(c context.Context) (*sql.Rows, error) { query := ` SELECT * FROM @@ -114,6 +116,7 @@ func (ar *activityRepository) FindDetail(c context.Context) (*sql.Rows, error) { return ar.crud.Read(c, query) } +// 最新のレコードを取得 func (ar *activityRepository) FindLatestRecord(c context.Context) (*sql.Row, error) { query := ` SELECT @@ -141,3 +144,37 @@ func (ar *activityRepository) FindSponsorStyle(c context.Context, sponsorStyleID WHERE activity_styles.activity_id = ` + sponsorStyleID return ar.crud.Read(c, query) } + +// 年度別のactivityに紐づくsponserとusersを取得する +func (ar *activityRepository) AllDetailsByPeriod(c context.Context, year string) (*sql.Rows, error) { + query := ` + SELECT + activities.*, + sponsors.*, + users.* + FROM + activities + INNER JOIN + sponsors + ON + activities.sponsor_id = sponsors.id + INNER JOIN + users + ON + activities.user_id = users.id + INNER JOIN + year_periods + ON + activities.created_at > year_periods.started_at + AND + activities.created_at < year_periods.ended_at + INNER JOIN + years + ON + year_periods.year_id = years.id + WHERE + years.year = ` + year + + " ORDER BY activities.id;" + + return ar.crud.Read(c, query) +} diff --git a/api/internals/usecase/activity_usecase.go b/api/internals/usecase/activity_usecase.go index 94a82ab93..05243d731 100644 --- a/api/internals/usecase/activity_usecase.go +++ b/api/internals/usecase/activity_usecase.go @@ -20,6 +20,7 @@ type ActivityUseCase interface { UpdateActivity(context.Context, string, string, string, string, string, string, string, string, string) (domain.Activity, error) DestroyActivity(context.Context, string) error GetActivityDetail(context.Context) ([]domain.ActivityDetail, error) + GetActivityDetailsByPeriod(context.Context, string) ([]domain.ActivityDetail, error) } func NewActivityUseCase(rep rep.ActivityRepository) ActivityUseCase { @@ -144,7 +145,7 @@ func (a *activityUseCase) UpdateActivity( &updatedActivity.Expense, &updatedActivity.Remark, &updatedActivity.Design, - &updatedActivity.Url, + &updatedActivity.Url, &updatedActivity.CreatedAt, &updatedActivity.UpdatedAt, ) @@ -229,3 +230,74 @@ func (a *activityUseCase) GetActivityDetail(c context.Context) ([]domain.Activit } return activities, nil } + +func (a *activityUseCase) GetActivityDetailsByPeriod(c context.Context, year string) ([]domain.ActivityDetail, error) { + + activity := domain.ActivityDetail{} + var activities []domain.ActivityDetail + styleDetail := domain.StyleDetail{} + var styleDetails []domain.StyleDetail + // クエリー実行 + rows, err := a.rep.AllDetailsByPeriod(c, year) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + err := rows.Scan( + &activity.Activity.ID, + &activity.Activity.UserID, + &activity.Activity.IsDone, + &activity.Activity.SponsorID, + &activity.Activity.Feature, + &activity.Activity.Expense, + &activity.Activity.Remark, + &activity.Activity.Design, + &activity.Activity.Url, + &activity.Activity.CreatedAt, + &activity.Activity.UpdatedAt, + &activity.Sponsor.ID, + &activity.Sponsor.Name, + &activity.Sponsor.Tel, + &activity.Sponsor.Email, + &activity.Sponsor.Address, + &activity.Sponsor.Representative, + &activity.Sponsor.CreatedAt, + &activity.Sponsor.UpdatedAt, + &activity.User.ID, + &activity.User.Name, + &activity.User.BureauID, + &activity.User.RoleID, + &activity.User.CreatedAt, + &activity.User.UpdatedAt, + ) + if err != nil { + return nil, errors.Wrapf(err, "cannot connect SQL") + } + rows, err := a.rep.FindSponsorStyle(c,strconv.Itoa(int(activity.Activity.ID))) + for rows.Next(){ + err := rows.Scan( + &styleDetail.ActivityStyle.ID, + &styleDetail.ActivityStyle.ActivityID, + &styleDetail.ActivityStyle.SponsoStyleID, + &styleDetail.ActivityStyle.CreatedAt, + &styleDetail.ActivityStyle.UpdatedAt, + &styleDetail.SponsorStyle.ID, + &styleDetail.SponsorStyle.Style, + &styleDetail.SponsorStyle.Feature, + &styleDetail.SponsorStyle.Price, + &styleDetail.SponsorStyle.CreatedAt, + &styleDetail.SponsorStyle.UpdatedAt, + ) + if err != nil { + return nil, err + } + styleDetails = append(styleDetails, styleDetail) + } + activity.StyleDetail = styleDetails + activities = append(activities, activity) + styleDetails = nil + } + return activities, nil +} diff --git a/api/router/router.go b/api/router/router.go index feacb5514..5b4cda1c4 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -83,6 +83,7 @@ func (r router) ProvideRouter(e *echo.Echo) { e.PUT("/activities/:id", r.activityController.UpdateActivity) e.DELETE("/activities/:id", r.activityController.DestroyActivity) e.GET("/activities/details", r.activityController.IndexActivityDetail) + e.GET("/activities/details/:year",r.activityController.IndexActivityDetailsByPeriod) // activityStyleのRoute e.GET("/activity_styles", r.activityStyleController.IndexActivityStyle) From 7fedd2f61e34cc16c64ff2645bbc05d7c974ce23 Mon Sep 17 00:00:00 2001 From: hikahana <22.h.hanada.nutfes@gmail.com> Date: Tue, 20 Feb 2024 15:56:33 +0000 Subject: [PATCH 44/54] =?UTF-8?q?[feat]=20=E5=B9=B4=E5=BA=A6=E3=81=A7?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E3=81=95=E3=82=8C=E3=81=9Fsponsors=E3=82=92?= =?UTF-8?q?=E5=8F=96=E5=BE=97=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/docs/docs.go | 20 +++++++++++++ .../controller/sponsor_controller.go | 11 ++++++++ .../repository/sponsor_repository.go | 24 ++++++++++++++++ api/internals/usecase/sponsor_usecase.go | 28 +++++++++++++++++++ api/router/router.go | 1 + 5 files changed, 84 insertions(+) diff --git a/api/docs/docs.go b/api/docs/docs.go index 057ef7762..3a2dfd073 100644 --- a/api/docs/docs.go +++ b/api/docs/docs.go @@ -1627,6 +1627,26 @@ const docTemplate = `{ }, }, }, + "/sponsors/{year}": { + "get": { + tags: ["sponsor"], + "description": "年度で指定されたsponsorを取得", + "parameters": [ + { + "name": "year", + "in": "path", + "description": "year", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "sponsorの取得完了", + } + } + }, + }, "/sponsorstyles": { "get": { tags: ["sponsorstyle"], diff --git a/api/externals/controller/sponsor_controller.go b/api/externals/controller/sponsor_controller.go index c65303772..87cc1a871 100644 --- a/api/externals/controller/sponsor_controller.go +++ b/api/externals/controller/sponsor_controller.go @@ -19,6 +19,7 @@ type SponsorController interface { CreateSponsor(echo.Context) error UpdateSponsor(echo.Context) error DestroySponsor(echo.Context) error + IndexSponsorByPeriod(echo.Context) error } func NewSponsorController(u usecase.SponsorUseCase) SponsorController { @@ -90,3 +91,13 @@ func (s *sponsorController) DestroySponsor(c echo.Context) error { } return c.String(http.StatusOK, "Destroy Sponsor") } + +//年度別に取得 +func (s *sponsorController) IndexSponsorByPeriod(c echo.Context) error { + year := c.Param("year") + sponsors, err := s.u.GetSponsorByPeriod(c.Request().Context(), year) + if err != nil { + return err + } + return c.JSON(http.StatusOK, sponsors) +} diff --git a/api/externals/repository/sponsor_repository.go b/api/externals/repository/sponsor_repository.go index 1135bd92d..1fe310074 100644 --- a/api/externals/repository/sponsor_repository.go +++ b/api/externals/repository/sponsor_repository.go @@ -20,6 +20,7 @@ type SponsorRepository interface { Update(context.Context, string, string, string, string, string, string) error Delete(context.Context, string) error FindLatestRecord(context.Context) (*sql.Row, error) + AllByPeriod(context.Context, string) (*sql.Rows, error) } func NewSponsorRepository(c db.Client, ac abstract.Crud) SponsorRepository { @@ -92,3 +93,26 @@ func (sr *sponsorRepository) FindLatestRecord(c context.Context) (*sql.Row, erro query := `SELECT * FROM sponsors ORDER BY id DESC LIMIT 1` return sr.crud.ReadByID(c, query) } + +// 年度別に取得 +func (sr *sponsorRepository) AllByPeriod(c context.Context, year string) (*sql.Rows, error) { + query := ` + SELECT + sponsors.* + FROM + sponsors + INNER JOIN + year_periods + ON + sponsors.created_at > year_periods.started_at + AND + sponsors.created_at < year_periods.ended_at + INNER JOIN + years + ON + year_periods.year_id = years.id + WHERE + years.year = ` + year + + " ORDER BY sponsors.id;" + return sr.crud.Read(c, query) +} diff --git a/api/internals/usecase/sponsor_usecase.go b/api/internals/usecase/sponsor_usecase.go index fe6c01c9e..f2be5c57a 100644 --- a/api/internals/usecase/sponsor_usecase.go +++ b/api/internals/usecase/sponsor_usecase.go @@ -17,6 +17,7 @@ type SponsorUseCase interface { CreateSponsor(context.Context, string, string, string, string, string) (domain.Sponsor, error) UpdateSponsor(context.Context, string, string, string, string, string, string) (domain.Sponsor, error) DestroySponsor(context.Context, string) error + GetSponsorByPeriod(context.Context, string) ([]domain.Sponsor, error) } func NewSponsorUseCase(rep rep.SponsorRepository) SponsorUseCase { @@ -132,3 +133,30 @@ func (s *sponsorUseCase) DestroySponsor( err := s.rep.Delete(c, id) return err } + +// 年度別のsponsorsの取得(GetByPeriod) +func (s *sponsorUseCase) GetSponsorByPeriod(c context.Context, year string) ([]domain.Sponsor, error) { + sponsor := domain.Sponsor{} + var sponsors []domain.Sponsor + rows, err := s.rep.AllByPeriod(c, year) + if err != nil { + return nil, err + } + for rows.Next() { + err := rows.Scan( + &sponsor.ID, + &sponsor.Name, + &sponsor.Tel, + &sponsor.Email, + &sponsor.Address, + &sponsor.Representative, + &sponsor.CreatedAt, + &sponsor.UpdatedAt, + ) + if err != nil { + return nil, err + } + sponsors = append(sponsors, sponsor) + } + return sponsors, nil +} diff --git a/api/router/router.go b/api/router/router.go index 0ed17cb4f..41f4b8069 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -187,6 +187,7 @@ func (r router) ProvideRouter(e *echo.Echo) { e.POST("/sponsors", r.sponsorController.CreateSponsor) e.PUT("/sponsors/:id", r.sponsorController.UpdateSponsor) e.DELETE("/sponsors/:id", r.sponsorController.DestroySponsor) + e.GET("/sponsors/:year", r.sponsorController.IndexSponsorByPeriod) // sponsorstylesのRoute e.GET("/sponsorstyles", r.sponsorStyleController.IndexSponsorStyle) From c0b357afe6022260413b60ccf4a5986e07302153 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Wed, 21 Feb 2024 14:01:25 +0900 Subject: [PATCH 45/54] =?UTF-8?q?budget=E3=81=AE=E5=B9=B4=E5=BA=A6API?= =?UTF-8?q?=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/docs/docs.go | 20 ++++++++++ api/externals/controller/budget_controller.go | 11 ++++++ api/externals/repository/budget_repository.go | 23 ++++++++++++ api/internals/usecase/budget_usecase.go | 37 +++++++++++++++++++ api/router/router.go | 1 + 5 files changed, 92 insertions(+) diff --git a/api/docs/docs.go b/api/docs/docs.go index 3a2dfd073..954772d3f 100644 --- a/api/docs/docs.go +++ b/api/docs/docs.go @@ -283,6 +283,26 @@ const docTemplate = `{ } }, }, + "/budgets/details/{year}": { + "get": { + tags: ["budget"], + "description": "年度で指定されたbudgetsに紐づく年度とソースを取得", + "parameters": [ + { + "name": "year", + "in": "path", + "description": "year", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "年度で指定されたbudgetsに紐づく年度とソースを取得", + } + } + }, + }, "/budgets/{id}": { "get": { tags: ["budget"], diff --git a/api/externals/controller/budget_controller.go b/api/externals/controller/budget_controller.go index b6726c019..6a5f0a3b8 100644 --- a/api/externals/controller/budget_controller.go +++ b/api/externals/controller/budget_controller.go @@ -19,6 +19,7 @@ type BudgetController interface { DestroyBudget(echo.Context) error ShowBudgetDetailById(echo.Context) error ShowBudgetDetails(echo.Context) error + ShowBudgetDetailsByPeriods(echo.Context) error } func NewBudgetController(u usecase.BudgetUseCase) BudgetController { @@ -97,3 +98,13 @@ func (b *budgetController) ShowBudgetDetails(c echo.Context) error { } return c.JSON(http.StatusOK, budgetDetails) } + +// 年度ごとにBudgetと紐づくデータ全件取得 +func (b *budgetController) ShowBudgetDetailsByPeriods(c echo.Context) error { + year := c.Param("year") + budgetDetails, err := b.u.GetBudgetDetailsByPeriod(c.Request().Context(), year) + if err != nil { + return err + } + return c.JSON(http.StatusOK, budgetDetails) +} diff --git a/api/externals/repository/budget_repository.go b/api/externals/repository/budget_repository.go index de49fcbe6..34bcd7962 100644 --- a/api/externals/repository/budget_repository.go +++ b/api/externals/repository/budget_repository.go @@ -22,6 +22,7 @@ type BudgetRepository interface { FindDetailByID(context.Context, string) (*sql.Row, error) FindLatestRecord(context.Context) (*sql.Row, error) FindDetail(context.Context) (*sql.Rows, error) + FindDetailsByPeriod(context.Context, string) (*sql.Rows, error) } func NewBudgetRepository(c db.Client, ac abstract.Crud) BudgetRepository { @@ -128,3 +129,25 @@ func (br *budgetRepository) FindLatestRecord(c context.Context) (*sql.Row, error ` return br.crud.ReadByID(c, query) } + +// yearで切り替えるBudgetに紐づくyearとsourceを全件取得する +func (br *budgetRepository) FindDetailsByPeriod(c context.Context, year string) (*sql.Rows, error) { + query := ` + SELECT + * + FROM + budgets + INNER JOIN + years + ON + budgets.year_id = years.id + INNER JOIN + sources + ON + budgets.source_id = sources.id + WHERE + years.year = ` + year + + " ORDER BY budgets.id;" + + return br.crud.Read(c, query) +} diff --git a/api/internals/usecase/budget_usecase.go b/api/internals/usecase/budget_usecase.go index 0eb7fabea..6e4bb59d3 100644 --- a/api/internals/usecase/budget_usecase.go +++ b/api/internals/usecase/budget_usecase.go @@ -20,6 +20,7 @@ type BudgetUseCase interface { DestroyBudget(context.Context, string) error GetBudgetDetailByID(context.Context, string) (domain.BudgetDetail, error) GetBudgetDetails(c context.Context) ([]domain.BudgetDetail, error) + GetBudgetDetailsByPeriod(context.Context, string) ([]domain.BudgetDetail, error) } func NewBudgetUseCase(rep rep.BudgetRepository) BudgetUseCase { @@ -175,3 +176,39 @@ func (b *budgetUseCase) GetBudgetDetails(c context.Context) ([]domain.BudgetDeta } return budgetDetails, nil } + + +func (b *budgetUseCase) GetBudgetDetailsByPeriod(c context.Context, year string) ([]domain.BudgetDetail, error) { + budgetDetail := domain.BudgetDetail{} + var budgetDetails []domain.BudgetDetail + + rows, err := b.rep.FindDetailsByPeriod(c, year) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + err := rows.Scan( + &budgetDetail.Budget.ID, + &budgetDetail.Budget.Price, + &budgetDetail.Budget.YearID, + &budgetDetail.Budget.SourceID, + &budgetDetail.Budget.CreatedAt, + &budgetDetail.Budget.UpdatedAt, + &budgetDetail.Year.ID, + &budgetDetail.Year.Year, + &budgetDetail.Year.CreatedAt, + &budgetDetail.Year.UpdatedAt, + &budgetDetail.Source.ID, + &budgetDetail.Source.Name, + &budgetDetail.Source.CreatedAt, + &budgetDetail.Source.UpdatedAt, + ) + if err != nil { + return nil, errors.Wrapf(err, "cannot connect SQL") + } + budgetDetails = append(budgetDetails, budgetDetail) + } + return budgetDetails, nil +} diff --git a/api/router/router.go b/api/router/router.go index 41f4b8069..b00227c0e 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -100,6 +100,7 @@ func (r router) ProvideRouter(e *echo.Echo) { e.DELETE("/budgets/:id", r.budgetController.DestroyBudget) e.GET("/budgets/:id/details", r.budgetController.ShowBudgetDetailById) e.GET("/budgets/details", r.budgetController.ShowBudgetDetails) + e.GET("/budgets/details/:year", r.budgetController.ShowBudgetDetailsByPeriods) //bureauのRoute e.GET("/bureaus", r.bureauController.IndexBureau) From e7c78b89fc4c14411d5467902af0065bbe21a552 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Wed, 21 Feb 2024 14:59:10 +0900 Subject: [PATCH 46/54] =?UTF-8?q?=E4=BA=88=E7=AE=97=E3=83=BB=E6=94=AF?= =?UTF-8?q?=E5=87=BA=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AE=E5=B9=B4=E5=BA=A6?= =?UTF-8?q?=E5=88=87=E3=82=8A=E6=9B=BF=E3=81=88=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/src/pages/budgets/index.tsx | 96 ++++++++++++------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/view/next-project/src/pages/budgets/index.tsx b/view/next-project/src/pages/budgets/index.tsx index c3583b0dc..9478a31f0 100644 --- a/view/next-project/src/pages/budgets/index.tsx +++ b/view/next-project/src/pages/budgets/index.tsx @@ -26,11 +26,20 @@ interface Props { expenses: ExpenseView[]; } +const date = new Date(); + export async function getServerSideProps() { - const getBudgetUrl = process.env.SSR_API_URI + '/budgets/details'; - const getSourceUrl = process.env.SSR_API_URI + '/sources'; const getYearUrl = process.env.SSR_API_URI + '/years'; - const getExpenseUrl = process.env.SSR_API_URI + '/expenses/details'; + const periodsRes = await get(getYearUrl); + const getBudgetUrl = + process.env.SSR_API_URI + + '/budgets/details/' + + (periodsRes ? String(periodsRes[periodsRes.length - 1].year) : String(date.getFullYear())); + const getSourceUrl = process.env.SSR_API_URI + '/sources'; + const getExpenseUrl = + process.env.SSR_API_URI + + '/expenses/details/' + + (periodsRes ? String(periodsRes[periodsRes.length - 1].year) : String(date.getFullYear())); const budgetRes = await get(getBudgetUrl); const sourceRes = await get(getSourceUrl); @@ -50,6 +59,8 @@ export default function BudgetList(props: Props) { const { budgets, sources, years, expenses } = props; const auth = useRecoilValue(authAtom); const [currentUser, setCurrentUser] = useState<User>(); + const [budgetViews, setBudgetViews] = useState<BudgetView[]>(props.budgets); + const [expenseViews, setExpenseViews] = useState<ExpenseView[]>(props.expenses); useEffect(() => { const getUser = async () => { @@ -66,42 +77,51 @@ export default function BudgetList(props: Props) { return true; }, [currentUser]); - const [expenseView, setExpenseView] = useState<ExpenseView>(props.expenses[0]); + const [forcusExpense, setForcusExpense] = useState<ExpenseView>(props.expenses[0]); const [isOpen, setIsOpen] = useState(false); const onOpen = (expenseID: number, expenseView: ExpenseView) => { - setExpenseView(expenseView); + setForcusExpense(expenseView); setIsOpen(true); }; - const currentYear: Year = { year: new Date().getFullYear() }; - const [selectedYear, setSelectedYear] = useState<Year>(currentYear); + const [selectedYear, setSelectedYear] = useState<string>( + years ? String(years[years.length - 1].year) : String(date.getFullYear()), + ); + const [selectedExpenseYear, setSelectedExpenseYear] = useState<string>( - currentYear.year.toString(), + years ? String(years[years.length - 1].year) : String(date.getFullYear()), ); - const handleSelectedYear = (selectedYear: number) => { - const year: Year = { year: selectedYear }; - setSelectedYear(year); + + const getBudgets = async () => { + const getBudgtesByYearsURL = process.env.CSR_API_URI + '/budgets/details/' + selectedYear; + const getExpensesByYearsURL = process.env.CSR_API_URI + '/expenses/details/' + selectedYear; + const getBudgetsByYears = await get(getBudgtesByYearsURL); + const getExpensesByYears = await get(getExpensesByYearsURL); + setBudgetViews(getBudgetsByYears); + setExpenseViews(getExpensesByYears); }; - const filteredBudgets = useMemo(() => { - if (!budgets || budgets.length === 0) return []; - return budgets.filter((budgetView) => { - return budgetView.year.year == selectedYear.year; - }); - }, [budgets, selectedYear]); + const getExpenses = async () => { + const getExpensesByYearsURL = + process.env.CSR_API_URI + '/expenses/details/' + selectedExpenseYear; + const getExpensesByYears = await get(getExpensesByYearsURL); + setExpenseViews(getExpensesByYears); + }; - const filteredExpenses = useMemo(() => { - return expenses.filter((expenseView) => { - return expenseView.expense.createdAt?.includes(selectedExpenseYear); - }); - }, [expenses, selectedExpenseYear]); + useEffect(() => { + getBudgets(); + }, [selectedYear]); + + useEffect(() => { + getExpenses(); + }, [selectedExpenseYear]); // 合計金額用の変数 - const budgetsTotalFee = filteredBudgets.reduce((prev, current) => { + const budgetsTotalFee = budgetViews.reduce((prev, current) => { return prev + current.budget.price; }, 0); - const expensesTotalFee = filteredExpenses.reduce((prev, current) => { + const expensesTotalFee = expenseViews.reduce((prev, current) => { return prev + current.expense.totalPrice; }, 0); @@ -130,8 +150,8 @@ export default function BudgetList(props: Props) { <Title title={'収入一覧'} /> <select className='w-100' - defaultValue={currentYear.year} - onChange={(e) => handleSelectedYear(Number(e.target.value))} + defaultValue={selectedYear} + onChange={(e) => setSelectedYear(e.target.value)} > {years.map((year) => ( <option key={year.year} value={year.year}> @@ -168,7 +188,7 @@ export default function BudgetList(props: Props) { </tr> </thead> <tbody> - {filteredBudgets.map((budgetView, index) => ( + {budgetViews.map((budgetView, index) => ( <tr key={budgetView.budget.id} className={clsx( @@ -203,7 +223,7 @@ export default function BudgetList(props: Props) { </td> </tr> ))} - {!filteredBudgets.length && ( + {!budgetViews.length && ( <tr> <td colSpan={6} className='py-3 text-center text-sm text-black-600'> データがありません @@ -211,7 +231,7 @@ export default function BudgetList(props: Props) { </tr> )} </tbody> - {filteredBudgets.length > 0 && ( + {budgetViews.length > 0 && ( <tfoot className={clsx( 'border border-x-white-0 border-b-white-0 border-t-primary-1', @@ -244,12 +264,14 @@ export default function BudgetList(props: Props) { <Title title={'支出一覧'} /> <select className='w-100 ' - defaultValue={currentYear.year} + defaultValue={selectedYear} onChange={(e) => setSelectedExpenseYear(e.target.value)} > - <option value='2021'>2021</option> - <option value='2022'>2022</option> - <option value='2023'>2023</option> + {years.map((year) => ( + <option key={year.year} value={year.year}> + {year.year} + </option> + ))} </select> </div> <div className='mb-2 mt-4 overflow-scroll md:p-5'> @@ -276,7 +298,7 @@ export default function BudgetList(props: Props) { </tr> </thead> <tbody> - {filteredExpenses.map((expenseView, index) => ( + {expenseViews.map((expenseView, index) => ( <tr key={expenseView.expense.id} className={clsx( @@ -325,7 +347,7 @@ export default function BudgetList(props: Props) { </td> </tr> ))} - {!filteredExpenses.length && ( + {!expenseViews.length && ( <tr> <td colSpan={6} className='py-3 text-center text-sm text-black-600'> データがありません @@ -333,7 +355,7 @@ export default function BudgetList(props: Props) { </tr> )} </tbody> - {filteredExpenses.length > 0 && ( + {expenseViews.length > 0 && ( <tfoot className={clsx( 'border border-x-white-0 border-b-white-0 border-t-primary-1', @@ -358,7 +380,7 @@ export default function BudgetList(props: Props) { </TabPanel> </TabPanels> </Tabs> - {isOpen && <DetailModal setIsOpen={setIsOpen} expenseView={expenseView} />} + {isOpen && <DetailModal setIsOpen={setIsOpen} expenseView={forcusExpense} />} </MainLayout> ); } From 758247f649ef46664c1043425502d544369cae5f Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Wed, 21 Feb 2024 15:09:35 +0900 Subject: [PATCH 47/54] =?UTF-8?q?[fix]=E3=83=87=E3=83=BC=E3=82=BF=E3=81=8C?= =?UTF-8?q?0=E4=BB=B6=E3=81=AE=E5=87=A6=E7=90=86=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/src/pages/budgets/index.tsx | 191 +++++++++--------- 1 file changed, 97 insertions(+), 94 deletions(-) diff --git a/view/next-project/src/pages/budgets/index.tsx b/view/next-project/src/pages/budgets/index.tsx index 9478a31f0..8fa4ae6e2 100644 --- a/view/next-project/src/pages/budgets/index.tsx +++ b/view/next-project/src/pages/budgets/index.tsx @@ -94,11 +94,8 @@ export default function BudgetList(props: Props) { const getBudgets = async () => { const getBudgtesByYearsURL = process.env.CSR_API_URI + '/budgets/details/' + selectedYear; - const getExpensesByYearsURL = process.env.CSR_API_URI + '/expenses/details/' + selectedYear; const getBudgetsByYears = await get(getBudgtesByYearsURL); - const getExpensesByYears = await get(getExpensesByYearsURL); setBudgetViews(getBudgetsByYears); - setExpenseViews(getExpensesByYears); }; const getExpenses = async () => { @@ -117,13 +114,17 @@ export default function BudgetList(props: Props) { }, [selectedExpenseYear]); // 合計金額用の変数 - const budgetsTotalFee = budgetViews.reduce((prev, current) => { - return prev + current.budget.price; - }, 0); + const budgetsTotalFee = + budgetViews && + budgetViews.reduce((prev, current) => { + return prev + current.budget.price; + }, 0); - const expensesTotalFee = expenseViews.reduce((prev, current) => { - return prev + current.expense.totalPrice; - }, 0); + const expensesTotalFee = + expenseViews && + expenseViews.reduce((prev, current) => { + return prev + current.expense.totalPrice; + }, 0); const formatDate = (date: string) => { const datetime = date.replace('T', ' '); @@ -188,42 +189,43 @@ export default function BudgetList(props: Props) { </tr> </thead> <tbody> - {budgetViews.map((budgetView, index) => ( - <tr - key={budgetView.budget.id} - className={clsx( - index !== budgets.length - 1 && 'border-b', - 'py-3 text-black-600', - )} - > - <td className='py-3 text-center'>{budgetView.source.name}</td> - <td className='py-3 text-center'>{budgetView.year.year}</td> - <td className='py-3 text-center'>{budgetView.budget.price}</td> - <td className='py-3 text-center'> - {formatDate( - budgetView.budget.createdAt ? budgetView.budget.createdAt : '', + {budgetViews && + budgetViews.map((budgetView, index) => ( + <tr + key={budgetView.budget.id} + className={clsx( + index !== budgets.length - 1 && 'border-b', + 'py-3 text-black-600', )} - </td> - <td className='py-3 text-center'> - {formatDate( - budgetView.budget.updatedAt ? budgetView.budget.updatedAt : '', - )} - </td> - <td className='flex items-center justify-center gap-3 py-3'> - <OpenEditModalButton - id={budgetView.budget.id ? budgetView.budget.id : 0} - sources={sources} - years={years} - isDisabled={isDisabled} - /> - <OpenDeleteModalButton - id={budgetView.budget.id ? budgetView.budget.id : 0} - isDisabled={isDisabled} - /> - </td> - </tr> - ))} - {!budgetViews.length && ( + > + <td className='py-3 text-center'>{budgetView.source.name}</td> + <td className='py-3 text-center'>{budgetView.year.year}</td> + <td className='py-3 text-center'>{budgetView.budget.price}</td> + <td className='py-3 text-center'> + {formatDate( + budgetView.budget.createdAt ? budgetView.budget.createdAt : '', + )} + </td> + <td className='py-3 text-center'> + {formatDate( + budgetView.budget.updatedAt ? budgetView.budget.updatedAt : '', + )} + </td> + <td className='flex items-center justify-center gap-3 py-3'> + <OpenEditModalButton + id={budgetView.budget.id ? budgetView.budget.id : 0} + sources={sources} + years={years} + isDisabled={isDisabled} + /> + <OpenDeleteModalButton + id={budgetView.budget.id ? budgetView.budget.id : 0} + isDisabled={isDisabled} + /> + </td> + </tr> + ))} + {!budgetViews && ( <tr> <td colSpan={6} className='py-3 text-center text-sm text-black-600'> データがありません @@ -231,7 +233,7 @@ export default function BudgetList(props: Props) { </tr> )} </tbody> - {budgetViews.length > 0 && ( + {budgetViews && budgetViews.length > 0 && ( <tfoot className={clsx( 'border border-x-white-0 border-b-white-0 border-t-primary-1', @@ -298,56 +300,57 @@ export default function BudgetList(props: Props) { </tr> </thead> <tbody> - {expenseViews.map((expenseView, index) => ( - <tr - key={expenseView.expense.id} - className={clsx( - index !== expenses.length - 1 && 'border-b', - 'py-3 text-black-600', - )} - > - <td - className='py-3 text-center' - onClick={() => onOpen(expenseView.expense.id || 0, expenseView)} - > - {expenseView.expense.name} - </td> - <td - onClick={() => onOpen(expenseView.expense.id || 0, expenseView)} - className='py-3 text-center' - > - {expenseView.expense.totalPrice} - </td> - <td - onClick={() => onOpen(expenseView.expense.id || 0, expenseView)} - className='py-3 text-center' - > - {formatDate( - expenseView.expense.createdAt ? expenseView.expense.createdAt : '', + {expenseViews && + expenseViews.map((expenseView, index) => ( + <tr + key={expenseView.expense.id} + className={clsx( + index !== expenses.length - 1 && 'border-b', + 'py-3 text-black-600', )} - </td> - <td - onClick={() => onOpen(expenseView.expense.id || 0, expenseView)} - className='py-3 text-center' > - {formatDate( - expenseView.expense.updatedAt ? expenseView.expense.updatedAt : '', - )} - </td> - <td className='flex justify-center gap-3 py-3'> - <OpenExpenseEditModalButton - disabled={isDisabled} - id={expenseView.expense.id ? expenseView.expense.id : 0} - expense={expenseView.expense} - /> - <OpenExpenseDeleteModalButton - disabled={isDisabled} - id={expenseView.expense.id ? expenseView.expense.id : 0} - /> - </td> - </tr> - ))} - {!expenseViews.length && ( + <td + className='py-3 text-center' + onClick={() => onOpen(expenseView.expense.id || 0, expenseView)} + > + {expenseView.expense.name} + </td> + <td + onClick={() => onOpen(expenseView.expense.id || 0, expenseView)} + className='py-3 text-center' + > + {expenseView.expense.totalPrice} + </td> + <td + onClick={() => onOpen(expenseView.expense.id || 0, expenseView)} + className='py-3 text-center' + > + {formatDate( + expenseView.expense.createdAt ? expenseView.expense.createdAt : '', + )} + </td> + <td + onClick={() => onOpen(expenseView.expense.id || 0, expenseView)} + className='py-3 text-center' + > + {formatDate( + expenseView.expense.updatedAt ? expenseView.expense.updatedAt : '', + )} + </td> + <td className='flex justify-center gap-3 py-3'> + <OpenExpenseEditModalButton + disabled={isDisabled} + id={expenseView.expense.id ? expenseView.expense.id : 0} + expense={expenseView.expense} + /> + <OpenExpenseDeleteModalButton + disabled={isDisabled} + id={expenseView.expense.id ? expenseView.expense.id : 0} + /> + </td> + </tr> + ))} + {!expenseViews && ( <tr> <td colSpan={6} className='py-3 text-center text-sm text-black-600'> データがありません @@ -355,7 +358,7 @@ export default function BudgetList(props: Props) { </tr> )} </tbody> - {expenseViews.length > 0 && ( + {expenseViews && expenseViews.length > 0 && ( <tfoot className={clsx( 'border border-x-white-0 border-b-white-0 border-t-primary-1', From 740cb8480ef9de3ee1d61c8b6d3b50907a743f74 Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Wed, 21 Feb 2024 15:19:01 +0900 Subject: [PATCH 48/54] =?UTF-8?q?[fix]=20=E5=90=84=E5=B9=B4=E5=BA=A6?= =?UTF-8?q?=E6=AF=8E=E3=81=AB=E5=8F=96=E5=BE=97=E3=81=99=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/purchasereports/index.tsx | 111 ++++++++++-------- 1 file changed, 63 insertions(+), 48 deletions(-) diff --git a/view/next-project/src/pages/purchasereports/index.tsx b/view/next-project/src/pages/purchasereports/index.tsx index dd53e909a..a786e80f3 100644 --- a/view/next-project/src/pages/purchasereports/index.tsx +++ b/view/next-project/src/pages/purchasereports/index.tsx @@ -1,9 +1,7 @@ -import clsx from 'clsx'; import Head from 'next/head'; import { useCallback, useEffect, useState, useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import PrimaryButton from '@/components/common/OutlinePrimaryButton/OutlinePrimaryButton'; - import { authAtom } from '@/store/atoms'; import { put } from '@/utils/api/api_methods'; import { createPurchaseReportCsv } from '@/utils/createPurchaseReportCsv'; @@ -16,7 +14,7 @@ import DetailModal from '@components/purchasereports/DetailModal'; import OpenAddModalButton from '@components/purchasereports/OpenAddModalButton'; import OpenDeleteModalButton from '@components/purchasereports/OpenDeleteModalButton'; import OpenEditModalButton from '@components/purchasereports/OpenEditModalButton'; -import { PurchaseItem, PurchaseOrder, PurchaseReport, User, Expense } from '@type/common'; +import { PurchaseItem, PurchaseOrder, PurchaseReport, User, Expense, YearPeriod } from '@type/common'; export interface PurchaseReportView { purchaseReport: PurchaseReport; @@ -32,11 +30,16 @@ interface Props { user: User; purchaseOrder: PurchaseOrder[]; expenses: Expense[]; + yearPeriods: YearPeriod[]; } +const date = new Date(); + export async function getServerSideProps() { - const getPurchaseReportsUrl = process.env.SSR_API_URI + '/purchasereports'; - const getPurchaseReportViewUrl = process.env.SSR_API_URI + '/purchasereports/details'; + const getPurchaseReportsUrl = process.env.SSR_API_URI + '/years/periods'; + const periodsRes = await get(getPurchaseReportsUrl) + const getPurchaseReportViewUrl = process.env.SSR_API_URI + '/purchasereports/details/' + + (periodsRes ? String(periodsRes[periodsRes.length - 1].year) : String(date.getFullYear())); const getExpenseUrl = process.env.SSR_API_URI + '/expenses'; const purchaseReportsRes = await get(getPurchaseReportsUrl); const purchaseReportViewRes = await get(getPurchaseReportViewUrl); @@ -46,6 +49,7 @@ export async function getServerSideProps() { purchaseReports: purchaseReportsRes, purchaseReportViews: purchaseReportViewRes, expenses: expenseRes, + yearPeriods: periodsRes, }, }; } @@ -60,16 +64,14 @@ const formatYYYYMMDD = (date: Date) => { export default function PurchaseReports(props: Props) { const auth = useRecoilValue(authAtom); const [currentUser, setCurrentUser] = useState<User>(); - const [purchaseReportID, setPurchaseReportID] = useState<number>(1); const [purchaseReportViewItem, setPurchaseReportViewItem] = useState<PurchaseReportView>(); const [purchaseReportViews, setPurchaseReportViews] = useState<PurchaseReportView[]>( props.purchaseReportViews, ); - const [purchaseReportChecks, setPurchaseReportChecks] = useState<boolean[]>([]); - const [isOpen, setIsOpen] = useState<boolean>(false); + const onOpen = (purchaseOrderID: number, purchaseReportViewItem: PurchaseReportView) => { setPurchaseReportID(purchaseOrderID); setPurchaseReportViewItem(purchaseReportViewItem); @@ -82,14 +84,19 @@ export default function PurchaseReports(props: Props) { return datetime2; }, []); - const currentYear = new Date().getFullYear().toString(); - const [selectedYear, setSelectedYear] = useState<string>(currentYear); + const yearPeriods = props.yearPeriods; + const [selectedYear, setSelectedYear] = useState<string>( + yearPeriods ? String(yearPeriods[yearPeriods.length - 1].year) : String(date.getFullYear()), + ); - const filteredPurchaseReportViews = useMemo(() => { - return purchaseReportViews.filter((purchaseReportViewItem) => { - return purchaseReportViewItem.purchaseOrder.createdAt?.includes(selectedYear); - }); - }, [purchaseReportViews, selectedYear]); + // eslint-disable-next-line react-hooks/exhaustive-deps + const getPurchaseReport = async () => { + const getPurchaseReportViewUrlByYear = + process.env.CSR_API_URI + '/purchasereports/details/' + selectedYear; + console.log(getPurchaseReportViewUrlByYear); + const getPurchaseOrderByYears = await get(getPurchaseReportViewUrlByYear); + setPurchaseReportViews(getPurchaseOrderByYears); + }; const TotalFee = useCallback((purchaseReport: PurchaseReport, purchaseItems: PurchaseItem[]) => { let totalFee = 0; @@ -104,18 +111,23 @@ export default function PurchaseReports(props: Props) { } }, []); - // すべてのpurchaseReportの合計金額 + //すべてのpurchaseReportの合計金額 const totalReportFee = useMemo(() => { - if (filteredPurchaseReportViews) { + if (purchaseReportViews) { let totalFee = 0; - filteredPurchaseReportViews.map((purchaseReportView: PurchaseReportView) => { - totalFee += - TotalFee(purchaseReportView.purchaseReport, purchaseReportView.purchaseItems) || 0; + purchaseReportViews.forEach((purchaseReportView: PurchaseReportView) => { + const fee = TotalFee(purchaseReportView.purchaseReport, purchaseReportView.purchaseItems) || 0; + console.log(`Report ID: ${purchaseReportView.purchaseReport.id}, Fee: ${fee}`); + totalFee += fee; }); return totalFee; } return 0; - }, [filteredPurchaseReportViews]); + }, [TotalFee, purchaseReportViews]); + + useEffect(() => { + getPurchaseReport(); + }, [selectedYear, getPurchaseReport]) const isDisabled = useCallback( (purchaseReportView: PurchaseReportView) => { @@ -130,7 +142,7 @@ export default function PurchaseReports(props: Props) { return true; } }, - [currentUser?.roleID, currentUser?.id, purchaseReportViews], + [currentUser?.roleID, currentUser?.id], ); const updatePurchaseReport = async (purchaseReportID: number, purchaseReport: PurchaseReport) => { @@ -146,13 +158,13 @@ export default function PurchaseReports(props: Props) { }; useEffect(() => { - if (filteredPurchaseReportViews) { - const purchaseReportChecks = filteredPurchaseReportViews.map((purchaseReportView) => { + if (purchaseReportViews) { + const purchaseReportChecks = purchaseReportViews.map((purchaseReportView) => { return purchaseReportView.purchaseReport.financeCheck; }); setPurchaseReportChecks(purchaseReportChecks); } - }, [filteredPurchaseReportViews]); + }, [purchaseReportViews]); const isFinanceDirector = useMemo(() => { if (currentUser?.roleID === 3) { @@ -168,7 +180,7 @@ export default function PurchaseReports(props: Props) { setCurrentUser(res); }; getUser(); - }, []); + }); return ( <MainLayout> @@ -176,25 +188,32 @@ export default function PurchaseReports(props: Props) { <title>購入報告一覧 - +
<select - className='w-100 ' - defaultValue={currentYear} - onChange={(e) => setSelectedYear(e.target.value)} + className='w-100' + defaultValue={selectedYear} + onChange={async (e) => { + setSelectedYear(e.target.value); + }} > - <option value='2021'>2021</option> - <option value='2022'>2022</option> - <option value='2023'>2023</option> + {props.yearPeriods && + props.yearPeriods.map((year) => { + return ( + <option value={year.year} key={year.id}> + {year.year}年度 + </option> + ); + })} </select> <PrimaryButton className='hidden md:block' onClick={async () => { downloadFile({ downloadContent: await createPurchaseReportCsv( - filteredPurchaseReportViews, + purchaseReportViews, props.expenses, ), fileName: `購入申請一覧(${selectedYear})_${formatYYYYMMDD(new Date())}.csv`, @@ -244,13 +263,11 @@ export default function PurchaseReports(props: Props) { </tr> </thead> <tbody className='border border-x-white-0 border-b-primary-1 border-t-white-0'> - {filteredPurchaseReportViews && - filteredPurchaseReportViews.map((purchaseReportViewItem, index) => ( + {purchaseReportViews && + purchaseReportViews.map((purchaseReportViewItem, index) => ( <tr className='border-b' key={purchaseReportViewItem.purchaseReport.id}> - <td - className={clsx('px-1', index === 0 ? 'pb-3 pt-4' : 'py-3', 'border-b py-3')} - > - <div className={clsx('text-center text-sm text-black-600')}> + <td className='py-3'> + <div className='text-center text-sm text-black-600'> <Checkbox checked={purchaseReportChecks[index]} disabled={!isFinanceDirector} @@ -283,7 +300,7 @@ export default function PurchaseReports(props: Props) { ); }} > - <div className={clsx('flex justify-center')}> + <div className='flex justify-center'> <BureauLabel bureauName={ props.expenses.find( @@ -331,9 +348,7 @@ export default function PurchaseReports(props: Props) { }} > <div - className={clsx( - 'overflow-hidden text-ellipsis whitespace-nowrap text-center text-sm text-black-600', - )} + className='overflow-hidden text-ellipsis whitespace-nowrap text-center text-sm text-black-600' > {/* name (個数/finasucheck) */} {purchaseReportViewItem.purchaseItems?.map((purchaseItem, index) => ( @@ -410,9 +425,9 @@ export default function PurchaseReports(props: Props) { </td> </tr> ))} - {filteredPurchaseReportViews.length > 0 && ( - <tr> - <td className='border-b border-primary-1 px-1 py-3' colSpan={6}> + {purchaseReportViews && purchaseReportViews.length > 0 && ( + <tr className='border-b border-primary-1'> + <td className='px-1 py-3' colSpan={6}> <div className='text-right text-sm text-black-600'>合計</div> </td> <td className='border-b border-primary-1 px-1 py-3'> @@ -423,7 +438,7 @@ export default function PurchaseReports(props: Props) { </td> </tr> )} - {!filteredPurchaseReportViews.length && ( + {!purchaseReportViews && ( <tr> <td className='border-b border-primary-1 px-1 py-3' colSpan={9}> <div className='text-center text-sm text-black-600'>データがありません</div> From 4dd155cdf7d18797f798ea810e27154d55c7520f Mon Sep 17 00:00:00 2001 From: TkymHrt <TkymHrt@users.noreply.github.com> Date: Wed, 21 Feb 2024 06:28:26 +0000 Subject: [PATCH 49/54] formatted by workflow --- .../src/pages/purchasereports/index.tsx | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/view/next-project/src/pages/purchasereports/index.tsx b/view/next-project/src/pages/purchasereports/index.tsx index a786e80f3..4e120267c 100644 --- a/view/next-project/src/pages/purchasereports/index.tsx +++ b/view/next-project/src/pages/purchasereports/index.tsx @@ -14,7 +14,14 @@ import DetailModal from '@components/purchasereports/DetailModal'; import OpenAddModalButton from '@components/purchasereports/OpenAddModalButton'; import OpenDeleteModalButton from '@components/purchasereports/OpenDeleteModalButton'; import OpenEditModalButton from '@components/purchasereports/OpenEditModalButton'; -import { PurchaseItem, PurchaseOrder, PurchaseReport, User, Expense, YearPeriod } from '@type/common'; +import { + PurchaseItem, + PurchaseOrder, + PurchaseReport, + User, + Expense, + YearPeriod, +} from '@type/common'; export interface PurchaseReportView { purchaseReport: PurchaseReport; @@ -37,9 +44,11 @@ const date = new Date(); export async function getServerSideProps() { const getPurchaseReportsUrl = process.env.SSR_API_URI + '/years/periods'; - const periodsRes = await get(getPurchaseReportsUrl) - const getPurchaseReportViewUrl = process.env.SSR_API_URI + '/purchasereports/details/' + - (periodsRes ? String(periodsRes[periodsRes.length - 1].year) : String(date.getFullYear())); + const periodsRes = await get(getPurchaseReportsUrl); + const getPurchaseReportViewUrl = + process.env.SSR_API_URI + + '/purchasereports/details/' + + (periodsRes ? String(periodsRes[periodsRes.length - 1].year) : String(date.getFullYear())); const getExpenseUrl = process.env.SSR_API_URI + '/expenses'; const purchaseReportsRes = await get(getPurchaseReportsUrl); const purchaseReportViewRes = await get(getPurchaseReportViewUrl); @@ -116,7 +125,8 @@ export default function PurchaseReports(props: Props) { if (purchaseReportViews) { let totalFee = 0; purchaseReportViews.forEach((purchaseReportView: PurchaseReportView) => { - const fee = TotalFee(purchaseReportView.purchaseReport, purchaseReportView.purchaseItems) || 0; + const fee = + TotalFee(purchaseReportView.purchaseReport, purchaseReportView.purchaseItems) || 0; console.log(`Report ID: ${purchaseReportView.purchaseReport.id}, Fee: ${fee}`); totalFee += fee; }); @@ -127,7 +137,7 @@ export default function PurchaseReports(props: Props) { useEffect(() => { getPurchaseReport(); - }, [selectedYear, getPurchaseReport]) + }, [selectedYear, getPurchaseReport]); const isDisabled = useCallback( (purchaseReportView: PurchaseReportView) => { @@ -347,9 +357,7 @@ export default function PurchaseReports(props: Props) { ); }} > - <div - className='overflow-hidden text-ellipsis whitespace-nowrap text-center text-sm text-black-600' - > + <div className='overflow-hidden text-ellipsis whitespace-nowrap text-center text-sm text-black-600'> {/* name (個数/finasucheck) */} {purchaseReportViewItem.purchaseItems?.map((purchaseItem, index) => ( <div key={index}> From 82718d6d3022eabe689502552c86e81db9cd4e1d Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Wed, 21 Feb 2024 15:38:43 +0900 Subject: [PATCH 50/54] =?UTF-8?q?[feat]=E5=8B=9F=E9=87=91=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=81=AE=E5=B9=B4=E5=BA=A6=E5=88=87=E3=82=8A?= =?UTF-8?q?=E6=9B=BF=E3=81=88=E6=A9=9F=E8=83=BD=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/fund_informations/index.tsx | 122 +++++++++++------- 1 file changed, 77 insertions(+), 45 deletions(-) diff --git a/view/next-project/src/pages/fund_informations/index.tsx b/view/next-project/src/pages/fund_informations/index.tsx index 06a0991eb..e23e06c8b 100644 --- a/view/next-project/src/pages/fund_informations/index.tsx +++ b/view/next-project/src/pages/fund_informations/index.tsx @@ -14,7 +14,7 @@ import OpenDeleteModalButton from '@components/fund_information/OpenDeleteModalB import OpenEditModalButton from '@components/fund_information/OpenEditModalButton'; import MainLayout from '@components/layout/MainLayout'; import { DEPARTMENTS } from '@constants/departments'; -import { Department, FundInformation, Teacher, User } from '@type/common'; +import { Department, FundInformation, Teacher, User, YearPeriod } from '@type/common'; interface FundInformationView { fundInformation: FundInformation; @@ -29,13 +29,21 @@ interface Props { fundInformation: FundInformation[]; fundInformationView: FundInformationView[]; users: User[]; + yearPeriods: YearPeriod[]; } +const date = new Date(); + export const getServerSideProps = async () => { + const getPeriodsUrl = process.env.SSR_API_URI + '/years/periods'; + const periodsRes = await get(getPeriodsUrl); const getTeachersInformationURL = process.env.SSR_API_URI + '/teachers'; const getDepartmentURL = process.env.SSR_API_URI + '/departments'; const getFundInformationURL = process.env.SSR_API_URI + '/fund_informations'; - const getFundInformationViewURL = process.env.SSR_API_URI + '/fund_informations/details'; + const getFundInformationViewURL = + process.env.SSR_API_URI + + '/fund_informations/details/' + + (periodsRes ? String(periodsRes[periodsRes.length - 1].year) : String(date.getFullYear())); const getUserURL = process.env.SSR_API_URI + '/users'; const teachersInformationRes = await get(getTeachersInformationURL); const fundInformationRes = await get(getFundInformationURL); @@ -50,6 +58,7 @@ export const getServerSideProps = async () => { fundInformation: fundInformationRes, fundInformationView: fundInformationViewRes, users: userRes, + yearPeriods: periodsRes, }, }; }; @@ -59,7 +68,6 @@ export default function FundInformations(props: Props) { const teachers: Teacher[] = props.teachers; const users: User[] = props.users; const departments: Department[] = props.departments; - const auth = useRecoilValue(authAtom); const [currentUser, setCurrentUser] = useState<User>(); @@ -69,19 +77,27 @@ export default function FundInformations(props: Props) { ); //年の指定 - const currentYear = new Date().getFullYear().toString(); - const [selectedYear, setSelectedYear] = useState<string>(currentYear); + const yearPeriods = props.yearPeriods; + const [selectedYear, setSelectedYear] = useState<string>( + yearPeriods ? String(yearPeriods[yearPeriods.length - 1].year) : String(date.getFullYear()), + ); + + //年度を指定して募金を取得し、fundInformationViewsにset + const getFundInformations = async () => { + const getFundInformationsURL = + process.env.CSR_API_URI + '/fund_informations/details/' + selectedYear; + const getFundInformationsByYears = await get(getFundInformationsURL); + setFundInformationViews(getFundInformationsByYears); + }; + // 選択年が変更された際に募金データを取得 + useEffect(() => { + getFundInformations(); + }, [selectedYear]); // checkしたかどうか const [isFirstChecks, setIsFirstChecks] = useState<boolean[]>([]); const [isLastChecks, setIsLastChecks] = useState<boolean[]>([]); - const filteredFundInformationViews = useMemo(() => { - return fundInformationViews.filter((fundInformationView) => { - return fundInformationView.fundInformation.receivedAt.includes(selectedYear); - }); - }, [fundInformationViews, selectedYear]); - const isDeveloper = useMemo(() => { if (currentUser?.roleID == 2) { return true; @@ -131,31 +147,34 @@ export default function FundInformations(props: Props) { }, []); useEffect(() => { - if (filteredFundInformationViews) { - const firstChecks = filteredFundInformationViews.map((fundInformationView) => { + if (fundInformationViews) { + const firstChecks = fundInformationViews.map((fundInformationView) => { return fundInformationView.fundInformation.isFirstCheck; }); - const lastChecks = filteredFundInformationViews.map((fundInformationView) => { + const lastChecks = fundInformationViews.map((fundInformationView) => { return fundInformationView.fundInformation.isLastCheck; }); setIsFirstChecks(firstChecks); setIsLastChecks(lastChecks); } - }, [filteredFundInformationViews]); + }, [fundInformationViews]); // チェック済みの合計金額用のステート const totalFee = useMemo(() => { - return filteredFundInformationViews.reduce((sum, fundInformationView) => { - if ( - fundInformationView.fundInformation.isLastCheck && - fundInformationView.fundInformation.isFirstCheck - ) { - return sum + fundInformationView.fundInformation.price; - } else { - return sum; - } - }, 0); - }, [filteredFundInformationViews]); + return ( + fundInformationViews && + fundInformationViews.reduce((sum, fundInformationView) => { + if ( + fundInformationView.fundInformation.isLastCheck && + fundInformationView.fundInformation.isFirstCheck + ) { + return sum + fundInformationView.fundInformation.price; + } else { + return sum; + } + }, 0) + ); + }, [fundInformationViews]); // checkboxの値が変わったときに更新 const submit = async (id: number, fundItem: FundInformation) => { @@ -187,12 +206,17 @@ export default function FundInformations(props: Props) { <Title title={'学内募金一覧'} /> <select className='w-50 md:w-100' - defaultValue={currentYear} + defaultValue={selectedYear} onChange={(e) => setSelectedYear(e.target.value)} > - <option value='2021'>2021</option> - <option value='2022'>2022</option> - <option value='2023'>2023</option> + {props.yearPeriods && + props.yearPeriods.map((year) => { + return ( + <option value={year.year} key={year.id}> + {year.year}年度 + </option> + ); + })} </select> </div> <div className='hidden justify-end md:flex '> @@ -202,8 +226,8 @@ export default function FundInformations(props: Props) { </div> </div> <div className='mb-4 md:hidden'> - {filteredFundInformationViews && - filteredFundInformationViews.map((fundViewItem: FundInformationView) => ( + {fundInformationViews && + fundInformationViews.map((fundViewItem: FundInformationView) => ( <Card key={fundViewItem.fundInformation.id}> <div className='flex flex-col gap-2 p-4'> <div> @@ -253,9 +277,6 @@ export default function FundInformations(props: Props) { </div> </Card> ))} - {!filteredFundInformationViews.length && ( - <div className='my-5 text-center text-sm text-black-600'>データがありません</div> - )} </div> <div className='w-100 mb-2 hidden p-5 md:block'> <table className='w-full table-fixed border-collapse md:mb-5'> @@ -289,8 +310,8 @@ export default function FundInformations(props: Props) { </tr> </thead> <tbody className='border border-x-white-0 border-b-primary-1 border-t-white-0'> - {filteredFundInformationViews && - filteredFundInformationViews.map((fundViewItem: FundInformationView, index) => ( + {fundInformationViews && + fundInformationViews.map((fundViewItem: FundInformationView, index) => ( <tr key={fundViewItem.fundInformation.id} className={clsx(index !== fundInformationViews.length - 1 && 'border-b')} @@ -372,16 +393,27 @@ export default function FundInformations(props: Props) { </td> </tr> ))} + {!fundInformationViews && ( + <tr className='border-b border-primary-1'> + <td className='px-1 py-3' colSpan={8}> + <div className='flex justify-center'> + <div className='text-sm text-black-600'>データがありません</div> + </div> + </td> + </tr> + )} </tbody> <tfoot> - <tr> - <th /> - <th /> - <th /> - <th /> - <th className='text-center text-sm text-black-600'>合計金額</th> - <th className='text-center text-sm text-black-600'>{totalFee}</th> - </tr> + {fundInformationViews && ( + <tr> + <th /> + <th /> + <th /> + <th /> + <th className='text-center text-sm text-black-600'>合計金額</th> + <th className='text-center text-sm text-black-600'>{totalFee}</th> + </tr> + )} </tfoot> </table> </div> From bc8d9ecc55b43beda22fed842c2a0ed03cc81478 Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Thu, 22 Feb 2024 15:39:25 +0900 Subject: [PATCH 51/54] =?UTF-8?q?[fix]=20useEffect=E3=81=AE=E3=83=AB?= =?UTF-8?q?=E3=83=BC=E3=83=97=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/src/pages/purchasereports/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/view/next-project/src/pages/purchasereports/index.tsx b/view/next-project/src/pages/purchasereports/index.tsx index 4e120267c..195bed7ce 100644 --- a/view/next-project/src/pages/purchasereports/index.tsx +++ b/view/next-project/src/pages/purchasereports/index.tsx @@ -137,7 +137,8 @@ export default function PurchaseReports(props: Props) { useEffect(() => { getPurchaseReport(); - }, [selectedYear, getPurchaseReport]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedYear]); const isDisabled = useCallback( (purchaseReportView: PurchaseReportView) => { From 1f10c26e8ca2d1023eaca850a101cc1e4b991f02 Mon Sep 17 00:00:00 2001 From: TkymHrt <TkymHrt@users.noreply.github.com> Date: Thu, 22 Feb 2024 06:40:31 +0000 Subject: [PATCH 52/54] formatted by workflow --- view/next-project/src/pages/purchasereports/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/next-project/src/pages/purchasereports/index.tsx b/view/next-project/src/pages/purchasereports/index.tsx index 195bed7ce..2e9c54308 100644 --- a/view/next-project/src/pages/purchasereports/index.tsx +++ b/view/next-project/src/pages/purchasereports/index.tsx @@ -137,7 +137,7 @@ export default function PurchaseReports(props: Props) { useEffect(() => { getPurchaseReport(); - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedYear]); const isDisabled = useCallback( From 762f822f4d71f118c140a184ba03d5c5bac3440e Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Thu, 22 Feb 2024 16:30:18 +0900 Subject: [PATCH 53/54] =?UTF-8?q?[fix]=20console.log=E3=82=92=E5=89=8A?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/src/pages/purchasereports/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/view/next-project/src/pages/purchasereports/index.tsx b/view/next-project/src/pages/purchasereports/index.tsx index 2e9c54308..7e7dc0e12 100644 --- a/view/next-project/src/pages/purchasereports/index.tsx +++ b/view/next-project/src/pages/purchasereports/index.tsx @@ -102,7 +102,6 @@ export default function PurchaseReports(props: Props) { const getPurchaseReport = async () => { const getPurchaseReportViewUrlByYear = process.env.CSR_API_URI + '/purchasereports/details/' + selectedYear; - console.log(getPurchaseReportViewUrlByYear); const getPurchaseOrderByYears = await get(getPurchaseReportViewUrlByYear); setPurchaseReportViews(getPurchaseOrderByYears); }; @@ -127,7 +126,6 @@ export default function PurchaseReports(props: Props) { purchaseReportViews.forEach((purchaseReportView: PurchaseReportView) => { const fee = TotalFee(purchaseReportView.purchaseReport, purchaseReportView.purchaseItems) || 0; - console.log(`Report ID: ${purchaseReportView.purchaseReport.id}, Fee: ${fee}`); totalFee += fee; }); return totalFee; From 77feb1c9d47f11f29c03f4c567985195627126c7 Mon Sep 17 00:00:00 2001 From: Kubosaka <s223301@stn.nagaokaut.ac.jp> Date: Thu, 22 Feb 2024 16:34:22 +0900 Subject: [PATCH 54/54] =?UTF-8?q?[fix]=E3=83=90=E3=82=B0=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- view/next-project/src/pages/budgets/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/view/next-project/src/pages/budgets/index.tsx b/view/next-project/src/pages/budgets/index.tsx index 8fa4ae6e2..9ef8e688d 100644 --- a/view/next-project/src/pages/budgets/index.tsx +++ b/view/next-project/src/pages/budgets/index.tsx @@ -194,7 +194,7 @@ export default function BudgetList(props: Props) { <tr key={budgetView.budget.id} className={clsx( - index !== budgets.length - 1 && 'border-b', + budgetViews && index !== budgetViews.length - 1 && 'border-b', 'py-3 text-black-600', )} > @@ -305,7 +305,7 @@ export default function BudgetList(props: Props) { <tr key={expenseView.expense.id} className={clsx( - index !== expenses.length - 1 && 'border-b', + expenseViews && index !== expenseViews.length - 1 && 'border-b', 'py-3 text-black-600', )} >