Merge branch 'dev' of https://github.com/dikstub-rssa/simrs-be into feat/functional-position-100

This commit is contained in:
vanilia
2025-10-24 16:47:45 +07:00
32 changed files with 414 additions and 29 deletions
+14
View File
@@ -14,6 +14,20 @@
"mode": "auto", "mode": "auto",
"program": "${workspaceFolder}/cmd/bpjs-api" "program": "${workspaceFolder}/cmd/bpjs-api"
}, },
{
"name": "Launch Package simgos sync API",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/simgos-sync-api"
},
{
"name": "Launch Package main sync API",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/main-sync-api"
},
{ {
"name": "Launch Package migratioon", "name": "Launch Package migratioon",
"type": "go", "type": "go",
+12
View File
@@ -1,4 +1,16 @@
# APP DESIGN CONVENTION # APP DESIGN CONVENTION
## Intro
Uses Go Programming Language, with no framework.
- Why no framework? Go's std libs are already powerfull which aligns with the philosophy of "do one thing well"
- It's common in the Go community that "No framework is the best framework"
Uses community standard layout for the project layout, can be viewed here:<br />
https://github.com/golang-standards/project-layout
Uses Clean Architecture (later writen as CA) approach, can be viewed here:<br />
https://www.freecodecamp.org/news/a-quick-introduction-to-clean-architecture-990c014448d2
Uses kebab-case for the directory naming
## Implementing Clean Architecture (later called CA) in the layout ## Implementing Clean Architecture (later called CA) in the layout
1. The CA can be implemented simply by using directory structures to represent the layers 1. The CA can be implemented simply by using directory structures to represent the layers
+41
View File
@@ -0,0 +1,41 @@
appCfg:
fullName: SIMRS Sync
codeName: simrs-sync
version: 0.1.0
env: development
lang: en
dbCfg:
dsn:
maxOpenConns: 5
maxIdleConns: 5
maxIdleTime: 100
multiDbCfg:
dbs :
- name: simrs_sync
dsn:
maxOpenConns: 5
maxIdleConns: 5
maxIdleTime: 100
httpCfg:
host: 127.0.0.1
port: 8003
loggerCfg:
hideTime: true
hideLevel: true
langCfg:
active: en
path: ../../assets/language/en
fileName: data.json
corsCfg:
allowedOrigin:
allowedMethod: GET, POST, PUT, PATCH, DELETE, OPTIONS
syncUrlCfg:
target:
host:
+15
View File
@@ -0,0 +1,15 @@
package main
import (
a "github.com/karincake/apem"
h "simrs-vx/internal/interface/main-sync-handler"
d "github.com/karincake/apem/db-gorm-pg"
l "github.com/karincake/apem/logger-zerolog"
)
func main() {
a.Run(h.SetRoutes(), &l.O, &d.O)
}
+41
View File
@@ -0,0 +1,41 @@
appCfg:
fullName: SIMRS Sync
codeName: simrs-sync
version: 0.1.0
env: development
lang: en
dbCfg:
dsn:
maxOpenConns: 5
maxIdleConns: 5
maxIdleTime: 100
multiDbCfg:
dbs :
- name: simrs_sync
dsn:
maxOpenConns: 5
maxIdleConns: 5
maxIdleTime: 100
httpCfg:
host: 127.0.0.1
port: 8002
loggerCfg:
hideTime: true
hideLevel: true
langCfg:
active: en
path: ../../assets/language/en
fileName: data.json
corsCfg:
allowedOrigin:
allowedMethod: GET, POST, PUT, PATCH, DELETE, OPTIONS
syncUrlCfg:
target:
host:
+15
View File
@@ -0,0 +1,15 @@
package main
import (
a "github.com/karincake/apem"
h "simrs-vx/internal/interface/simgos-sync-handler"
d "github.com/karincake/apem/db-gorm-pg"
l "github.com/karincake/apem/logger-zerolog"
)
func main() {
a.Run(h.SetRoutes(), &l.O, &d.O)
}
@@ -9,6 +9,7 @@ import (
) )
type CreateDto struct { type CreateDto struct {
Code *string `json:"code" validate:"maxLength=20"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
SIP_Number *string `json:"sip_number"` SIP_Number *string `json:"sip_number"`
@@ -24,6 +25,7 @@ type ReadListDto struct {
} }
type FilterDto struct { type FilterDto struct {
Code *string `json:"code"`
Employee_Id *uint `json:"employee-id"` Employee_Id *uint `json:"employee-id"`
IHS_Number *string `json:"ihs-number" validate:"maxLength=20"` IHS_Number *string `json:"ihs-number" validate:"maxLength=20"`
SIP_Number *string `json:"sip-number" validate:"maxLength=20"` SIP_Number *string `json:"sip-number" validate:"maxLength=20"`
@@ -34,6 +36,7 @@ type FilterDto struct {
type ReadDetailDto struct { type ReadDetailDto struct {
Id uint16 `json:"id"` Id uint16 `json:"id"`
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
SIP_Number *string `json:"sip_number"` SIP_Number *string `json:"sip_number"`
@@ -56,6 +59,7 @@ type MetaDto struct {
type ResponseDto struct { type ResponseDto struct {
ecore.Main ecore.Main
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
Employee *ee.Employee `json:"employee,omitempty"` Employee *ee.Employee `json:"employee,omitempty"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
@@ -70,6 +74,7 @@ type ResponseDto struct {
func (d Doctor) ToResponse() ResponseDto { func (d Doctor) ToResponse() ResponseDto {
resp := ResponseDto{ resp := ResponseDto{
Code: d.Code,
Employee_Id: d.Employee_Id, Employee_Id: d.Employee_Id,
Employee: d.Employee, Employee: d.Employee,
IHS_Number: d.IHS_Number, IHS_Number: d.IHS_Number,
@@ -6,6 +6,7 @@ import (
) )
type CreateDto struct { type CreateDto struct {
Code *string `json:"code" validate:"maxLength=20"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` IHS_Number *string `json:"ihs_number" validate:"maxLength=20"`
} }
@@ -17,12 +18,14 @@ type ReadListDto struct {
} }
type FilterDto struct { type FilterDto struct {
Code *string `json:"code"`
Employee_Id *uint `json:"employee-id"` Employee_Id *uint `json:"employee-id"`
IHS_Number *string `json:"ihs-number"` IHS_Number *string `json:"ihs-number"`
} }
type ReadDetailDto struct { type ReadDetailDto struct {
Id uint16 `json:"id"` Id uint16 `json:"id"`
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
} }
@@ -44,6 +47,7 @@ type MetaDto struct {
type ResponseDto struct { type ResponseDto struct {
ecore.Main ecore.Main
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
Employee *ee.Employee `json:"employee,omitempty"` Employee *ee.Employee `json:"employee,omitempty"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
@@ -51,6 +55,7 @@ type ResponseDto struct {
func (d Laborant) ToResponse() ResponseDto { func (d Laborant) ToResponse() ResponseDto {
resp := ResponseDto{ resp := ResponseDto{
Code: d.Code,
Employee_Id: d.Employee_Id, Employee_Id: d.Employee_Id,
Employee: d.Employee, Employee: d.Employee,
IHS_Number: d.IHS_Number, IHS_Number: d.IHS_Number,
@@ -6,6 +6,7 @@ import (
) )
type CreateDto struct { type CreateDto struct {
Code *string `json:"code" validate:"maxLength=20"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` IHS_Number *string `json:"ihs_number" validate:"maxLength=20"`
} }
@@ -17,12 +18,14 @@ type ReadListDto struct {
} }
type FilterDto struct { type FilterDto struct {
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
} }
type ReadDetailDto struct { type ReadDetailDto struct {
Id uint16 `json:"id"` Id uint16 `json:"id"`
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
} }
@@ -44,6 +47,7 @@ type MetaDto struct {
type ResponseDto struct { type ResponseDto struct {
ecore.Main ecore.Main
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
Employee *ee.Employee `json:"employee,omitempty"` Employee *ee.Employee `json:"employee,omitempty"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
@@ -51,6 +55,7 @@ type ResponseDto struct {
func (d Midwife) ToResponse() ResponseDto { func (d Midwife) ToResponse() ResponseDto {
resp := ResponseDto{ resp := ResponseDto{
Code: d.Code,
Employee_Id: d.Employee_Id, Employee_Id: d.Employee_Id,
Employee: d.Employee, Employee: d.Employee,
IHS_Number: d.IHS_Number, IHS_Number: d.IHS_Number,
@@ -8,6 +8,7 @@ import (
) )
type CreateDto struct { type CreateDto struct {
Code *string `json:"code" validate:"maxLength=20"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` IHS_Number *string `json:"ihs_number" validate:"maxLength=20"`
Unit_Id *uint16 `json:"unit_id"` Unit_Id *uint16 `json:"unit_id"`
@@ -21,6 +22,7 @@ type ReadListDto struct {
} }
type FilterDto struct { type FilterDto struct {
Code *string `json:"code"`
Employee_Id *uint `json:"employee-id"` Employee_Id *uint `json:"employee-id"`
IHS_Number *string `json:"ihs-number"` IHS_Number *string `json:"ihs-number"`
Unit_Id *uint16 `json:"unit-id"` Unit_Id *uint16 `json:"unit-id"`
@@ -28,6 +30,7 @@ type FilterDto struct {
} }
type ReadDetailDto struct { type ReadDetailDto struct {
Id uint16 `json:"id"` Id uint16 `json:"id"`
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
} }
@@ -49,6 +52,7 @@ type MetaDto struct {
type ResponseDto struct { type ResponseDto struct {
ecore.Main ecore.Main
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
Employee *ee.Employee `json:"employee,omitempty"` Employee *ee.Employee `json:"employee,omitempty"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
@@ -60,6 +64,7 @@ type ResponseDto struct {
func (d Nurse) ToResponse() ResponseDto { func (d Nurse) ToResponse() ResponseDto {
resp := ResponseDto{ resp := ResponseDto{
Code: d.Code,
Employee_Id: d.Employee_Id, Employee_Id: d.Employee_Id,
Employee: d.Employee, Employee: d.Employee,
IHS_Number: d.IHS_Number, IHS_Number: d.IHS_Number,
@@ -6,6 +6,7 @@ import (
) )
type CreateDto struct { type CreateDto struct {
Code *string `json:"code" validate:"maxLength=20"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` IHS_Number *string `json:"ihs_number" validate:"maxLength=20"`
} }
@@ -17,12 +18,14 @@ type ReadListDto struct {
} }
type FilterDto struct { type FilterDto struct {
Code *string `json:"code"`
Employee_Id *uint `json:"employee-id"` Employee_Id *uint `json:"employee-id"`
IHS_Number *string `json:"ihs-number"` IHS_Number *string `json:"ihs-number"`
} }
type ReadDetailDto struct { type ReadDetailDto struct {
Id uint16 `json:"id"` Id uint16 `json:"id"`
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
} }
@@ -44,6 +47,7 @@ type MetaDto struct {
type ResponseDto struct { type ResponseDto struct {
ecore.Main ecore.Main
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
Employee *ee.Employee `json:"employee,omitempty"` Employee *ee.Employee `json:"employee,omitempty"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
@@ -51,6 +55,7 @@ type ResponseDto struct {
func (d Nutritionist) ToResponse() ResponseDto { func (d Nutritionist) ToResponse() ResponseDto {
resp := ResponseDto{ resp := ResponseDto{
Code: d.Code,
Employee_Id: d.Employee_Id, Employee_Id: d.Employee_Id,
Employee: d.Employee, Employee: d.Employee,
IHS_Number: d.IHS_Number, IHS_Number: d.IHS_Number,
+2 -2
View File
@@ -57,8 +57,8 @@ type DeleteDto struct {
} }
type SearchDto struct { type SearchDto struct {
Search string `json:"search"` Search string `json:"search"`
Mode SearchMode `json:"mode"` Pagination ecore.Pagination
} }
type UploadDto struct { type UploadDto struct {
@@ -6,6 +6,7 @@ import (
) )
type CreateDto struct { type CreateDto struct {
Code *string `json:"code" validate:"maxLength=20"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` IHS_Number *string `json:"ihs_number" validate:"maxLength=20"`
} }
@@ -17,12 +18,14 @@ type ReadListDto struct {
} }
type FilterDto struct { type FilterDto struct {
Code *string `json:"code"`
Employee_Id *uint `json:"employee-id"` Employee_Id *uint `json:"employee-id"`
IHS_Number *string `json:"ihs-number"` IHS_Number *string `json:"ihs-number"`
} }
type ReadDetailDto struct { type ReadDetailDto struct {
Id uint16 `json:"id"` Id uint16 `json:"id"`
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
} }
@@ -44,6 +47,7 @@ type MetaDto struct {
type ResponseDto struct { type ResponseDto struct {
ecore.Main ecore.Main
Code *string `json:"code"`
Employee_Id *uint `json:"employee_id"` Employee_Id *uint `json:"employee_id"`
Employee *ee.Employee `json:"employee,omitempty"` Employee *ee.Employee `json:"employee,omitempty"`
IHS_Number *string `json:"ihs_number"` IHS_Number *string `json:"ihs_number"`
@@ -51,6 +55,7 @@ type ResponseDto struct {
func (d Pharmacist) ToResponse() ResponseDto { func (d Pharmacist) ToResponse() ResponseDto {
resp := ResponseDto{ resp := ResponseDto{
Code: d.Code,
Employee_Id: d.Employee_Id, Employee_Id: d.Employee_Id,
Employee: d.Employee, Employee: d.Employee,
IHS_Number: d.IHS_Number, IHS_Number: d.IHS_Number,
@@ -20,6 +20,7 @@ type CreateDto struct {
Person *ep.UpdateDto `json:"person"` Person *ep.UpdateDto `json:"person"`
PersonAddresses []epa.UpdateDto `json:"personAddresses"` PersonAddresses []epa.UpdateDto `json:"personAddresses"`
PersonContacts []epc.UpdateDto `json:"personContacts"` PersonContacts []epc.UpdateDto `json:"personContacts"`
Code *string `json:"code" validate:"maxLength=20"`
Employee *EmployeUpdateDto `json:"employee"` Employee *EmployeUpdateDto `json:"employee"`
IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` IHS_Number *string `json:"ihs_number" validate:"maxLength=20"`
SIP_Number *string `json:"sip_number" validate:"maxLength=20"` SIP_Number *string `json:"sip_number" validate:"maxLength=20"`
+14
View File
@@ -0,0 +1,14 @@
package synccfg
import (
a "github.com/karincake/apem"
lo "github.com/karincake/apem/loggero"
)
func SetConfig() {
a.ParseSingleCfg(&O)
if O.Host == "" || O.Target == "" {
panic("sync url config host or target empty")
}
lo.I.Println("sync url config loaded, status: DONE!!")
}
+8
View File
@@ -0,0 +1,8 @@
package synccfg
var O SyncUrlCfg = SyncUrlCfg{}
type SyncUrlCfg struct {
Target string `yaml:"target"`
Host string `yaml:"host"`
}
@@ -274,7 +274,7 @@ func SetRoutes() http.Handler {
"PATCH /{id}": patient.O.Update, "PATCH /{id}": patient.O.Update,
"DELETE /{id}": patient.O.Delete, "DELETE /{id}": patient.O.Delete,
"GET /search/{keyword}": patient.O.Search, "GET /search/{keyword}": patient.O.Search,
"GET /by-resident-identity": patient.O.SearchByResidentIdentity, "GET /by-resident-identity": patient.O.SearchByResidentIdentityNumber,
"POST /{id}/upload": patient.O.Upload, "POST /{id}/upload": patient.O.Upload,
}) })
@@ -76,21 +76,22 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) {
func (obj myBase) Search(w http.ResponseWriter, r *http.Request) { func (obj myBase) Search(w http.ResponseWriter, r *http.Request) {
dto := e.SearchDto{} dto := e.SearchDto{}
sf.UrlQueryParam(&dto, *r.URL)
keyword := rw.ValidateString(w, "keyword", r.PathValue("keyword")) keyword := rw.ValidateString(w, "keyword", r.PathValue("keyword"))
if keyword == "" { if keyword == "" {
rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "keyword is required"}, nil) rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "keyword is required"}, nil)
} }
dto.Mode = e.SMIdent
dto.Search = keyword dto.Search = keyword
res, err := u.Search(dto) res, err := u.Search(dto)
rw.DataResponse(w, res, err) rw.DataResponse(w, res, err)
} }
func (obj myBase) SearchByResidentIdentity(w http.ResponseWriter, r *http.Request) { func (obj myBase) SearchByResidentIdentityNumber(w http.ResponseWriter, r *http.Request) {
dto := e.SearchDto{} dto := e.SearchDto{}
sf.UrlQueryParam(&dto, *r.URL) sf.UrlQueryParam(&dto, *r.URL)
dto.Mode = e.SMNik res, err := u.SearchByResidentIdentityNumber(dto)
res, err := u.Search(dto)
rw.DataResponse(w, res, err) rw.DataResponse(w, res, err)
} }
@@ -0,0 +1,36 @@
package mainsynchandler
import (
"net/http"
/******************** infra ********************/
gs "simrs-vx/internal/infra/gorm-setting"
synccfg "simrs-vx/internal/infra/sync-cfg"
/******************** pkg ********************/
cmw "simrs-vx/pkg/cors-manager-mw"
lh "simrs-vx/pkg/lang-helper"
handlerlogger "simrs-vx/pkg/middleware/handler-logger"
zlc "simrs-vx/pkg/zerolog-ctx"
/******************** external ********************/
a "github.com/karincake/apem"
/******************** internal ********************/
"simrs-vx/internal/interface/main-handler/home"
)
func SetRoutes() http.Handler {
///
a.RegisterExtCall(gs.Adjust)
a.RegisterExtCall(zlc.Adjust)
a.RegisterExtCall(lh.Populate)
a.RegisterExtCall(synccfg.SetConfig)
r := http.NewServeMux()
/******************** Main ********************/
r.HandleFunc("/", home.Home)
return cmw.SetCors(handlerlogger.SetLog(r))
}
@@ -0,0 +1,36 @@
package simgossynchandler
import (
"net/http"
/******************** infra ********************/
gs "simrs-vx/internal/infra/gorm-setting"
synccfg "simrs-vx/internal/infra/sync-cfg"
/******************** pkg ********************/
cmw "simrs-vx/pkg/cors-manager-mw"
lh "simrs-vx/pkg/lang-helper"
handlerlogger "simrs-vx/pkg/middleware/handler-logger"
zlc "simrs-vx/pkg/zerolog-ctx"
/******************** external ********************/
a "github.com/karincake/apem"
/******************** internal ********************/
"simrs-vx/internal/interface/main-handler/home"
)
func SetRoutes() http.Handler {
///
a.RegisterExtCall(gs.Adjust)
a.RegisterExtCall(zlc.Adjust)
a.RegisterExtCall(lh.Populate)
a.RegisterExtCall(synccfg.SetConfig)
r := http.NewServeMux()
/******************** Main ********************/
r.HandleFunc("/", home.Home)
return cmw.SetCors(handlerlogger.SetLog(r))
}
@@ -17,6 +17,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Doctor) {
inputSrc = &inputTemp.CreateDto inputSrc = &inputTemp.CreateDto
} }
data.Code = inputSrc.Code
data.Employee_Id = inputSrc.Employee_Id data.Employee_Id = inputSrc.Employee_Id
data.IHS_Number = inputSrc.IHS_Number data.IHS_Number = inputSrc.IHS_Number
data.SIP_Number = inputSrc.SIP_Number data.SIP_Number = inputSrc.SIP_Number
@@ -17,6 +17,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Laborant) {
inputSrc = &inputTemp.CreateDto inputSrc = &inputTemp.CreateDto
} }
data.Code = inputSrc.Code
data.Employee_Id = inputSrc.Employee_Id data.Employee_Id = inputSrc.Employee_Id
data.IHS_Number = inputSrc.IHS_Number data.IHS_Number = inputSrc.IHS_Number
} }
@@ -17,6 +17,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Midwife) {
inputSrc = &inputTemp.CreateDto inputSrc = &inputTemp.CreateDto
} }
data.Code = inputSrc.Code
data.Employee_Id = inputSrc.Employee_Id data.Employee_Id = inputSrc.Employee_Id
data.IHS_Number = inputSrc.IHS_Number data.IHS_Number = inputSrc.IHS_Number
} }
@@ -17,6 +17,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Nurse) {
inputSrc = &inputTemp.CreateDto inputSrc = &inputTemp.CreateDto
} }
data.Code = inputSrc.Code
data.Employee_Id = inputSrc.Employee_Id data.Employee_Id = inputSrc.Employee_Id
data.IHS_Number = inputSrc.IHS_Number data.IHS_Number = inputSrc.IHS_Number
data.Unit_Id = inputSrc.Unit_Id data.Unit_Id = inputSrc.Unit_Id
@@ -17,6 +17,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Nutritionist) {
inputSrc = &inputTemp.CreateDto inputSrc = &inputTemp.CreateDto
} }
data.Code = inputSrc.Code
data.Employee_Id = inputSrc.Employee_Id data.Employee_Id = inputSrc.Employee_Id
data.IHS_Number = inputSrc.IHS_Number data.IHS_Number = inputSrc.IHS_Number
} }
@@ -352,18 +352,18 @@ func Delete(input e.DeleteDto) (*d.Data, error) {
} }
func Search(input e.SearchDto) (*d.Data, error) { func SearchByResidentIdentityNumber(input e.SearchDto) (*d.Data, error) {
var data *e.Patient var data *e.Patient
var err error var err error
event := pl.Event{ event := pl.Event{
Feature: "Search", Feature: "Search By Resident Identity Number",
Source: source, Source: source,
} }
// Start log // Start log
pl.SetLogInfo(&event, input, "started", "search") pl.SetLogInfo(&event, input, "started", "search")
if data, err = SearchData(input, &event); err != nil { if data, err = SearchDataByRIN(input, &event); err != nil {
return nil, err return nil, err
} }
@@ -377,6 +377,46 @@ func Search(input e.SearchDto) (*d.Data, error) {
}, nil }, nil
} }
func Search(input e.SearchDto) (*d.Data, error) {
var dataList []e.Patient
var metaList *e.MetaDto
var err error
event := pl.Event{
Feature: "Search",
Source: source,
}
// Start log
pl.SetLogInfo(&event, input, "started", "readList")
err = dg.I.Transaction(func(tx *gorm.DB) error {
if dataList, metaList, err = SearchData(input, &event, tx); err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return &d.Data{
Meta: d.IS{
"source": source,
"structure": "list-data",
"status": "fetched",
"page_number": strconv.Itoa(metaList.PageNumber),
"page_size": strconv.Itoa(metaList.PageSize),
"record_totalCount": strconv.Itoa(metaList.Count),
"record_currentCount": strconv.Itoa(len(dataList)),
},
Data: e.ToResponseList(dataList),
}, nil
}
func Upload(input e.UploadDto) (*d.Data, error) { func Upload(input e.UploadDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: uint16(input.Id)} rdDto := e.ReadDetailDto{Id: uint16(input.Id)}
var data *e.Patient var data *e.Patient
+52 -19
View File
@@ -154,11 +154,11 @@ func DeleteData(data *e.Patient, event *pl.Event, dbx ...*gorm.DB) error {
return nil return nil
} }
func SearchData(input e.SearchDto, event *pl.Event, dbx ...*gorm.DB) (*e.Patient, error) { // Search By Resident Identity Number
func SearchDataByRIN(input e.SearchDto, event *pl.Event, dbx ...*gorm.DB) (*e.Patient, error) {
pl.SetLogInfo(event, input, "started", "DBSearch") pl.SetLogInfo(event, input, "started", "DBSearch")
var patient e.Patient var data e.Patient
var err error
var tx *gorm.DB var tx *gorm.DB
if len(dbx) > 0 { if len(dbx) > 0 {
@@ -174,27 +174,60 @@ func SearchData(input e.SearchDto, event *pl.Event, dbx ...*gorm.DB) (*e.Patient
Preload("Person.Relatives"). Preload("Person.Relatives").
Preload("Person.Insurances") Preload("Person.Insurances")
switch input.Mode { // Search by patient person's resident identity number (exact match)
case e.SMIdent: err := tx.Joins("JOIN \"Person\" ON \"Patient\".\"Person_Id\" = \"Person\".\"Id\"").
// Search by patient number OR person's resident identity number (exact match) OR person's name (partial match) Where("\"Person\".\"ResidentIdentityNumber\" = ?",
err = tx.Joins("JOIN \"Person\" ON \"Patient\".\"Person_Id\" = \"Person\".\"Id\""). input.Search).
Where("\"Patient\".\"Number\" = ? OR \"Person\".\"ResidentIdentityNumber\" = ? OR \"Person\".\"Name\" ILIKE ?", First(&data).Error
input.Search, input.Search, "%"+input.Search+"%").
First(&patient).Error
case e.SMNik:
// Search by patient person's resident identity number (exact match)
err = tx.Joins("JOIN \"Person\" ON \"Patient\".\"Person_Id\" = \"Person\".\"Id\"").
Where("\"Person\".\"ResidentIdentityNumber\" = ?",
input.Search).
First(&patient).Error
}
if err != nil { if err != nil {
if processedErr := pu.HandleSearchError(err, event, source, input.Search, patient); processedErr != nil { if processedErr := pu.HandleSearchError(err, event, source, input.Search, data); processedErr != nil {
return nil, processedErr return nil, processedErr
} }
} }
pl.SetLogInfo(event, nil, "complete") pl.SetLogInfo(event, nil, "complete")
return &patient, nil return &data, nil
}
func SearchData(input e.SearchDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Patient, *e.MetaDto, error) {
pl.SetLogInfo(event, input, "started", "DBSearch")
var data []e.Patient
pagination := gh.Pagination{}
count := int64(0)
meta := e.MetaDto{}
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
// Preload associations for complete data
tx = tx.Preload(clause.Associations)
tx = tx.Preload("Person.Addresses").
Preload("Person.Contacts").
Preload("Person.Relatives").
Preload("Person.Insurances")
// Search by patient number OR person's resident identity number (exact match) OR person's name (partial match)
tx = tx.Joins("JOIN \"Person\" ON \"Patient\".\"Person_Id\" = \"Person\".\"Id\"").
Where("\"Patient\".\"Number\" ILIKE ? OR \"Person\".\"ResidentIdentityNumber\" ILIKE ? OR \"Person\".\"Name\" ILIKE ?",
"%"+input.Search+"%", "%"+input.Search+"%", "%"+input.Search+"%")
err := tx.Scopes(gh.Paginate(input, &pagination)).Find(&data).Error
if err != nil {
if processedErr := pu.HandleSearchError(err, event, source, input.Search, data); processedErr != nil {
return nil, nil, processedErr
}
}
meta.Count = int(count)
meta.PageNumber = pagination.PageNumber
meta.PageSize = pagination.PageSize
pl.SetLogInfo(event, nil, "complete")
return data, &meta, nil
} }
@@ -17,6 +17,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Pharmacist) {
inputSrc = &inputTemp.CreateDto inputSrc = &inputTemp.CreateDto
} }
data.Code = inputSrc.Code
data.Employee_Id = inputSrc.Employee_Id data.Employee_Id = inputSrc.Employee_Id
data.IHS_Number = inputSrc.IHS_Number data.IHS_Number = inputSrc.IHS_Number
} }
@@ -9,6 +9,7 @@ import (
ed "simrs-vx/internal/domain/main-entities/doctor" ed "simrs-vx/internal/domain/main-entities/doctor"
ee "simrs-vx/internal/domain/main-entities/employee" ee "simrs-vx/internal/domain/main-entities/employee"
el "simrs-vx/internal/domain/main-entities/laborant" el "simrs-vx/internal/domain/main-entities/laborant"
emw "simrs-vx/internal/domain/main-entities/midwife"
en "simrs-vx/internal/domain/main-entities/nurse" en "simrs-vx/internal/domain/main-entities/nurse"
et "simrs-vx/internal/domain/main-entities/nutritionist" et "simrs-vx/internal/domain/main-entities/nutritionist"
ep "simrs-vx/internal/domain/main-entities/pharmacist" ep "simrs-vx/internal/domain/main-entities/pharmacist"
@@ -18,6 +19,7 @@ import (
ud "simrs-vx/internal/use-case/main-use-case/doctor" ud "simrs-vx/internal/use-case/main-use-case/doctor"
ue "simrs-vx/internal/use-case/main-use-case/employee" ue "simrs-vx/internal/use-case/main-use-case/employee"
ul "simrs-vx/internal/use-case/main-use-case/laborant" ul "simrs-vx/internal/use-case/main-use-case/laborant"
umw "simrs-vx/internal/use-case/main-use-case/midwife"
un "simrs-vx/internal/use-case/main-use-case/nurse" un "simrs-vx/internal/use-case/main-use-case/nurse"
ut "simrs-vx/internal/use-case/main-use-case/nutritionist" ut "simrs-vx/internal/use-case/main-use-case/nutritionist"
upe "simrs-vx/internal/use-case/main-use-case/person" upe "simrs-vx/internal/use-case/main-use-case/person"
@@ -106,6 +108,7 @@ func Create(input e.CreateDto) (*d.Data, error) {
switch input.Employee.Position_Code { switch input.Employee.Position_Code {
case ero.EPCDoc: case ero.EPCDoc:
createDoc := ed.CreateDto{ createDoc := ed.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
SIP_Number: input.SIP_Number, SIP_Number: input.SIP_Number,
@@ -118,6 +121,7 @@ func Create(input e.CreateDto) (*d.Data, error) {
} }
case ero.EPCNur: case ero.EPCNur:
createNurse := en.CreateDto{ createNurse := en.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
Unit_Id: input.Unit_Id, Unit_Id: input.Unit_Id,
@@ -128,6 +132,7 @@ func Create(input e.CreateDto) (*d.Data, error) {
} }
case ero.EPCNut: case ero.EPCNut:
createNutritionist := et.CreateDto{ createNutritionist := et.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
} }
@@ -136,6 +141,7 @@ func Create(input e.CreateDto) (*d.Data, error) {
} }
case ero.EPCPha: case ero.EPCPha:
createPharmacist := ep.CreateDto{ createPharmacist := ep.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
} }
@@ -144,12 +150,22 @@ func Create(input e.CreateDto) (*d.Data, error) {
} }
case ero.EPCLab: case ero.EPCLab:
createLaborant := el.CreateDto{ createLaborant := el.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
} }
if _, err := ul.CreateData(createLaborant, &event, tx); err != nil { if _, err := ul.CreateData(createLaborant, &event, tx); err != nil {
return err return err
} }
case ero.EPCMwi:
createMidWife := emw.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number,
}
if _, err := umw.CreateData(createMidWife, &event, tx); err != nil {
return err
}
default: default:
return errors.New("invalid employee position") return errors.New("invalid employee position")
} }
@@ -380,6 +396,7 @@ func Update(input e.UpdateDto) (*d.Data, error) {
return err return err
} }
createDoc := ed.CreateDto{ createDoc := ed.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
SIP_Number: input.SIP_Number, SIP_Number: input.SIP_Number,
@@ -402,6 +419,7 @@ func Update(input e.UpdateDto) (*d.Data, error) {
return err return err
} }
createNur := en.CreateDto{ createNur := en.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
} }
@@ -422,6 +440,7 @@ func Update(input e.UpdateDto) (*d.Data, error) {
return err return err
} }
createNut := et.CreateDto{ createNut := et.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
} }
@@ -442,6 +461,7 @@ func Update(input e.UpdateDto) (*d.Data, error) {
return err return err
} }
createPha := ep.CreateDto{ createPha := ep.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
} }
@@ -462,6 +482,7 @@ func Update(input e.UpdateDto) (*d.Data, error) {
return err return err
} }
createLab := el.CreateDto{ createLab := el.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id, Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number, IHS_Number: input.IHS_Number,
} }
@@ -475,6 +496,27 @@ func Update(input e.UpdateDto) (*d.Data, error) {
if _, err := ul.CreateData(createLab, &event, tx); err != nil { if _, err := ul.CreateData(createLab, &event, tx); err != nil {
return err return err
} }
case ero.EPCMwi:
readMidWife := emw.ReadDetailDto{Employee_Id: &employeeData.Id}
readMidWifeData, err := umw.ReadDetailData(readMidWife, &event, tx)
if err != nil {
return err
}
createMidWife := emw.CreateDto{
Code: input.Code,
Employee_Id: &employeeData.Id,
IHS_Number: input.IHS_Number,
}
if readMidWifeData != nil {
if err := umw.UpdateData(emw.UpdateDto{CreateDto: createMidWife}, readMidWifeData, &event, tx); err != nil {
return err
}
return nil
}
if _, err := umw.CreateData(createMidWife, &event, tx); err != nil {
return err
}
default: default:
return errors.New("invalid employee position") return errors.New("invalid employee position")
} }