diff --git a/docs/docs.go b/docs/docs.go index f62f1f9..6fa1d8c 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -223,6 +223,47 @@ const docTemplate = `{ } } }, + "/dashboard/perbandingan-status-antrian/": { + "get": { + "tags": [ + "Dashboard" + ], + "summary": "Get Perbandingan Status Antrean", + "parameters": [ + { + "type": "integer", + "description": "tahun dalam int", + "name": "year", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "bulan dalam int", + "name": "month", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/dashboard.PerbandinganStatusAntreanResponse" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/shared.BaseErrorResponse" + } + } + } + } + }, "/reference/diagnosa/": { "get": { "tags": [ @@ -591,6 +632,10 @@ const docTemplate = `{ "antrianoperasi.FormDataRequest": { "type": "object", "required": [ + "jenisKelamin", + "namaPasien", + "noKtp", + "noRekamMedis", "nomorTelepon" ], "properties": { @@ -598,7 +643,11 @@ const docTemplate = `{ "type": "string" }, "jenisKelamin": { - "type": "string" + "type": "string", + "enum": [ + "L", + "P" + ] }, "namaPasien": { "type": "string" @@ -715,12 +764,21 @@ const docTemplate = `{ }, "antrianoperasi.StatusPasienRequest": { "type": "object", + "required": [ + "statusOperasi" + ], "properties": { "keteranganStatus": { "type": "string" }, "statusOperasi": { - "type": "string" + "type": "string", + "enum": [ + "1", + "2", + "3", + "4" + ] }, "tanggalSelesai": { "type": "string" @@ -794,6 +852,20 @@ const docTemplate = `{ } } }, + "dashboard.PerbandinganStatusAntreanResponse": { + "type": "object", + "properties": { + "idStatus": { + "type": "integer" + }, + "jumlah": { + "type": "integer" + }, + "status": { + "type": "string" + } + } + }, "diagnosa.DiagnosaResponse": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 6441afa..ccf136a 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -217,6 +217,47 @@ } } }, + "/dashboard/perbandingan-status-antrian/": { + "get": { + "tags": [ + "Dashboard" + ], + "summary": "Get Perbandingan Status Antrean", + "parameters": [ + { + "type": "integer", + "description": "tahun dalam int", + "name": "year", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "bulan dalam int", + "name": "month", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/dashboard.PerbandinganStatusAntreanResponse" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/shared.BaseErrorResponse" + } + } + } + } + }, "/reference/diagnosa/": { "get": { "tags": [ @@ -585,6 +626,10 @@ "antrianoperasi.FormDataRequest": { "type": "object", "required": [ + "jenisKelamin", + "namaPasien", + "noKtp", + "noRekamMedis", "nomorTelepon" ], "properties": { @@ -592,7 +637,11 @@ "type": "string" }, "jenisKelamin": { - "type": "string" + "type": "string", + "enum": [ + "L", + "P" + ] }, "namaPasien": { "type": "string" @@ -709,12 +758,21 @@ }, "antrianoperasi.StatusPasienRequest": { "type": "object", + "required": [ + "statusOperasi" + ], "properties": { "keteranganStatus": { "type": "string" }, "statusOperasi": { - "type": "string" + "type": "string", + "enum": [ + "1", + "2", + "3", + "4" + ] }, "tanggalSelesai": { "type": "string" @@ -788,6 +846,20 @@ } } }, + "dashboard.PerbandinganStatusAntreanResponse": { + "type": "object", + "properties": { + "idStatus": { + "type": "integer" + }, + "jumlah": { + "type": "integer" + }, + "status": { + "type": "string" + } + } + }, "diagnosa.DiagnosaResponse": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 1446922..b06e544 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -81,6 +81,9 @@ definitions: alamat: type: string jenisKelamin: + enum: + - L + - P type: string namaPasien: type: string @@ -98,6 +101,10 @@ definitions: umur: type: string required: + - jenisKelamin + - namaPasien + - noKtp + - noRekamMedis - nomorTelepon type: object antrianoperasi.PasienOperasi: @@ -164,9 +171,16 @@ definitions: keteranganStatus: type: string statusOperasi: + enum: + - "1" + - "2" + - "3" + - "4" type: string tanggalSelesai: type: string + required: + - statusOperasi type: object antrianoperasi.TindakanItemRequest: properties: @@ -212,6 +226,15 @@ definitions: subSpesialis: type: string type: object + dashboard.PerbandinganStatusAntreanResponse: + properties: + idStatus: + type: integer + jumlah: + type: integer + status: + type: string + type: object diagnosa.DiagnosaResponse: properties: keterangan: @@ -485,6 +508,33 @@ paths: summary: Get Antrian Per Spesialis tags: - Dashboard + /dashboard/perbandingan-status-antrian/: + get: + parameters: + - description: tahun dalam int + in: query + name: year + required: true + type: integer + - description: bulan dalam int + in: query + name: month + required: true + type: integer + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/dashboard.PerbandinganStatusAntreanResponse' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/shared.BaseErrorResponse' + summary: Get Perbandingan Status Antrean + tags: + - Dashboard /reference/diagnosa/: get: parameters: diff --git a/internal/domain/dashboard/dashboard_test.go b/internal/domain/dashboard/dashboard_test.go new file mode 100644 index 0000000..46f0042 --- /dev/null +++ b/internal/domain/dashboard/dashboard_test.go @@ -0,0 +1,44 @@ +package dashboard + +import ( + "testing" +) + +type expectedRangeDate struct { + startDate string + endDate string +} + +func TestDashboardDateRange(t *testing.T) { + dataSet := []struct { + testCase string + data PeriodeDashboardRequest + expected expectedRangeDate + }{ + { + testCase: "Normal case", + data: PeriodeDashboardRequest{Year: 2025, Month: 1}, + expected: expectedRangeDate{startDate: "2025-1-1", endDate: "2025-2-1"}, + }, + { + testCase: "Cross year case", + data: PeriodeDashboardRequest{Year: 2025, Month: 12}, + expected: expectedRangeDate{startDate: "2025-12-1", endDate: "2026-1-1"}, + }, + { + testCase: "Month > 12", + data: PeriodeDashboardRequest{Year: 2025, Month: 20}, + expected: expectedRangeDate{startDate: "2025-12-1", endDate: "2026-1-1"}, + }, + } + + t.Run("test parsing dashboard range date", func(t *testing.T) { + for _, testcase := range dataSet { + resultStartDate, resultEndDate := GenerateStartEndDate(testcase.data) + + if resultStartDate != testcase.expected.startDate || resultEndDate != testcase.expected.endDate { + t.Fatalf("expected start date %v got %v \n expected end date %v got %v", testcase.expected.startDate, resultStartDate, testcase.expected.endDate, resultEndDate) + } + } + }) +} diff --git a/internal/domain/dashboard/handler.go b/internal/domain/dashboard/handler.go index 6f2ed7d..16c5471 100644 --- a/internal/domain/dashboard/handler.go +++ b/internal/domain/dashboard/handler.go @@ -3,6 +3,7 @@ package dashboard import ( "net/http" + "antrian-operasi/internal/shared" baseResponse "antrian-operasi/internal/shared" "github.com/gin-gonic/gin" @@ -64,3 +65,43 @@ func (h DashboardHandler) GetAntrianPerSpesialis(c *gin.Context) { c.JSON(http.StatusOK, response) } + +// GetPerbandinganStatusAntrean godoc +// @Summary Get Perbandingan Status Antrean +// @Tags Dashboard +// @Param year query int true "tahun dalam int" +// @Param month query int true "bulan dalam int" +// @Success 200 {object} []PerbandinganStatusAntreanResponse +// @Failure 500 {object} shared.BaseErrorResponse +// @Router /dashboard/perbandingan-status-antrian/ [get] +func (h DashboardHandler) GetPerbandinganstatusAntrean(c *gin.Context) { + var req PeriodeDashboardRequest + if err := c.ShouldBindQuery(&req); err != nil { + c.JSON(400, shared.BaseErrorResponse{ + Success: false, + Code: 500, + Message: "error bind json", + Errors: shared.ValidationError(err), + }) + return + } + + data, err := h.repo.GetPerbandinganStatusAntrean(c, req) + if err != nil { + errorResponse := baseResponse.BaseErrorResponse{ + Success: false, + Code: 500, + Message: err.Error(), + } + c.JSON(http.StatusInternalServerError, errorResponse) + return + } + + response := baseResponse.ToBaseResponse( + data.MapToResponse(), + true, + 200, + "success get perbandingan status antrean") + + c.JSON(http.StatusOK, response) +} diff --git a/internal/domain/dashboard/map.go b/internal/domain/dashboard/map.go new file mode 100644 index 0000000..c81c9bc --- /dev/null +++ b/internal/domain/dashboard/map.go @@ -0,0 +1,22 @@ +package dashboard + +type ListPerbandinganStatusAntrean []PerbandinganStatusAntreanQueryResult + +func (list ListPerbandinganStatusAntrean) findJumlahById(id int) int { + for _, item := range list { + if item.IdStatus == id { + return item.Jumlah + } + } + + return 0 +} + +func (list ListPerbandinganStatusAntrean) MapToResponse() []PerbandinganStatusAntreanResponse { + return []PerbandinganStatusAntreanResponse{ + {IdStatus: 1, Status: "Belum", Jumlah: list.findJumlahById(1)}, + {IdStatus: 2, Status: "Selesai", Jumlah: list.findJumlahById(2)}, + {IdStatus: 3, Status: "Tunda", Jumlah: list.findJumlahById(3)}, + {IdStatus: 4, Status: "Batal", Jumlah: list.findJumlahById(4)}, + } +} diff --git a/internal/domain/dashboard/model.go b/internal/domain/dashboard/model.go index 5bc36d1..7465265 100644 --- a/internal/domain/dashboard/model.go +++ b/internal/domain/dashboard/model.go @@ -27,6 +27,17 @@ type AntrianPerSubSpesialisResponse struct { JmlAntrian int } +type PerbandinganStatusAntreanQueryResult struct { + IdStatus int `db:"status_operasi"` + Jumlah int `db:"jumlah"` +} + +type PerbandinganStatusAntreanResponse struct { + IdStatus int `json:"id"` + Jumlah int `json:"jumlah"` + Status string `json:"statust"` +} + type ListModelAntrianPerSpesialis []AntrianPerSpesialisModel func (list ListModelAntrianPerSpesialis) ParseToResponse() []AntrianPerSpesialisResponse { diff --git a/internal/domain/dashboard/repository.go b/internal/domain/dashboard/repository.go index 98c06cc..a247b06 100644 --- a/internal/domain/dashboard/repository.go +++ b/internal/domain/dashboard/repository.go @@ -15,6 +15,7 @@ const TBL_SUBSPESIALIS = "daftar_subspesialis" type IDashboardRepository interface { GetAntrianPerKategori(c *gin.Context) ([]AntrianPerKategori, error) GetAntrianPerSpesialis(c *gin.Context) (ListModelAntrianPerSpesialis, error) + GetPerbandinganStatusAntrean(c *gin.Context, req PeriodeDashboardRequest) (ListPerbandinganStatusAntrean, error) } type dashboardRepo struct { @@ -149,3 +150,41 @@ func (r dashboardRepo) GetAntrianPerSpesialis(c *gin.Context) (ListModelAntrianP return result, nil } + +func (r dashboardRepo) GetPerbandinganStatusAntrean(c *gin.Context, req PeriodeDashboardRequest) (ListPerbandinganStatusAntrean, error) { + var result ListPerbandinganStatusAntrean + startDate, endDate := GenerateStartEndDate(req) + + query := queryUtils.DynamicQuery{ + From: TBL_NAME, + Aliases: "dpo", + Fields: []queryUtils.SelectField{ + {Expression: "dpo.Status_operasi", Alias: "status_operasi"}, + {Expression: "COUNT(dpo.id)", Alias: "jumlah"}, + }, + Filters: []queryUtils.FilterGroup{ + { + Filters: []queryUtils.DynamicFilter{ + {Column: "dpo.Tanggal_daftar", Operator: queryUtils.OpBetween, Value: []string{startDate, endDate}}, + }, + }, + }, + GroupBy: []string{"dpo.Status_operasi"}, + Sort: []queryUtils.SortField{ + {Column: "dpo.Status_operasi", Order: "ASC"}, + }, + } + + dbconn, err := r.db.GetSQLXDB(DB_NAME) + if err != nil { + return result, err + } + + err = r.queryBuilder.ExecuteQuery( + c, dbconn, query, &result) + if err != nil { + return result, err + } + + return result, nil +} diff --git a/internal/domain/dashboard/request.go b/internal/domain/dashboard/request.go new file mode 100644 index 0000000..0686683 --- /dev/null +++ b/internal/domain/dashboard/request.go @@ -0,0 +1,23 @@ +package dashboard + +import "strconv" + +type PeriodeDashboardRequest struct { + Year int `form:"year" binding:"required,min=1"` + Month int `form:"month" binding:"required,min=1,max=12"` +} + +func GenerateStartEndDate(req PeriodeDashboardRequest) (startDate string, endDate string) { + endYear := req.Year + endMonth := req.Month + 1 + if req.Month >= 12 { + req.Month = 12 + endYear = req.Year + 1 + endMonth = 1 + } + + startDate = strconv.Itoa(req.Year) + "-" + strconv.Itoa(req.Month) + "-1" + endDate = strconv.Itoa(endYear) + "-" + strconv.Itoa(endMonth) + "-1" + + return startDate, endDate +} diff --git a/internal/domain/dashboard/routes.go b/internal/domain/dashboard/routes.go index 0b1644b..d430f45 100644 --- a/internal/domain/dashboard/routes.go +++ b/internal/domain/dashboard/routes.go @@ -12,4 +12,5 @@ func RegisterRoutes(r *gin.RouterGroup, dbService database.Service) { r.GET("/antrian-per-kategori", dashboardHandler.GetAntrianPerKategori) r.GET("/antrian-per-spesialis", dashboardHandler.GetAntrianPerSpesialis) + r.GET("/perbandingan-status-antrian", dashboardHandler.GetPerbandinganstatusAntrean) }