From f51b9baeed7f1670c3d78df3244e322290190a53 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 3 Sep 2025 16:39:26 +0700 Subject: [PATCH 01/30] feat (encounter): basic crud --- .../main-handler/encounter/handler.go | 71 +++++ .../interface/main-handler/main-handler.go | 3 +- .../use-case/main-use-case/encounter/case.go | 275 ++++++++++++++++++ .../main-use-case/encounter/helper.go | 29 ++ .../use-case/main-use-case/encounter/lib.go | 149 ++++++++++ .../encounter/middleware-runner.go | 103 +++++++ .../main-use-case/encounter/middleware.go | 9 + .../main-use-case/encounter/tycovar.go | 44 +++ 8 files changed, 682 insertions(+), 1 deletion(-) create mode 100644 internal/interface/main-handler/encounter/handler.go create mode 100644 internal/use-case/main-use-case/encounter/case.go create mode 100644 internal/use-case/main-use-case/encounter/helper.go create mode 100644 internal/use-case/main-use-case/encounter/lib.go create mode 100644 internal/use-case/main-use-case/encounter/middleware-runner.go create mode 100644 internal/use-case/main-use-case/encounter/middleware.go create mode 100644 internal/use-case/main-use-case/encounter/tycovar.go diff --git a/internal/interface/main-handler/encounter/handler.go b/internal/interface/main-handler/encounter/handler.go new file mode 100644 index 00000000..01350b87 --- /dev/null +++ b/internal/interface/main-handler/encounter/handler.go @@ -0,0 +1,71 @@ +package encounter + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/encounter" + u "simrs-vx/internal/use-case/main-use-case/encounter" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 3b6c0c47..87c17f91 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -6,6 +6,7 @@ import ( /******************** main / transaction ********************/ auth "simrs-vx/internal/interface/main-handler/authentication" counter "simrs-vx/internal/interface/main-handler/counter" + encounter "simrs-vx/internal/interface/main-handler/encounter" medicicinemix "simrs-vx/internal/interface/main-handler/medicine-mix" medicicinemixitem "simrs-vx/internal/interface/main-handler/medicine-mix-item" practiceschedule "simrs-vx/internal/interface/main-handler/practice-schedule" @@ -88,12 +89,12 @@ func SetRoutes() http.Handler { r.HandleFunc("/", home.Home) r.HandleFunc("POST /v1/authentication/login", auth.Login) - // r.HandleFunc("POST /v1/authentication/logout", auth.Logout) hk.Route("POST /v1/authentication/logout", r, auth.GuardMW, auth.Logout) hc.RegCrud(r, "/v1/practice-schedule", practiceschedule.O) hc.RegCrud(r, "/v1/counter", counter.O) hc.RegCrud(r, "/v1/medicine-mix", medicicinemix.O) hc.RegCrud(r, "/v1/medicine-mix-item", medicicinemixitem.O) + hc.RegCrud(r, "/v1/encounter", encounter.O) /******************** actor ********************/ hk.GroupRoutes("/v1/user", r, hk.MapHandlerFunc{ diff --git a/internal/use-case/main-use-case/encounter/case.go b/internal/use-case/main-use-case/encounter/case.go new file mode 100644 index 00000000..32c630f7 --- /dev/null +++ b/internal/use-case/main-use-case/encounter/case.go @@ -0,0 +1,275 @@ +package encounter + +import ( + e "simrs-vx/internal/domain/main-entities/encounter" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "encounter" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Encounter{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Encounter + var dataList []e.Encounter + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Encounter + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Encounter + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Encounter + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/encounter/helper.go b/internal/use-case/main-use-case/encounter/helper.go new file mode 100644 index 00000000..ede229f4 --- /dev/null +++ b/internal/use-case/main-use-case/encounter/helper.go @@ -0,0 +1,29 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package encounter + +import ( + e "simrs-vx/internal/domain/main-entities/encounter" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Patient_Id = inputSrc.Patient_Id + data.RegisteredAt = inputSrc.RegisteredAt + data.Class_Code = inputSrc.Class_Code + data.Unit_Id = inputSrc.Unit_Id + data.VisitDate = inputSrc.VisitDate + data.Assignment_Doctor_Id = inputSrc.Assignment_Doctor_Id + data.Responsible_Doctor_Id = inputSrc.Responsible_Doctor_Id + data.DischardeMethod_Code = inputSrc.DischardeMethod_Code + data.RefSource_Name = inputSrc.RefSource_Name +} diff --git a/internal/use-case/main-use-case/encounter/lib.go b/internal/use-case/main-use-case/encounter/lib.go new file mode 100644 index 00000000..dec500de --- /dev/null +++ b/internal/use-case/main-use-case/encounter/lib.go @@ -0,0 +1,149 @@ +package encounter + +import ( + e "simrs-vx/internal/domain/main-entities/encounter" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Encounter, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Encounter{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Encounter, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Encounter{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.Encounter{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Encounter, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Encounter{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func DeleteData(data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/encounter/middleware-runner.go b/internal/use-case/main-use-case/encounter/middleware-runner.go new file mode 100644 index 00000000..1448a7af --- /dev/null +++ b/internal/use-case/main-use-case/encounter/middleware-runner.go @@ -0,0 +1,103 @@ +package encounter + +import ( + e "simrs-vx/internal/domain/main-entities/encounter" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/main-use-case/encounter/middleware.go b/internal/use-case/main-use-case/encounter/middleware.go new file mode 100644 index 00000000..8a047d33 --- /dev/null +++ b/internal/use-case/main-use-case/encounter/middleware.go @@ -0,0 +1,9 @@ +package encounter + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/encounter/tycovar.go b/internal/use-case/main-use-case/encounter/tycovar.go new file mode 100644 index 00000000..17890a1b --- /dev/null +++ b/internal/use-case/main-use-case/encounter/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package encounter + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/encounter" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Encounter, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Encounter, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Encounter, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw From 9c49b90bb6939173fe97627b0de85424d2cdb9dd Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 14 Oct 2025 13:23:58 +0700 Subject: [PATCH 02/30] feat (encounter): update entity and adjust --- .../domain/main-entities/encounter/dto.go | 24 +++++++++++++++++++ .../domain/main-entities/encounter/entity.go | 6 ++--- .../main-use-case/encounter/helper.go | 6 +++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/internal/domain/main-entities/encounter/dto.go b/internal/domain/main-entities/encounter/dto.go index 608d26dd..93685899 100644 --- a/internal/domain/main-entities/encounter/dto.go +++ b/internal/domain/main-entities/encounter/dto.go @@ -4,8 +4,10 @@ import ( "time" ecore "simrs-vx/internal/domain/base-entities/core" + evs "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" ea "simrs-vx/internal/domain/main-entities/appointment" ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/employee" ep "simrs-vx/internal/domain/main-entities/patient" es "simrs-vx/internal/domain/main-entities/specialist" ess "simrs-vx/internal/domain/main-entities/subspecialist" @@ -25,7 +27,13 @@ type CreateDto struct { Specialist_Id *uint16 `json:"specialist_id"` Subspecialist_Id *uint16 `json:"subspecialist_id"` VisitDate time.Time `json:"visitDate"` + PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code" gorm:"size:10"` + InsuranceCompany_Id *uint `json:"insuranceCompany_id"` + Member_Number *string `json:"memberNumber" validate:"maxLength=20"` + Ref_Number *string `json:"refNumber" validate:"maxLength=20"` + Trx_Number *string `json:"trxNumber" validate:"maxLength=20"` Appointment_Doctor_Id *uint `json:"appointment_doctor_id"` + Adm_Employee_Id *uint `json:"adm_employee_id"` Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` RefSource_Name *string `json:"refSource_name" validate:"maxLength=100"` Appointment_Id *uint `json:"appointment_id"` @@ -97,10 +105,17 @@ type ResponseDto struct { Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` Unit *eu.Unit `json:"unit,omitempty"` VisitDate time.Time `json:"visitDate"` + PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code"` + InsuranceCompany_Id *uint `json:"insuranceCompany_id"` + Member_Number *string `json:"memberNumber"` + Ref_Number *string `json:"refNumber"` + Trx_Number *string `json:"trxNumber"` Appointment_Doctor_Id *uint `json:"assignment_doctor_id"` Appointment_Doctor *ed.Doctor `json:"assignment_doctor,omitempty"` Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` Responsible_Doctor *ed.Doctor `json:"responsible_doctor,omitempty"` + Adm_Employee_Id *uint `json:"adm_employee_id"` + Adm_Employee *ee.Employee `json:"adm_employee,omitempty"` DischargeMethod_Code *ere.DischargeMethodCode `json:"dischargeMethod_code"` RefSource_Name *string `json:"refSource_name"` Appointment_Id *uint `json:"appointment_id"` @@ -110,6 +125,7 @@ type ResponseDto struct { AdmDischargeEducation *string `json:"admDischargeEducation"` DischargeReason *string `json:"dischargeReason"` Status_Code erc.DataStatusCode `json:"status_code"` + VclaimSep *evs.VClaimSep `json:"vclaimSep,omitempty"` } func (d Encounter) ToResponse() ResponseDto { @@ -125,8 +141,15 @@ func (d Encounter) ToResponse() ResponseDto { Subspecialist_Id: d.Subspecialist_Id, Subspecialist: d.Subspecialist, VisitDate: d.VisitDate, + PaymentMethod_Code: d.PaymentMethod_Code, + InsuranceCompany_Id: d.InsuranceCompany_Id, + Member_Number: d.Member_Number, + Ref_Number: d.Ref_Number, + Trx_Number: d.Trx_Number, Appointment_Doctor_Id: d.Appointment_Doctor_Id, Appointment_Doctor: d.Appointment_Doctor, + Adm_Employee_Id: d.Adm_Employee_Id, + Adm_Employee: d.Adm_Employee, Responsible_Doctor_Id: d.Responsible_Doctor_Id, Responsible_Doctor: d.Responsible_Doctor, DischargeMethod_Code: d.DischargeMethod_Code, @@ -138,6 +161,7 @@ func (d Encounter) ToResponse() ResponseDto { AdmDischargeEducation: d.AdmDischargeEducation, DischargeReason: d.DischargeReason, Status_Code: d.Status_Code, + VclaimSep: d.VclaimSep, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/encounter/entity.go b/internal/domain/main-entities/encounter/entity.go index 321e838f..50080a37 100644 --- a/internal/domain/main-entities/encounter/entity.go +++ b/internal/domain/main-entities/encounter/entity.go @@ -32,14 +32,14 @@ type Encounter struct { VisitDate time.Time `json:"visitDate"` PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code" gorm:"size:10"` InsuranceCompany_Id *uint `json:"insuranceCompany_id"` + InsuranceCompany *ei.InsuranceCompany `json:"insuranceCompany,omitempty" gorm:"foreignKey:InsuranceCompany_Id;references:Id"` Member_Number *string `json:"memberNumber" gorm:"unique;size:20"` Ref_Number *string `json:"refNumber" gorm:"unique;size:20"` Trx_Number *string `json:"trxNumber" gorm:"unique;size:20"` - InsuranceCompany *ei.InsuranceCompany `json:"insuranceCompany,omitempty" gorm:"foreignKey:InsuranceCompany_Id;references:Id"` Appointment_Doctor_Id *uint `json:"appointment_doctor_id"` Appointment_Doctor *ed.Doctor `json:"appointment_doctor,omitempty" gorm:"foreignKey:Appointment_Doctor_Id;references:Id"` - Adm_Employee_Id *uint `json:"admEmployee_id"` - Adm_Employee *ee.Employee `json:"admEmployee,omitempty" gorm:"foreignKey:Adm_Employee_Id;references:Id"` + Adm_Employee_Id *uint `json:"adm_employee_id"` + Adm_Employee *ee.Employee `json:"adm_employee,omitempty" gorm:"foreignKey:Adm_Employee_Id;references:Id"` Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` Responsible_Doctor *ed.Doctor `json:"responsible_doctor,omitempty" gorm:"foreignKey:Responsible_Doctor_Id;references:Id"` DischargeMethod_Code *ere.DischargeMethodCode `json:"dischargeMethod_code" gorm:"size:16"` diff --git a/internal/use-case/main-use-case/encounter/helper.go b/internal/use-case/main-use-case/encounter/helper.go index 8d9ea44d..9b8f5999 100644 --- a/internal/use-case/main-use-case/encounter/helper.go +++ b/internal/use-case/main-use-case/encounter/helper.go @@ -55,7 +55,13 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) { data.Specialist_Id = inputSrc.Specialist_Id data.Subspecialist_Id = inputSrc.Subspecialist_Id data.VisitDate = inputSrc.VisitDate + data.PaymentMethod_Code = inputSrc.PaymentMethod_Code + data.InsuranceCompany_Id = inputSrc.InsuranceCompany_Id + data.Member_Number = inputSrc.Member_Number + data.Ref_Number = inputSrc.Ref_Number + data.Trx_Number = inputSrc.Trx_Number data.Appointment_Doctor_Id = inputSrc.Appointment_Doctor_Id + data.Adm_Employee_Id = inputSrc.Adm_Employee_Id data.Responsible_Doctor_Id = inputSrc.Responsible_Doctor_Id data.RefSource_Name = inputSrc.RefSource_Name data.Appointment_Id = inputSrc.Appointment_Id From 3976f74556ff6e223ba5dc4115f5ad6b17e524dc Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 14 Oct 2025 13:34:20 +0700 Subject: [PATCH 03/30] wip --- .../bpjs-entities/vclaim-sep-hist/dto.go | 66 +++++ .../bpjs-entities/vclaim-sep-print/dto.go | 60 ++++ .../domain/bpjs-entities/vclaim-sep/dto.go | 61 ++++ .../use-case/bpjs-use-case/vclaim-sep/case.go | 279 ++++++++++++++++++ .../bpjs-use-case/vclaim-sep/helper.go | 25 ++ .../use-case/bpjs-use-case/vclaim-sep/lib.go | 140 +++++++++ .../vclaim-sep/middleware-runner.go | 103 +++++++ .../bpjs-use-case/vclaim-sep/middleware.go | 9 + .../bpjs-use-case/vclaim-sep/tycovar.go | 44 +++ 9 files changed, 787 insertions(+) create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep/case.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep/helper.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep/lib.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep/middleware-runner.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep/middleware.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep/tycovar.go diff --git a/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go b/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go index 778154cb..83a389cc 100644 --- a/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go @@ -1 +1,67 @@ package vclaimsephist + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + RequestPayload *string `json:"requestPayload"` + ResponseBody *string `json:"responseBody"` + Message *string `json:"message"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + RequestPayload *string `json:"requestPayload"` + ResponseBody *string `json:"responseBody"` + Message *string `json:"message"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + RequestPayload *string `json:"requestPayload"` + ResponseBody *string `json:"responseBody"` + Message *string `json:"message"` +} + +func (d VClaimSepHist) ToResponse() ResponseDto { + resp := ResponseDto{ + RequestPayload: d.RequestPayload, + ResponseBody: d.ResponseBody, + Message: d.Message, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []VClaimSepHist) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/bpjs-entities/vclaim-sep-print/dto.go b/internal/domain/bpjs-entities/vclaim-sep-print/dto.go index b975dd96..b3383ff9 100644 --- a/internal/domain/bpjs-entities/vclaim-sep-print/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep-print/dto.go @@ -1 +1,61 @@ package vclaimsepprint + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + VclaimSep_Number *string `json:"vclaimSep_number"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + VclaimSep_Number *string `json:"vclaimSep_number"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + VclaimSep_Number *string `json:"vclaimSep_number"` + Counter *uint `json:"counter"` +} + +func (d VClaimSepPrint) ToResponse() ResponseDto { + resp := ResponseDto{ + VclaimSep_Number: d.VclaimSep_Number, + Counter: d.Counter, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []VClaimSepPrint) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/bpjs-entities/vclaim-sep/dto.go b/internal/domain/bpjs-entities/vclaim-sep/dto.go index ce4c6f55..1ea32bff 100644 --- a/internal/domain/bpjs-entities/vclaim-sep/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep/dto.go @@ -1 +1,62 @@ package vclaimsep + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Number *string `json:"number" validate:"maxLength=19"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Number *string `json:"number"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Number *string `json:"number"` +} + +func (d VClaimSep) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Number: d.Number, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []VClaimSep) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/case.go b/internal/use-case/bpjs-use-case/vclaim-sep/case.go new file mode 100644 index 00000000..01a47536 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep/case.go @@ -0,0 +1,279 @@ +package vclaimsep + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "vclaim-sep" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.VclaimSep{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if err := createItem(&input, &event, tx); err != nil { + return err + } + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.VclaimSep + var dataList []e.VclaimSep + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); 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 ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.VclaimSep + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.VclaimSep + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.VclaimSep + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/helper.go b/internal/use-case/bpjs-use-case/vclaim-sep/helper.go new file mode 100644 index 00000000..8e5949dd --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep/helper.go @@ -0,0 +1,25 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package vclaimsep + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimSep) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Uom_Code = inputSrc.Uom_Code + data.Item_Id = inputSrc.Item_Id + data.Infra_Id = inputSrc.Infra_Id +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/lib.go b/internal/use-case/bpjs-use-case/vclaim-sep/lib.go new file mode 100644 index 00000000..c80b5c7b --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep/lib.go @@ -0,0 +1,140 @@ +package vclaimsep + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimSep, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.VclaimSep{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.VclaimSep, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.VclaimSep{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.VclaimSep{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimSep, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.VclaimSep{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.VclaimSep, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func DeleteData(data *e.VclaimSep, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/middleware-runner.go b/internal/use-case/bpjs-use-case/vclaim-sep/middleware-runner.go new file mode 100644 index 00000000..dee35276 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep/middleware-runner.go @@ -0,0 +1,103 @@ +package vclaimsep + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.VclaimSep) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.VclaimSep) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSep) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSep) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSep) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go b/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go new file mode 100644 index 00000000..6edc2873 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go @@ -0,0 +1,9 @@ +package vclaimsep + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/tycovar.go b/internal/use-case/bpjs-use-case/vclaim-sep/tycovar.go new file mode 100644 index 00000000..932bc355 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package vclaimsep + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.VclaimSep, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.VclaimSep, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.VclaimSep, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw From 2d813408e47f8271bd78288c4025d48a87a77abe Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 14 Oct 2025 14:25:09 +0700 Subject: [PATCH 04/30] wip --- .../bpjs-entities/vclaim-sep-hist/dto.go | 5 +- .../bpjs-entities/vclaim-sep-print/dto.go | 5 +- .../domain/bpjs-entities/vclaim-sep/dto.go | 10 +- .../domain/main-entities/encounter/dto.go | 2 +- .../bpjs-handler/vclaim-sep/handler.go | 75 +++++ .../bpjs-use-case/vclaim-sep-hist/case.go | 277 ++++++++++++++++++ .../bpjs-use-case/vclaim-sep-hist/helper.go | 23 ++ .../bpjs-use-case/vclaim-sep-hist/lib.go | 140 +++++++++ .../vclaim-sep-hist/middleware-runner.go | 103 +++++++ .../vclaim-sep-hist/middleware.go | 9 + .../bpjs-use-case/vclaim-sep-hist/tycovar.go | 44 +++ .../bpjs-use-case/vclaim-sep-print/case.go | 277 ++++++++++++++++++ .../bpjs-use-case/vclaim-sep-print/helper.go | 21 ++ .../bpjs-use-case/vclaim-sep-print/lib.go | 148 ++++++++++ .../vclaim-sep-print/middleware-runner.go | 103 +++++++ .../vclaim-sep-print/middleware.go | 9 + .../bpjs-use-case/vclaim-sep-print/tycovar.go | 44 +++ .../use-case/bpjs-use-case/vclaim-sep/case.go | 10 +- .../bpjs-use-case/vclaim-sep/helper.go | 7 +- 19 files changed, 1292 insertions(+), 20 deletions(-) create mode 100644 internal/interface/bpjs-handler/vclaim-sep/handler.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-hist/case.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-hist/helper.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-hist/lib.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-hist/middleware-runner.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-hist/middleware.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-hist/tycovar.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-print/case.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-print/helper.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-print/lib.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-print/middleware-runner.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-print/middleware.go create mode 100644 internal/use-case/bpjs-use-case/vclaim-sep-print/tycovar.go diff --git a/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go b/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go index 83a389cc..dc7fce78 100644 --- a/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go @@ -13,6 +13,7 @@ type CreateDto struct { type ReadListDto struct { FilterDto Includes string `json:"includes"` + Sort string `json:"sort"` Pagination ecore.Pagination } @@ -48,7 +49,7 @@ type ResponseDto struct { Message *string `json:"message"` } -func (d VClaimSepHist) ToResponse() ResponseDto { +func (d VclaimSepHist) ToResponse() ResponseDto { resp := ResponseDto{ RequestPayload: d.RequestPayload, ResponseBody: d.ResponseBody, @@ -58,7 +59,7 @@ func (d VClaimSepHist) ToResponse() ResponseDto { return resp } -func ToResponseList(data []VClaimSepHist) []ResponseDto { +func ToResponseList(data []VclaimSepHist) []ResponseDto { resp := make([]ResponseDto, len(data)) for i, u := range data { resp[i] = u.ToResponse() diff --git a/internal/domain/bpjs-entities/vclaim-sep-print/dto.go b/internal/domain/bpjs-entities/vclaim-sep-print/dto.go index b3383ff9..17650e40 100644 --- a/internal/domain/bpjs-entities/vclaim-sep-print/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep-print/dto.go @@ -11,6 +11,7 @@ type CreateDto struct { type ReadListDto struct { FilterDto Includes string `json:"includes"` + Sort string `json:"sort"` Pagination ecore.Pagination } @@ -43,7 +44,7 @@ type ResponseDto struct { Counter *uint `json:"counter"` } -func (d VClaimSepPrint) ToResponse() ResponseDto { +func (d VclaimSepPrint) ToResponse() ResponseDto { resp := ResponseDto{ VclaimSep_Number: d.VclaimSep_Number, Counter: d.Counter, @@ -52,7 +53,7 @@ func (d VClaimSepPrint) ToResponse() ResponseDto { return resp } -func ToResponseList(data []VClaimSepPrint) []ResponseDto { +func ToResponseList(data []VclaimSepPrint) []ResponseDto { resp := make([]ResponseDto, len(data)) for i, u := range data { resp[i] = u.ToResponse() diff --git a/internal/domain/bpjs-entities/vclaim-sep/dto.go b/internal/domain/bpjs-entities/vclaim-sep/dto.go index 1ea32bff..ce62b758 100644 --- a/internal/domain/bpjs-entities/vclaim-sep/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep/dto.go @@ -5,13 +5,15 @@ import ( ) type CreateDto struct { - Encounter_Id *uint `json:"encounter_id"` - Number *string `json:"number" validate:"maxLength=19"` + Encounter_Id *uint `json:"encounter_id"` + Number *string `json:"number" validate:"maxLength=19"` + RequestPayload []byte `json:"requestPayload" validate:"maxLength=1024"` } type ReadListDto struct { FilterDto Includes string `json:"includes"` + Sort string `json:"sort"` Pagination ecore.Pagination } @@ -44,7 +46,7 @@ type ResponseDto struct { Number *string `json:"number"` } -func (d VClaimSep) ToResponse() ResponseDto { +func (d VclaimSep) ToResponse() ResponseDto { resp := ResponseDto{ Encounter_Id: d.Encounter_Id, Number: d.Number, @@ -53,7 +55,7 @@ func (d VClaimSep) ToResponse() ResponseDto { return resp } -func ToResponseList(data []VClaimSep) []ResponseDto { +func ToResponseList(data []VclaimSep) []ResponseDto { resp := make([]ResponseDto, len(data)) for i, u := range data { resp[i] = u.ToResponse() diff --git a/internal/domain/main-entities/encounter/dto.go b/internal/domain/main-entities/encounter/dto.go index 93685899..4d752e9a 100644 --- a/internal/domain/main-entities/encounter/dto.go +++ b/internal/domain/main-entities/encounter/dto.go @@ -125,7 +125,7 @@ type ResponseDto struct { AdmDischargeEducation *string `json:"admDischargeEducation"` DischargeReason *string `json:"dischargeReason"` Status_Code erc.DataStatusCode `json:"status_code"` - VclaimSep *evs.VClaimSep `json:"vclaimSep,omitempty"` + VclaimSep *evs.VclaimSep `json:"vclaimSep,omitempty"` } func (d Encounter) ToResponse() ResponseDto { diff --git a/internal/interface/bpjs-handler/vclaim-sep/handler.go b/internal/interface/bpjs-handler/vclaim-sep/handler.go new file mode 100644 index 00000000..93d87fc8 --- /dev/null +++ b/internal/interface/bpjs-handler/vclaim-sep/handler.go @@ -0,0 +1,75 @@ +package vclaimsep + +import ( + "io" + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + u "simrs-vx/internal/use-case/bpjs-use-case/vclaim-sep" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "failed to read body", http.StatusBadRequest) + return + } + defer r.Body.Close() + + dto.RequestPayload = body + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-hist/case.go b/internal/use-case/bpjs-use-case/vclaim-sep-hist/case.go new file mode 100644 index 00000000..0d2e77d0 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-hist/case.go @@ -0,0 +1,277 @@ +package vclaimsephist + +import ( + "strconv" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "vclaim-sep-hist" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.VclaimSepHist{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.VclaimSepHist + var dataList []e.VclaimSepHist + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); 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 ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.VclaimSepHist + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.VclaimSepHist + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.VclaimSepHist + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-hist/helper.go b/internal/use-case/bpjs-use-case/vclaim-sep-hist/helper.go new file mode 100644 index 00000000..fe13d47c --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-hist/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package vclaimsephist + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimSepHist) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.RequestPayload = inputSrc.RequestPayload + data.ResponseBody = inputSrc.ResponseBody + data.Message = inputSrc.Message +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-hist/lib.go b/internal/use-case/bpjs-use-case/vclaim-sep-hist/lib.go new file mode 100644 index 00000000..13104e36 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-hist/lib.go @@ -0,0 +1,140 @@ +package vclaimsephist + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" + + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimSepHist, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.VclaimSepHist{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.VclaimSepHist, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.VclaimSepHist{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.VclaimSepHist{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimSepHist, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.VclaimSepHist{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.VclaimSepHist, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func DeleteData(data *e.VclaimSepHist, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-hist/middleware-runner.go b/internal/use-case/bpjs-use-case/vclaim-sep-hist/middleware-runner.go new file mode 100644 index 00000000..315a358e --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-hist/middleware-runner.go @@ -0,0 +1,103 @@ +package vclaimsephist + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.VclaimSepHist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.VclaimSepHist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSepHist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSepHist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSepHist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-hist/middleware.go b/internal/use-case/bpjs-use-case/vclaim-sep-hist/middleware.go new file mode 100644 index 00000000..16cf95b9 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-hist/middleware.go @@ -0,0 +1,9 @@ +package vclaimsephist + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-hist/tycovar.go b/internal/use-case/bpjs-use-case/vclaim-sep-hist/tycovar.go new file mode 100644 index 00000000..f525303a --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-hist/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package vclaimsephist + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.VclaimSepHist, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.VclaimSepHist, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.VclaimSepHist, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-print/case.go b/internal/use-case/bpjs-use-case/vclaim-sep-print/case.go new file mode 100644 index 00000000..e1f26e10 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-print/case.go @@ -0,0 +1,277 @@ +package vclaimsepprint + +import ( + "strconv" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-print" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "vclaim-sep-print" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.VclaimSepPrint{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.VclaimSepPrint + var dataList []e.VclaimSepPrint + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); 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 ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.VclaimSepPrint + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.VclaimSepPrint + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.VclaimSepPrint + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-print/helper.go b/internal/use-case/bpjs-use-case/vclaim-sep-print/helper.go new file mode 100644 index 00000000..5a89f7a9 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-print/helper.go @@ -0,0 +1,21 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package vclaimsepprint + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-print" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimSepPrint) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.VclaimSep_Number = inputSrc.VclaimSep_Number +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-print/lib.go b/internal/use-case/bpjs-use-case/vclaim-sep-print/lib.go new file mode 100644 index 00000000..12bdad69 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-print/lib.go @@ -0,0 +1,148 @@ +package vclaimsepprint + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-print" + + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimSepPrint, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.VclaimSepPrint{} + var maxCounter uint + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + err := tx.Model(&data). + Where("VclaimSep_Number = ?", input.VclaimSep_Number). + Select("COALESCE(MAX(Counter), 0)"). + Scan(&maxCounter).Error + if err != nil { + return nil, err + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.VclaimSepPrint, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.VclaimSepPrint{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.VclaimSepPrint{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimSepPrint, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.VclaimSepPrint{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.VclaimSepPrint, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func DeleteData(data *e.VclaimSepPrint, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-print/middleware-runner.go b/internal/use-case/bpjs-use-case/vclaim-sep-print/middleware-runner.go new file mode 100644 index 00000000..47db3773 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-print/middleware-runner.go @@ -0,0 +1,103 @@ +package vclaimsepprint + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-print" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.VclaimSepPrint) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.VclaimSepPrint) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSepPrint) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSepPrint) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSepPrint) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-print/middleware.go b/internal/use-case/bpjs-use-case/vclaim-sep-print/middleware.go new file mode 100644 index 00000000..ae857af4 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-print/middleware.go @@ -0,0 +1,9 @@ +package vclaimsepprint + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-print/tycovar.go b/internal/use-case/bpjs-use-case/vclaim-sep-print/tycovar.go new file mode 100644 index 00000000..9566a7e0 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-print/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package vclaimsepprint + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-print" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.VclaimSepPrint, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.VclaimSepPrint, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.VclaimSepPrint, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/case.go b/internal/use-case/bpjs-use-case/vclaim-sep/case.go index 01a47536..84ccd109 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/case.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/case.go @@ -1,9 +1,10 @@ package vclaimsep import ( - e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" "strconv" + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" @@ -34,9 +35,6 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } - if err := createItem(&input, &event, tx); err != nil { - return err - } if resData, err := CreateData(input, &event, tx); err != nil { return err } else { @@ -169,7 +167,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { } func Update(input e.UpdateDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + rdDto := e.ReadDetailDto{Id: input.Id} var data *e.VclaimSep var err error @@ -225,7 +223,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { } func Delete(input e.DeleteDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + rdDto := e.ReadDetailDto{Id: input.Id} var data *e.VclaimSep var err error diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/helper.go b/internal/use-case/bpjs-use-case/vclaim-sep/helper.go index 8e5949dd..7760d854 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/helper.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/helper.go @@ -17,9 +17,6 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimSep) { inputSrc = &inputTemp.CreateDto } - data.Code = inputSrc.Code - data.Name = inputSrc.Name - data.Uom_Code = inputSrc.Uom_Code - data.Item_Id = inputSrc.Item_Id - data.Infra_Id = inputSrc.Infra_Id + data.Encounter_Id = inputSrc.Encounter_Id + data.Number = inputSrc.Number } From d3f441dd56ea55af13ca139e787c205d71cd8fc6 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 14 Oct 2025 14:31:40 +0700 Subject: [PATCH 05/30] wip --- internal/domain/bpjs-entities/vclaim-sep/dto.go | 3 +++ internal/use-case/bpjs-plugin/vclaim-sep/plugin.go | 1 + 2 files changed, 4 insertions(+) create mode 100644 internal/use-case/bpjs-plugin/vclaim-sep/plugin.go diff --git a/internal/domain/bpjs-entities/vclaim-sep/dto.go b/internal/domain/bpjs-entities/vclaim-sep/dto.go index ce62b758..e8b6871b 100644 --- a/internal/domain/bpjs-entities/vclaim-sep/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep/dto.go @@ -2,12 +2,15 @@ package vclaimsep import ( ecore "simrs-vx/internal/domain/base-entities/core" + evsh "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" ) type CreateDto struct { Encounter_Id *uint `json:"encounter_id"` Number *string `json:"number" validate:"maxLength=19"` RequestPayload []byte `json:"requestPayload" validate:"maxLength=1024"` + + VclaimSepHist evsh.CreateDto } type ReadListDto struct { diff --git a/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go b/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go new file mode 100644 index 00000000..ce4c6f55 --- /dev/null +++ b/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go @@ -0,0 +1 @@ +package vclaimsep From 3e4ce7d1bf1dbf54156c3881cea6a45e06fccec1 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 14 Oct 2025 16:39:28 +0700 Subject: [PATCH 06/30] almost done, not tested yet --- cmd/bpjs-api/config.yml-example | 5 +- .../bpjs-entities/vclaim-sep-hist/dto.go | 6 +- .../domain/bpjs-entities/vclaim-sep/dto.go | 10 +++- internal/infra/bpjs/bpjs.go | 9 +++ internal/infra/bpjs/tycovar.go | 7 +++ .../interface/bpjs-handler/bpjs-handler.go | 26 +++++++-- .../bpjs-handler/vclaim-sep-hist/handler.go | 22 +++++++ .../bpjs-handler/vclaim-sep-print/handler.go | 23 ++++++++ .../bpjs-handler/vclaim-sep/handler.go | 46 +++++++-------- .../use-case/bpjs-plugin/vclaim-sep/plugin.go | 57 +++++++++++++++++++ .../bpjs-plugin/vclaim-sep/tycovar.go | 12 ++++ .../bpjs-use-case/vclaim-sep-hist/helper.go | 6 +- .../use-case/bpjs-use-case/vclaim-sep/case.go | 15 ++++- .../use-case/bpjs-use-case/vclaim-sep/lib.go | 9 ++- .../bpjs-use-case/vclaim-sep/middleware.go | 16 ++++-- 15 files changed, 221 insertions(+), 48 deletions(-) create mode 100644 internal/infra/bpjs/bpjs.go create mode 100644 internal/infra/bpjs/tycovar.go create mode 100644 internal/interface/bpjs-handler/vclaim-sep-hist/handler.go create mode 100644 internal/interface/bpjs-handler/vclaim-sep-print/handler.go create mode 100644 internal/use-case/bpjs-plugin/vclaim-sep/tycovar.go diff --git a/cmd/bpjs-api/config.yml-example b/cmd/bpjs-api/config.yml-example index f131a725..60b1644c 100644 --- a/cmd/bpjs-api/config.yml-example +++ b/cmd/bpjs-api/config.yml-example @@ -63,4 +63,7 @@ bpjsCfg: corsCfg: allowedOrigins: - http://example.com - allowedMethod: \ No newline at end of file + allowedMethod: + +bpjsCfg: + baseUrl: \ No newline at end of file diff --git a/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go b/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go index dc7fce78..d58eaf6e 100644 --- a/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep-hist/dto.go @@ -5,9 +5,9 @@ import ( ) type CreateDto struct { - RequestPayload *string `json:"requestPayload"` - ResponseBody *string `json:"responseBody"` - Message *string `json:"message"` + RequestPayload string `json:"requestPayload"` + ResponseBody string `json:"responseBody"` + Message string `json:"message"` } type ReadListDto struct { diff --git a/internal/domain/bpjs-entities/vclaim-sep/dto.go b/internal/domain/bpjs-entities/vclaim-sep/dto.go index e8b6871b..8a174688 100644 --- a/internal/domain/bpjs-entities/vclaim-sep/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep/dto.go @@ -25,7 +25,8 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint `json:"id"` + Id uint `json:"id"` + Number *string `json:"number"` } type UpdateDto struct { @@ -34,7 +35,8 @@ type UpdateDto struct { } type DeleteDto struct { - Id uint `json:"id"` + Id uint `json:"id"` + Number *string `json:"number"` } type MetaDto struct { @@ -65,3 +67,7 @@ func ToResponseList(data []VclaimSep) []ResponseDto { } return resp } + +func (c CreateDto) IsMessageSuccess() bool { + return c.VclaimSepHist.Message == "Sukses" +} diff --git a/internal/infra/bpjs/bpjs.go b/internal/infra/bpjs/bpjs.go new file mode 100644 index 00000000..68d1b877 --- /dev/null +++ b/internal/infra/bpjs/bpjs.go @@ -0,0 +1,9 @@ +package bpjs + +import ( + a "github.com/karincake/apem" +) + +func SetConfig() { + a.ParseSingleCfg(&O) +} diff --git a/internal/infra/bpjs/tycovar.go b/internal/infra/bpjs/tycovar.go new file mode 100644 index 00000000..54e45a63 --- /dev/null +++ b/internal/infra/bpjs/tycovar.go @@ -0,0 +1,7 @@ +package bpjs + +var O BpjsCfg = BpjsCfg{} + +type BpjsCfg struct { + BaseUrl string `yaml:"baseUrl"` +} diff --git a/internal/interface/bpjs-handler/bpjs-handler.go b/internal/interface/bpjs-handler/bpjs-handler.go index a3d86116..7f34b7cc 100644 --- a/internal/interface/bpjs-handler/bpjs-handler.go +++ b/internal/interface/bpjs-handler/bpjs-handler.go @@ -4,22 +4,24 @@ import ( "net/http" /******************** main / transaction ********************/ + vclaimsep "simrs-vx/internal/interface/bpjs-handler/vclaim-sep" + vclaimsephist "simrs-vx/internal/interface/bpjs-handler/vclaim-sep-hist" + vclaimsepprint "simrs-vx/internal/interface/bpjs-handler/vclaim-sep-print" /******************** actor ********************/ /******************** external ********************/ a "github.com/karincake/apem" + hk "github.com/karincake/hongkue" /******************** infra ********************/ + ibpjs "simrs-vx/internal/infra/bpjs" gs "simrs-vx/internal/infra/gorm-setting" - minio "simrs-vx/internal/infra/minio" - ssdb "simrs-vx/internal/infra/ss-db" /******************** pkg ********************/ cmw "simrs-vx/pkg/cors-manager-mw" lh "simrs-vx/pkg/lang-helper" handlerlogger "simrs-vx/pkg/middleware/handler-logger" - mh "simrs-vx/pkg/minio-helper" zlc "simrs-vx/pkg/zerolog-ctx" /******************** sources ********************/ @@ -33,10 +35,8 @@ func SetRoutes() http.Handler { ///// a.RegisterExtCall(gs.Adjust) a.RegisterExtCall(zlc.Adjust) - a.RegisterExtCall(ssdb.SetInstance) a.RegisterExtCall(lh.Populate) - a.RegisterExtCall(minio.Connect) - a.RegisterExtCall(mh.I.SetClient) + a.RegisterExtCall(ibpjs.SetConfig) a.RegisterExtCall(validation.RegisterValidation) r := http.NewServeMux() @@ -44,6 +44,20 @@ func SetRoutes() http.Handler { /******************** Main ********************/ r.HandleFunc("/", home.Home) + hk.GroupRoutes("/v1/vclaim-sep", r, hk.MapHandlerFunc{ + "POST /": vclaimsep.O.Create, + "PATCH /{id}": vclaimsep.O.Update, + "DELETE /{id}": vclaimsep.O.Delete, + }) + + hk.GroupRoutes("/v1/vclaim-sep-hist", r, hk.MapHandlerFunc{ + "GET /": vclaimsephist.O.GetList, + }) + + hk.GroupRoutes("/v1/vclaim-sep-print", r, hk.MapHandlerFunc{ + "POST /": vclaimsepprint.O.Create, + }) + /******************** actor ********************/ /******************** sources ********************/ diff --git a/internal/interface/bpjs-handler/vclaim-sep-hist/handler.go b/internal/interface/bpjs-handler/vclaim-sep-hist/handler.go new file mode 100644 index 00000000..73c2c4e2 --- /dev/null +++ b/internal/interface/bpjs-handler/vclaim-sep-hist/handler.go @@ -0,0 +1,22 @@ +package vclaimsephist + +import ( + "net/http" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" + u "simrs-vx/internal/use-case/bpjs-use-case/vclaim-sep-hist" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/bpjs-handler/vclaim-sep-print/handler.go b/internal/interface/bpjs-handler/vclaim-sep-print/handler.go new file mode 100644 index 00000000..838bc65b --- /dev/null +++ b/internal/interface/bpjs-handler/vclaim-sep-print/handler.go @@ -0,0 +1,23 @@ +package vclaimsepprint + +import ( + "net/http" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-print" + u "simrs-vx/internal/use-case/bpjs-use-case/vclaim-sep-print" + + rw "github.com/karincake/risoles" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/bpjs-handler/vclaim-sep/handler.go b/internal/interface/bpjs-handler/vclaim-sep/handler.go index 93d87fc8..c90cf9fc 100644 --- a/internal/interface/bpjs-handler/vclaim-sep/handler.go +++ b/internal/interface/bpjs-handler/vclaim-sep/handler.go @@ -5,7 +5,6 @@ import ( "net/http" rw "github.com/karincake/risoles" - sf "github.com/karincake/semprit" e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" u "simrs-vx/internal/use-case/bpjs-use-case/vclaim-sep" @@ -29,27 +28,27 @@ func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { rw.DataResponse(w, res, err) } -func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { - dto := e.ReadListDto{} - sf.UrlQueryParam(&dto, *r.URL) - res, err := u.ReadList(dto) - rw.DataResponse(w, res, err) -} +// func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { +// dto := e.ReadListDto{} +// sf.UrlQueryParam(&dto, *r.URL) +// res, err := u.ReadList(dto) +// rw.DataResponse(w, res, err) +// } -func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { - id := rw.ValidateInt(w, "id", r.PathValue("id")) - if id <= 0 { - return - } - dto := e.ReadDetailDto{} - dto.Id = uint(id) - res, err := u.ReadDetail(dto) - rw.DataResponse(w, res, err) -} +// func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { +// id := rw.ValidateInt(w, "id", r.PathValue("id")) +// if id <= 0 { +// return +// } +// dto := e.ReadDetailDto{} +// dto.Id = uint(id) +// res, err := u.ReadDetail(dto) +// rw.DataResponse(w, res, err) +// } func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { - id := rw.ValidateInt(w, "id", r.PathValue("id")) - if id <= 0 { + number := rw.ValidateString(w, "number", r.PathValue("number")) + if number <= "" { return } @@ -57,19 +56,18 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } - dto.Id = uint(id) + dto.Number = &number res, err := u.Update(dto) rw.DataResponse(w, res, err) } func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { - id := rw.ValidateInt(w, "id", r.PathValue("id")) - if id <= 0 { + number := rw.ValidateString(w, "number", r.PathValue("number")) + if number <= "" { return } - dto := e.DeleteDto{} - dto.Id = uint(id) + dto.Number = &number res, err := u.Delete(dto) rw.DataResponse(w, res, err) } diff --git a/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go b/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go index ce4c6f55..fd18763f 100644 --- a/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go +++ b/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go @@ -1 +1,58 @@ package vclaimsep + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + + ibpjs "simrs-vx/internal/infra/bpjs" + + "gorm.io/gorm" +) + +func CreateSep(input *e.CreateDto, data *e.VclaimSep, tx *gorm.DB) error { + req, err := http.NewRequest("POST", ibpjs.O.BaseUrl+"/sep", bytes.NewReader(input.RequestPayload)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + var vresp vclaimResponse + if err := json.Unmarshal(body, &vresp); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } + + msg := vresp.MetaData.Message + + if err := json.Unmarshal(body, data); err != nil { + return fmt.Errorf("failed to unmarshal into VclaimSep: %w", err) + } + + // Save request/response details in DTO for further use + input.VclaimSepHist.RequestPayload = string(input.RequestPayload) + input.VclaimSepHist.ResponseBody = string(body) + input.VclaimSepHist.Message = msg + input.Number = func() *string { + number := "" + if vresp.Response != nil && vresp.Response.Sep != nil { + number = vresp.Response.Sep.NoSep + } + return &number + }() + + return nil +} diff --git a/internal/use-case/bpjs-plugin/vclaim-sep/tycovar.go b/internal/use-case/bpjs-plugin/vclaim-sep/tycovar.go new file mode 100644 index 00000000..f057726e --- /dev/null +++ b/internal/use-case/bpjs-plugin/vclaim-sep/tycovar.go @@ -0,0 +1,12 @@ +package vclaimsep + +type vclaimResponse struct { + MetaData struct { + Message string `json:"message"` + } `json:"metaData"` + Response *struct { + Sep *struct { + NoSep string `json:"noSep"` + } `json:"sep"` + } `json:"response"` +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-hist/helper.go b/internal/use-case/bpjs-use-case/vclaim-sep-hist/helper.go index fe13d47c..038983bb 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep-hist/helper.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep-hist/helper.go @@ -17,7 +17,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimSepHist) { inputSrc = &inputTemp.CreateDto } - data.RequestPayload = inputSrc.RequestPayload - data.ResponseBody = inputSrc.ResponseBody - data.Message = inputSrc.Message + data.RequestPayload = &inputSrc.RequestPayload + data.ResponseBody = &inputSrc.ResponseBody + data.Message = &inputSrc.Message } diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/case.go b/internal/use-case/bpjs-use-case/vclaim-sep/case.go index 84ccd109..ac72d648 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/case.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/case.go @@ -4,6 +4,9 @@ import ( "strconv" e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + // evsh "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" + + uvsh "simrs-vx/internal/use-case/bpjs-use-case/vclaim-sep-hist" dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" @@ -35,6 +38,14 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + if _, err := uvsh.CreateData(input.VclaimSepHist, &event, tx); err != nil { + return err + } + + if !input.IsMessageSuccess() { + return nil + } + if resData, err := CreateData(input, &event, tx); err != nil { return err } else { @@ -167,7 +178,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { } func Update(input e.UpdateDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: input.Id} + rdDto := e.ReadDetailDto{Number: input.Number} var data *e.VclaimSep var err error @@ -223,7 +234,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { } func Delete(input e.DeleteDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: input.Id} + rdDto := e.ReadDetailDto{Number: input.Number} var data *e.VclaimSep var err error diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/lib.go b/internal/use-case/bpjs-use-case/vclaim-sep/lib.go index c80b5c7b..817c357c 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/lib.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/lib.go @@ -81,7 +81,14 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e tx = dg.I } - if err := tx.First(&data, input.Id).Error; err != nil { + if input.Number != nil { + tx = tx.Where("\"Number\" = ?", *input.Number) + } + if input.Id != 0 { + tx = tx.Where("\"Id\" = ?", input.Id) + } + + if err := tx.First(&data).Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { return nil, processedErr } diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go b/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go index 6edc2873..1ad0a853 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go @@ -1,9 +1,13 @@ package vclaimsep +import ( + pvs "simrs-vx/internal/use-case/bpjs-plugin/vclaim-sep" +) + // example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +func init() { + createPreMw = append(createPreMw, + createMw{Name: "create-sep", Func: pvs.CreateSep}, + ) + +} From 7871998c98c687ab77d96d7bd44915e71230d042 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 15 Oct 2025 15:49:05 +0700 Subject: [PATCH 07/30] feat (reference): done --- .vscode/launch.json | 7 + cmd/bpjs-api/main.go | 2 +- .../domain/bpjs-entities/reference/dto.go | 22 ++++ .../domain/bpjs-entities/reference/entity.go | 23 ++++ internal/infra/bpjs/bpjs.go | 5 + .../interface/bpjs-handler/bpjs-handler.go | 13 ++ .../bpjs-handler/reference/handler.go | 123 ++++++++++++++++++ .../bpjs-handler/vclaim-sep/handler.go | 4 +- .../use-case/bpjs-plugin/reference/helper.go | 35 +++++ .../use-case/bpjs-plugin/reference/plugin.go | 37 ++++++ .../use-case/bpjs-use-case/reference/case.go | 56 ++++++++ .../bpjs-use-case/reference/helper.go | 22 ++++ .../use-case/bpjs-use-case/reference/lib.go | 1 + .../reference/middleware-runner.go | 42 ++++++ .../bpjs-use-case/reference/middleware.go | 12 ++ .../bpjs-use-case/reference/tycovar.go | 23 ++++ 16 files changed, 424 insertions(+), 3 deletions(-) create mode 100644 internal/domain/bpjs-entities/reference/dto.go create mode 100644 internal/domain/bpjs-entities/reference/entity.go create mode 100644 internal/interface/bpjs-handler/reference/handler.go create mode 100644 internal/use-case/bpjs-plugin/reference/helper.go create mode 100644 internal/use-case/bpjs-plugin/reference/plugin.go create mode 100644 internal/use-case/bpjs-use-case/reference/case.go create mode 100644 internal/use-case/bpjs-use-case/reference/helper.go create mode 100644 internal/use-case/bpjs-use-case/reference/lib.go create mode 100644 internal/use-case/bpjs-use-case/reference/middleware-runner.go create mode 100644 internal/use-case/bpjs-use-case/reference/middleware.go create mode 100644 internal/use-case/bpjs-use-case/reference/tycovar.go diff --git a/.vscode/launch.json b/.vscode/launch.json index 7098c42c..fddb0d29 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,6 +7,13 @@ "mode": "auto", "program": "${workspaceFolder}/cmd/main-api" }, + { + "name": "Launch Package bpjs API", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/bpjs-api" + }, { "name": "Launch Package migratioon", "type": "go", diff --git a/cmd/bpjs-api/main.go b/cmd/bpjs-api/main.go index 74be3afd..e1cb2468 100644 --- a/cmd/bpjs-api/main.go +++ b/cmd/bpjs-api/main.go @@ -6,7 +6,7 @@ import ( l "github.com/karincake/apem/logger-zerolog" m "github.com/karincake/apem/ms-redis" - h "simrs-vx/internal/interface/main-handler" + h "simrs-vx/internal/interface/bpjs-handler" ) func main() { diff --git a/internal/domain/bpjs-entities/reference/dto.go b/internal/domain/bpjs-entities/reference/dto.go new file mode 100644 index 00000000..9be2ab5b --- /dev/null +++ b/internal/domain/bpjs-entities/reference/dto.go @@ -0,0 +1,22 @@ +package reference + +type ReadListDto struct { + ReferenceType ReferenceType `json:"-"` + PathValue1 string `json:"-"` + PathValue2 string `json:"-"` + PathValue3 string `json:"-"` +} + +type ReferenceType string + +const ( + RTProvince ReferenceType = "province" + RTDistrict ReferenceType = "district" + RTCities ReferenceType = "cities" + RTDiagnose ReferenceType = "diagnose" + RTDiagnosePrb ReferenceType = "diagnose-prb" + RTMedicinePrb ReferenceType = "medicine-prb" + RTUnit ReferenceType = "unit" + RTHealthcare ReferenceType = "healthcare" + RTDoctor ReferenceType = "doctor" +) diff --git a/internal/domain/bpjs-entities/reference/entity.go b/internal/domain/bpjs-entities/reference/entity.go new file mode 100644 index 00000000..bfcbb66e --- /dev/null +++ b/internal/domain/bpjs-entities/reference/entity.go @@ -0,0 +1,23 @@ +package reference + +type Response struct { + MetaData MetaData `json:"metaData"` + Response *CodeNameList `json:"response"` // pointer to handle possible null +} + +type MetaData struct { + Code string `json:"code"` + Message string `json:"message"` +} + +type CodeNameList struct { + List []CodeName `json:"list,omitempty"` + Diagnosa []CodeName `json:"diagnosa,omitempty"` + Poli []CodeName `json:"poli,omitempty"` + Faskes []CodeName `json:"faskes,omitempty"` +} + +type CodeName struct { + Kode string `json:"kode"` + Nama string `json:"nama"` +} diff --git a/internal/infra/bpjs/bpjs.go b/internal/infra/bpjs/bpjs.go index 68d1b877..36935c74 100644 --- a/internal/infra/bpjs/bpjs.go +++ b/internal/infra/bpjs/bpjs.go @@ -2,8 +2,13 @@ package bpjs import ( a "github.com/karincake/apem" + lo "github.com/karincake/apem/loggero" ) func SetConfig() { a.ParseSingleCfg(&O) + if O.BaseUrl == "" { + panic("config bpjs base url empty") + } + lo.I.Println("Bpjs config loaded, status: DONE!!") } diff --git a/internal/interface/bpjs-handler/bpjs-handler.go b/internal/interface/bpjs-handler/bpjs-handler.go index 7f34b7cc..5d5673df 100644 --- a/internal/interface/bpjs-handler/bpjs-handler.go +++ b/internal/interface/bpjs-handler/bpjs-handler.go @@ -4,6 +4,7 @@ import ( "net/http" /******************** main / transaction ********************/ + reference "simrs-vx/internal/interface/bpjs-handler/reference" vclaimsep "simrs-vx/internal/interface/bpjs-handler/vclaim-sep" vclaimsephist "simrs-vx/internal/interface/bpjs-handler/vclaim-sep-hist" vclaimsepprint "simrs-vx/internal/interface/bpjs-handler/vclaim-sep-print" @@ -58,6 +59,18 @@ func SetRoutes() http.Handler { "POST /": vclaimsepprint.O.Create, }) + hk.GroupRoutes("/v1/reference", r, hk.MapHandlerFunc{ + "GET /province": reference.GetListProvince, + "GET /regency/{provinceCode}": reference.GetListCities, + "GET /district/{regencyCode}": reference.GetListDistrict, + "GET /diagnose/{keyword}": reference.GetListDiagnose, + "GET /diagnose-prb": reference.GetListDiagnosePrb, + "GET /medicine-prb/{keyword}": reference.GetListMedicinePrb, + "GET /unit/{unitCode}": reference.GetListUnit, + "GET /healthcare/{healthcare}/{healthcareType}": reference.GetListHealthcare, + "GET /responsible-doctor/{serviceType}/{serviceDate}/{specialistCode}": reference.GetListDoctor, + }) + /******************** actor ********************/ /******************** sources ********************/ diff --git a/internal/interface/bpjs-handler/reference/handler.go b/internal/interface/bpjs-handler/reference/handler.go new file mode 100644 index 00000000..d452ebc4 --- /dev/null +++ b/internal/interface/bpjs-handler/reference/handler.go @@ -0,0 +1,123 @@ +package reference + +import ( + "net/http" + e "simrs-vx/internal/domain/bpjs-entities/reference" + u "simrs-vx/internal/use-case/bpjs-use-case/reference" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" +) + +func GetListProvince(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + dto.ReferenceType = e.RTProvince + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListCities(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue := rw.ValidateString(w, "provinceCode", r.PathValue("provinceCode")) + if pValue == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "provinceCode is required"}, nil) + } + dto.ReferenceType = e.RTCities + dto.PathValue1 = pValue + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListDistrict(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue := rw.ValidateString(w, "regencyCode", r.PathValue("regencyCode")) + if pValue == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "regencyCode is required"}, nil) + } + dto.ReferenceType = e.RTDistrict + dto.PathValue1 = pValue + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListDiagnose(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue := rw.ValidateString(w, "keyword", r.PathValue("keyword")) + if pValue == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "keyword is required"}, nil) + } + dto.ReferenceType = e.RTDiagnose + dto.PathValue1 = pValue + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListDiagnosePrb(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + dto.ReferenceType = e.RTDiagnosePrb + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListMedicinePrb(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue := rw.ValidateString(w, "keyword", r.PathValue("keyword")) + if pValue == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "keyword is required"}, nil) + } + dto.ReferenceType = e.RTMedicinePrb + dto.PathValue1 = pValue + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListUnit(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue := rw.ValidateString(w, "unitCode", r.PathValue("unitCode")) + if pValue == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "unitCode is required"}, nil) + } + dto.ReferenceType = e.RTUnit + dto.PathValue1 = pValue + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListHealthcare(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue1 := rw.ValidateString(w, "healthcare", r.PathValue("healthcare")) + if pValue1 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "healthcare is required"}, nil) + } + pValue2 := rw.ValidateString(w, "healthcareType", r.PathValue("healthcareType")) + if pValue2 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "healthcareType is required"}, nil) + } + dto.ReferenceType = e.RTHealthcare + dto.PathValue1 = pValue1 + dto.PathValue2 = pValue2 + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListDoctor(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue1 := rw.ValidateString(w, "serviceType", r.PathValue("serviceType")) + if pValue1 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "serviceType is required"}, nil) + } + pValue2 := rw.ValidateString(w, "serviceDate", r.PathValue("serviceDate")) + if pValue2 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "serviceDate is required"}, nil) + } + pValue3 := rw.ValidateString(w, "specialistCode", r.PathValue("specialistCode")) + if pValue3 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "specialistCode is required"}, nil) + } + dto.PathValue1 = pValue1 + dto.PathValue2 = pValue2 + dto.PathValue3 = pValue3 + dto.ReferenceType = e.RTDoctor + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/bpjs-handler/vclaim-sep/handler.go b/internal/interface/bpjs-handler/vclaim-sep/handler.go index c90cf9fc..d40c76e9 100644 --- a/internal/interface/bpjs-handler/vclaim-sep/handler.go +++ b/internal/interface/bpjs-handler/vclaim-sep/handler.go @@ -48,7 +48,7 @@ func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { number := rw.ValidateString(w, "number", r.PathValue("number")) - if number <= "" { + if number != "" { return } @@ -63,7 +63,7 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { number := rw.ValidateString(w, "number", r.PathValue("number")) - if number <= "" { + if number != "" { return } dto := e.DeleteDto{} diff --git a/internal/use-case/bpjs-plugin/reference/helper.go b/internal/use-case/bpjs-plugin/reference/helper.go new file mode 100644 index 00000000..834ba4e5 --- /dev/null +++ b/internal/use-case/bpjs-plugin/reference/helper.go @@ -0,0 +1,35 @@ +package reference + +import ( + "fmt" + e "simrs-vx/internal/domain/bpjs-entities/reference" + ibpjs "simrs-vx/internal/infra/bpjs" +) + +func endpointMapper(input *e.ReadListDto) string { + switch input.ReferenceType { + case e.RTProvince: + return ibpjs.O.BaseUrl + "provinces" + case e.RTCities: + return ibpjs.O.BaseUrl + "cities/" + input.PathValue1 + case e.RTDistrict: + return ibpjs.O.BaseUrl + "districts/" + input.PathValue1 + case e.RTDiagnose: + return ibpjs.O.BaseUrl + "diagnosa/" + input.PathValue1 + case e.RTDiagnosePrb: + return ibpjs.O.BaseUrl + "diagnosaprb" + case e.RTMedicinePrb: + return ibpjs.O.BaseUrl + "obatprb/" + input.PathValue1 + case e.RTUnit: + if input.QParam == "" { + return ibpjs.O.BaseUrl + "referensi/poli" + } + return ibpjs.O.BaseUrl + "referensi/poli/" + input.QParam + case e.RTHealthcare: + return fmt.Sprintf("%sreferensi/faskes?faskes=%s&jenis-faskes=%s", ibpjs.O.BaseUrl, input.PathValue1, input.PathValue2) + case e.RTDoctor: + return fmt.Sprintf("%sreferensi/dokter-dpjp?jenis-pelayanan=%s&tgl-pelayanan=%s&kode-spesialis=%s", ibpjs.O.BaseUrl, input.PathValue1, input.PathValue2, input.PathValue3) + default: + return "" + } +} diff --git a/internal/use-case/bpjs-plugin/reference/plugin.go b/internal/use-case/bpjs-plugin/reference/plugin.go new file mode 100644 index 00000000..f4d4098e --- /dev/null +++ b/internal/use-case/bpjs-plugin/reference/plugin.go @@ -0,0 +1,37 @@ +package reference + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + e "simrs-vx/internal/domain/bpjs-entities/reference" + + "gorm.io/gorm" +) + +func ReadList(input *e.ReadListDto, data *e.Response, tx *gorm.DB) error { + endpoint := endpointMapper(input) + req, err := http.NewRequest("GET", endpoint, nil) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if err := json.Unmarshal(body, &data); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } + + return nil +} diff --git a/internal/use-case/bpjs-use-case/reference/case.go b/internal/use-case/bpjs-use-case/reference/case.go new file mode 100644 index 00000000..d753a955 --- /dev/null +++ b/internal/use-case/bpjs-use-case/reference/case.go @@ -0,0 +1,56 @@ +package reference + +import ( + e "simrs-vx/internal/domain/bpjs-entities/reference" + // evsh "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" + + dg "github.com/karincake/apem/db-gorm-pg" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "reference" + +func ReadList(input e.ReadListDto) (*e.Response, error) { + var data e.Response + // var dataList []e.Response + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, &data); err != nil { + return err + } + + // if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + // return err + // } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, &data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &data, nil +} diff --git a/internal/use-case/bpjs-use-case/reference/helper.go b/internal/use-case/bpjs-use-case/reference/helper.go new file mode 100644 index 00000000..5f664320 --- /dev/null +++ b/internal/use-case/bpjs-use-case/reference/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package reference + +// import ( +// e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" +// ) + +// func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimSep) { +// var inputSrc *e.CreateDto +// if inputT, ok := any(input).(*e.CreateDto); ok { +// inputSrc = inputT +// } else { +// inputTemp := any(input).(*e.UpdateDto) +// inputSrc = &inputTemp.CreateDto +// } + +// data.Encounter_Id = inputSrc.Encounter_Id +// data.Number = inputSrc.Number +// } diff --git a/internal/use-case/bpjs-use-case/reference/lib.go b/internal/use-case/bpjs-use-case/reference/lib.go new file mode 100644 index 00000000..bccaf5df --- /dev/null +++ b/internal/use-case/bpjs-use-case/reference/lib.go @@ -0,0 +1 @@ +package reference diff --git a/internal/use-case/bpjs-use-case/reference/middleware-runner.go b/internal/use-case/bpjs-use-case/reference/middleware-runner.go new file mode 100644 index 00000000..0d13c083 --- /dev/null +++ b/internal/use-case/bpjs-use-case/reference/middleware-runner.go @@ -0,0 +1,42 @@ +package reference + +import ( + e "simrs-vx/internal/domain/bpjs-entities/reference" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Response) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/bpjs-use-case/reference/middleware.go b/internal/use-case/bpjs-use-case/reference/middleware.go new file mode 100644 index 00000000..f7680ffd --- /dev/null +++ b/internal/use-case/bpjs-use-case/reference/middleware.go @@ -0,0 +1,12 @@ +package reference + +import ( + pr "simrs-vx/internal/use-case/bpjs-plugin/reference" +) + +func init() { + readListPreMw = append(readListPreMw, + readListMw{Name: "readList-reference", Func: pr.ReadList}, + ) + +} diff --git a/internal/use-case/bpjs-use-case/reference/tycovar.go b/internal/use-case/bpjs-use-case/reference/tycovar.go new file mode 100644 index 00000000..51df4160 --- /dev/null +++ b/internal/use-case/bpjs-use-case/reference/tycovar.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package reference + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/reference" +) + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Response, tx *gorm.DB) error +} + +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. From 7f279d8c8ab929a286f12a3021b377938f231543 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 15 Oct 2025 15:52:25 +0700 Subject: [PATCH 08/30] adjust after qParam removed --- internal/use-case/bpjs-plugin/reference/helper.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/internal/use-case/bpjs-plugin/reference/helper.go b/internal/use-case/bpjs-plugin/reference/helper.go index 834ba4e5..3e87089b 100644 --- a/internal/use-case/bpjs-plugin/reference/helper.go +++ b/internal/use-case/bpjs-plugin/reference/helper.go @@ -21,10 +21,7 @@ func endpointMapper(input *e.ReadListDto) string { case e.RTMedicinePrb: return ibpjs.O.BaseUrl + "obatprb/" + input.PathValue1 case e.RTUnit: - if input.QParam == "" { - return ibpjs.O.BaseUrl + "referensi/poli" - } - return ibpjs.O.BaseUrl + "referensi/poli/" + input.QParam + return ibpjs.O.BaseUrl + "referensi/poli/" + input.PathValue1 case e.RTHealthcare: return fmt.Sprintf("%sreferensi/faskes?faskes=%s&jenis-faskes=%s", ibpjs.O.BaseUrl, input.PathValue1, input.PathValue2) case e.RTDoctor: From 609119c3060ae9435e675d16d0595076bdb6f06f Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 16 Oct 2025 08:39:22 +0700 Subject: [PATCH 09/30] add person-insurance --- internal/domain/main-entities/patient/dto.go | 18 +- .../main-entities/person-insurance/dto.go | 74 +++++ .../interface/main-handler/main-handler.go | 2 + .../main-handler/person-insurance/handler.go | 71 +++++ .../use-case/main-use-case/patient/case.go | 16 + .../main-use-case/person-insurance/case.go | 276 ++++++++++++++++++ .../main-use-case/person-insurance/helper.go | 24 ++ .../main-use-case/person-insurance/lib.go | 193 ++++++++++++ .../person-insurance/middleware-runner.go | 103 +++++++ .../person-insurance/middleware.go | 9 + .../main-use-case/person-insurance/tycovar.go | 44 +++ 11 files changed, 822 insertions(+), 8 deletions(-) create mode 100644 internal/interface/main-handler/person-insurance/handler.go create mode 100644 internal/use-case/main-use-case/person-insurance/case.go create mode 100644 internal/use-case/main-use-case/person-insurance/helper.go create mode 100644 internal/use-case/main-use-case/person-insurance/lib.go create mode 100644 internal/use-case/main-use-case/person-insurance/middleware-runner.go create mode 100644 internal/use-case/main-use-case/person-insurance/middleware.go create mode 100644 internal/use-case/main-use-case/person-insurance/tycovar.go diff --git a/internal/domain/main-entities/patient/dto.go b/internal/domain/main-entities/patient/dto.go index d1d32324..1374eb97 100644 --- a/internal/domain/main-entities/patient/dto.go +++ b/internal/domain/main-entities/patient/dto.go @@ -8,6 +8,7 @@ import ( ep "simrs-vx/internal/domain/main-entities/person" epa "simrs-vx/internal/domain/main-entities/person-address" epc "simrs-vx/internal/domain/main-entities/person-contact" + epi "simrs-vx/internal/domain/main-entities/person-insurance" epr "simrs-vx/internal/domain/main-entities/person-relative" erc "simrs-vx/internal/domain/references/common" @@ -15,14 +16,15 @@ import ( ) type CreateDto struct { - Person_Id *uint `json:"-"` - Person *ep.UpdateDto `json:"person"` - NewBornStatus bool `json:"newBornStatus"` - PersonAddresses []epa.UpdateDto `json:"personAddresses"` - PersonContacts []epc.UpdateDto `json:"personContacts"` - PersonRelatives []epr.UpdateDto `json:"personRelatives"` - RegisteredAt *time.Time `json:"registeredAt"` - Status_Code erc.ActiveStatusCode `json:"status_code" validate:"maxLength=10"` + Person_Id *uint `json:"-"` + Person *ep.UpdateDto `json:"person"` + NewBornStatus bool `json:"newBornStatus"` + PersonAddresses []epa.UpdateDto `json:"personAddresses"` + PersonContacts []epc.UpdateDto `json:"personContacts"` + PersonRelatives []epr.UpdateDto `json:"personRelatives"` + PersonInsurances []epi.UpdateDto `json:"personInsurances"` + RegisteredAt *time.Time `json:"registeredAt"` + Status_Code erc.ActiveStatusCode `json:"status_code" validate:"maxLength=10"` } type ReadListDto struct { diff --git a/internal/domain/main-entities/person-insurance/dto.go b/internal/domain/main-entities/person-insurance/dto.go index 5a2ee2a1..e811023d 100644 --- a/internal/domain/main-entities/person-insurance/dto.go +++ b/internal/domain/main-entities/person-insurance/dto.go @@ -1 +1,75 @@ package personinsurance + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/insurance-company" +) + +type CreateDto struct { + Person_Id uint `json:"person_id"` + InsuranceCompany_Id *uint `json:"insurance_id"` + Ref_Number *string `json:"ref_number" gorm:"unique;size:20"` + DefaultStatus *bool `json:"default_status" gorm:"uniqueIndex:idx_person_insurance"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Sort string `json:"sort"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Person_Id *uint `json:"person-id"` + InsuranceCompany_Id *uint `json:"insurance-company-id"` + Ref_Number *string `json:"ref-number"` + DefaultStatus *bool `json:"default-status"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Person_Id *uint `json:"person_id"` + InsuranceCompany_Id *uint `json:"insuranceCompany_id"` + InsuranceCompany *ei.InsuranceCompany `json:"insuranceCompany,omitempty"` + Ref_Number *string `json:"ref_number"` + DefaultStatus *bool `json:"defaultStatus"` +} + +func (d PersonInsurance) ToResponse() ResponseDto { + resp := ResponseDto{ + Person_Id: d.Person_Id, + InsuranceCompany_Id: d.InsuranceCompany_Id, + InsuranceCompany: d.InsuranceCompany, + Ref_Number: d.Ref_Number, + DefaultStatus: d.DefaultStatus, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []PersonInsurance) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 63448f21..7af27137 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -38,6 +38,7 @@ import ( person "simrs-vx/internal/interface/main-handler/person" personaddress "simrs-vx/internal/interface/main-handler/person-address" personcontact "simrs-vx/internal/interface/main-handler/person-contact" + personinsurance "simrs-vx/internal/interface/main-handler/person-insurance" pharmacist "simrs-vx/internal/interface/main-handler/pharmacist" user "simrs-vx/internal/interface/main-handler/user" @@ -239,6 +240,7 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/person", person.O) hc.RegCrud(r, "/v1/person-address", personaddress.O) hc.RegCrud(r, "/v1/person-contact", personcontact.O) + hc.RegCrud(r, "/v1/person-insurance", personinsurance.O) hc.RegCrud(r, "/v1/employee", employee.O) hc.RegCrud(r, "/v1/doctor", doctor.O) hc.RegCrud(r, "/v1/nurse", nurse.O) diff --git a/internal/interface/main-handler/person-insurance/handler.go b/internal/interface/main-handler/person-insurance/handler.go new file mode 100644 index 00000000..d5e42f7b --- /dev/null +++ b/internal/interface/main-handler/person-insurance/handler.go @@ -0,0 +1,71 @@ +package personinsurance + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/person-insurance" + u "simrs-vx/internal/use-case/main-use-case/person-insurance" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/main-use-case/patient/case.go b/internal/use-case/main-use-case/patient/case.go index 9736ee09..fd17d7fb 100644 --- a/internal/use-case/main-use-case/patient/case.go +++ b/internal/use-case/main-use-case/patient/case.go @@ -9,6 +9,7 @@ import ( upe "simrs-vx/internal/use-case/main-use-case/person" upa "simrs-vx/internal/use-case/main-use-case/person-address" upc "simrs-vx/internal/use-case/main-use-case/person-contact" + upi "simrs-vx/internal/use-case/main-use-case/person-insurance" upr "simrs-vx/internal/use-case/main-use-case/person-relative" ere "simrs-vx/internal/domain/references/encounter" @@ -47,6 +48,7 @@ func Create(input e.CreateDto) (*d.Data, error) { } else { input.Person_Id = person_id } + for idx := range input.PersonAddresses { input.PersonAddresses[idx].Person_Id = *input.Person_Id } @@ -68,6 +70,13 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + for idx := range input.PersonInsurances { + input.PersonInsurances[idx].Person_Id = *input.Person_Id + } + if err := upi.CreateOrUpdateBatch(input.PersonInsurances, &event, tx); err != nil { + return err + } + if resData, err := CreateData(input, &event, tx); err != nil { return err } else { @@ -252,6 +261,13 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } + for idx := range input.PersonInsurances { + input.PersonInsurances[idx].Person_Id = *input.Person_Id + } + if err := upi.CreateOrUpdateBatch(input.PersonInsurances, &event, tx); err != nil { + return err + } + if err := UpdateData(input, data, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/person-insurance/case.go b/internal/use-case/main-use-case/person-insurance/case.go new file mode 100644 index 00000000..e9595137 --- /dev/null +++ b/internal/use-case/main-use-case/person-insurance/case.go @@ -0,0 +1,276 @@ +package personinsurance + +import ( + e "simrs-vx/internal/domain/main-entities/person-insurance" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "person-insurance" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.PersonInsurance{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.PersonInsurance + var dataList []e.PersonInsurance + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err + } + + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); 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 ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.PersonInsurance + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err + } + + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.PersonInsurance + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.PersonInsurance + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + if err := DeleteData(data, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/person-insurance/helper.go b/internal/use-case/main-use-case/person-insurance/helper.go new file mode 100644 index 00000000..e9352119 --- /dev/null +++ b/internal/use-case/main-use-case/person-insurance/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package personinsurance + +import ( + e "simrs-vx/internal/domain/main-entities/person-insurance" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.PersonInsurance) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Person_Id = &inputSrc.Person_Id + data.InsuranceCompany_Id = inputSrc.InsuranceCompany_Id + data.Ref_Number = inputSrc.Ref_Number + data.DefaultStatus = inputSrc.DefaultStatus +} diff --git a/internal/use-case/main-use-case/person-insurance/lib.go b/internal/use-case/main-use-case/person-insurance/lib.go new file mode 100644 index 00000000..86c6dc83 --- /dev/null +++ b/internal/use-case/main-use-case/person-insurance/lib.go @@ -0,0 +1,193 @@ +package personinsurance + +import ( + e "simrs-vx/internal/domain/main-entities/person-insurance" + + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.PersonInsurance, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.PersonInsurance{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.PersonInsurance, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.PersonInsurance{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.PersonInsurance{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.PersonInsurance, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.PersonInsurance{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateData(input e.UpdateDto, data *e.PersonInsurance, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func DeleteData(data *e.PersonInsurance, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func CreateOrUpdateBatch(input []e.UpdateDto, event *pl.Event, tx ...*gorm.DB) error { + var data = make([]e.PersonInsurance, len(input)) + var dbx *gorm.DB + if len(tx) > 0 { + dbx = tx[0] + } else { + dbx = dg.I + } + + for idx := range input { + if input[idx].Id > 0 { + if err := dbx.Where("\"Id\" = ? AND \"Person_Id\" = ?", input[idx].Id, input[idx].Person_Id).First(&data[idx]).Error; err == nil { + setData(&input[idx], &data[idx]) + if err := dbx.Save(&data[idx]).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + } else if err != gorm.ErrRecordNotFound { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + continue + } + setData(&input[idx], &data[idx]) + if err := dbx.Create(&data[idx]).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + } + + return nil +} diff --git a/internal/use-case/main-use-case/person-insurance/middleware-runner.go b/internal/use-case/main-use-case/person-insurance/middleware-runner.go new file mode 100644 index 00000000..ce9ff869 --- /dev/null +++ b/internal/use-case/main-use-case/person-insurance/middleware-runner.go @@ -0,0 +1,103 @@ +package personinsurance + +import ( + e "simrs-vx/internal/domain/main-entities/person-insurance" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.PersonInsurance) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.PersonInsurance) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.PersonInsurance) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.PersonInsurance) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.PersonInsurance) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/main-use-case/person-insurance/middleware.go b/internal/use-case/main-use-case/person-insurance/middleware.go new file mode 100644 index 00000000..a190f067 --- /dev/null +++ b/internal/use-case/main-use-case/person-insurance/middleware.go @@ -0,0 +1,9 @@ +package personinsurance + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/person-insurance/tycovar.go b/internal/use-case/main-use-case/person-insurance/tycovar.go new file mode 100644 index 00000000..2cc94930 --- /dev/null +++ b/internal/use-case/main-use-case/person-insurance/tycovar.go @@ -0,0 +1,44 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package personinsurance + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/person-insurance" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.PersonInsurance, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.PersonInsurance, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.PersonInsurance, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw From b4a433450451953d246bae033b49ba24b22936f6 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 16 Oct 2025 08:55:07 +0700 Subject: [PATCH 10/30] feat (encounter): fix naming dto conventioon --- internal/domain/main-entities/encounter/dto.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/domain/main-entities/encounter/dto.go b/internal/domain/main-entities/encounter/dto.go index 4d752e9a..7062d92a 100644 --- a/internal/domain/main-entities/encounter/dto.go +++ b/internal/domain/main-entities/encounter/dto.go @@ -29,9 +29,9 @@ type CreateDto struct { VisitDate time.Time `json:"visitDate"` PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code" gorm:"size:10"` InsuranceCompany_Id *uint `json:"insuranceCompany_id"` - Member_Number *string `json:"memberNumber" validate:"maxLength=20"` - Ref_Number *string `json:"refNumber" validate:"maxLength=20"` - Trx_Number *string `json:"trxNumber" validate:"maxLength=20"` + Member_Number *string `json:"member_number" validate:"maxLength=20"` + Ref_Number *string `json:"ref_number" validate:"maxLength=20"` + Trx_Number *string `json:"trx_number" validate:"maxLength=20"` Appointment_Doctor_Id *uint `json:"appointment_doctor_id"` Adm_Employee_Id *uint `json:"adm_employee_id"` Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` @@ -49,7 +49,7 @@ type FilterDto struct { Patient_Id *uint `json:"patient-id"` Patient *ep.Patient `json:"patient,omitempty"` RegisteredAt *time.Time `json:"registeredAt"` - Class_Code ere.EncounterClassCode `json:"class_code" validate:"maxLength=10"` + Class_Code ere.EncounterClassCode `json:"class-code" validate:"maxLength=10"` Unit_Id *uint `json:"unit-id"` Specialist_Id *uint16 `json:"specialist-id"` Subspecialist_Id *uint16 `json:"subspecialist-id"` @@ -107,9 +107,9 @@ type ResponseDto struct { VisitDate time.Time `json:"visitDate"` PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code"` InsuranceCompany_Id *uint `json:"insuranceCompany_id"` - Member_Number *string `json:"memberNumber"` - Ref_Number *string `json:"refNumber"` - Trx_Number *string `json:"trxNumber"` + Member_Number *string `json:"member_number"` + Ref_Number *string `json:"ref_number"` + Trx_Number *string `json:"trx_number"` Appointment_Doctor_Id *uint `json:"assignment_doctor_id"` Appointment_Doctor *ed.Doctor `json:"assignment_doctor,omitempty"` Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` From c009a34f5e7d15a46afb6f1c89a6eb0d4f3565c3 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 16 Oct 2025 09:50:40 +0700 Subject: [PATCH 11/30] member, nik ok, bpjs tested but failed from 3rd party --- internal/domain/bpjs-entities/member/dto.go | 14 ++++ .../domain/bpjs-entities/member/entity.go | 78 +++++++++++++++++++ .../interface/bpjs-handler/bpjs-handler.go | 6 ++ .../interface/bpjs-handler/member/handler.go | 45 +++++++++++ .../bpjs-handler/reference/handler.go | 1 + .../use-case/bpjs-plugin/member/helper.go | 18 +++++ .../use-case/bpjs-plugin/member/plugin.go | 37 +++++++++ .../use-case/bpjs-use-case/member/case.go | 50 ++++++++++++ .../bpjs-use-case/member/middleware-runner.go | 42 ++++++++++ .../bpjs-use-case/member/middleware.go | 12 +++ .../use-case/bpjs-use-case/member/tycovar.go | 18 +++++ .../use-case/bpjs-use-case/reference/case.go | 6 -- .../bpjs-use-case/reference/helper.go | 22 ------ .../use-case/bpjs-use-case/reference/lib.go | 1 - 14 files changed, 321 insertions(+), 29 deletions(-) create mode 100644 internal/domain/bpjs-entities/member/dto.go create mode 100644 internal/domain/bpjs-entities/member/entity.go create mode 100644 internal/interface/bpjs-handler/member/handler.go create mode 100644 internal/use-case/bpjs-plugin/member/helper.go create mode 100644 internal/use-case/bpjs-plugin/member/plugin.go create mode 100644 internal/use-case/bpjs-use-case/member/case.go create mode 100644 internal/use-case/bpjs-use-case/member/middleware-runner.go create mode 100644 internal/use-case/bpjs-use-case/member/middleware.go create mode 100644 internal/use-case/bpjs-use-case/member/tycovar.go delete mode 100644 internal/use-case/bpjs-use-case/reference/helper.go delete mode 100644 internal/use-case/bpjs-use-case/reference/lib.go diff --git a/internal/domain/bpjs-entities/member/dto.go b/internal/domain/bpjs-entities/member/dto.go new file mode 100644 index 00000000..e61a9f74 --- /dev/null +++ b/internal/domain/bpjs-entities/member/dto.go @@ -0,0 +1,14 @@ +package member + +type ReadListDto struct { + ReferenceType ReferenceType `json:"-"` + PathValue1 string `json:"-"` + PathValue2 string `json:"-"` +} + +type ReferenceType string + +const ( + RTNik ReferenceType = "nik" + RTBpjs ReferenceType = "bpjs" +) diff --git a/internal/domain/bpjs-entities/member/entity.go b/internal/domain/bpjs-entities/member/entity.go new file mode 100644 index 00000000..b6c4f0d7 --- /dev/null +++ b/internal/domain/bpjs-entities/member/entity.go @@ -0,0 +1,78 @@ +package member + +type Response struct { + MetaData *MetaData `json:"metaData"` + Response *BPJSDataRes `json:"response"` +} + +type MetaData struct { + Code string `json:"code"` + Message string `json:"message"` +} + +type BPJSDataRes struct { + Peserta *Peserta `json:"peserta"` +} + +type Peserta struct { + Cob *COB `json:"cob"` + HakKelas *HakKelas `json:"hakKelas"` + Informasi *Informasi `json:"informasi"` + JenisPeserta *JenisPeserta `json:"jenisPeserta"` + Mr *MR `json:"mr"` + Nama *string `json:"nama"` + Nik *string `json:"nik"` + NoKartu *string `json:"noKartu"` + Pisa *string `json:"pisa"` + ProvUmum *ProvUmum `json:"provUmum"` + Sex *string `json:"sex"` + StatusPeserta *StatusPeserta `json:"statusPeserta"` + TglCetakKartu *string `json:"tglCetakKartu"` + TglLahir *string `json:"tglLahir"` + TglTAT *string `json:"tglTAT"` + TglTMT *string `json:"tglTMT"` + Umur *Umur `json:"umur"` +} + +type COB struct { + NmAsuransi *string `json:"nmAsuransi"` + NoAsuransi *string `json:"noAsuransi"` + TglTAT *string `json:"tglTAT"` + TglTMT *string `json:"tglTMT"` +} + +type HakKelas struct { + Keterangan *string `json:"keterangan"` + Kode *string `json:"kode"` +} + +type Informasi struct { + Dinsos *string `json:"dinsos"` + NoSKTM *string `json:"noSKTM"` + ProlanisPRB *string `json:"prolanisPRB"` +} + +type JenisPeserta struct { + Keterangan *string `json:"keterangan"` + Kode *string `json:"kode"` +} + +type MR struct { + NoMR *string `json:"noMR"` + NoTelepon *string `json:"noTelepon"` +} + +type ProvUmum struct { + KdProvider *string `json:"kdProvider"` + NmProvider *string `json:"nmProvider"` +} + +type StatusPeserta struct { + Keterangan *string `json:"keterangan"` + Kode *string `json:"kode"` +} + +type Umur struct { + UmurSaatPelayanan *string `json:"umurSaatPelayanan"` + UmurSekarang *string `json:"umurSekarang"` +} diff --git a/internal/interface/bpjs-handler/bpjs-handler.go b/internal/interface/bpjs-handler/bpjs-handler.go index 5d5673df..b1a2c80a 100644 --- a/internal/interface/bpjs-handler/bpjs-handler.go +++ b/internal/interface/bpjs-handler/bpjs-handler.go @@ -4,6 +4,7 @@ import ( "net/http" /******************** main / transaction ********************/ + member "simrs-vx/internal/interface/bpjs-handler/member" reference "simrs-vx/internal/interface/bpjs-handler/reference" vclaimsep "simrs-vx/internal/interface/bpjs-handler/vclaim-sep" vclaimsephist "simrs-vx/internal/interface/bpjs-handler/vclaim-sep-hist" @@ -71,6 +72,11 @@ func SetRoutes() http.Handler { "GET /responsible-doctor/{serviceType}/{serviceDate}/{specialistCode}": reference.GetListDoctor, }) + hk.GroupRoutes("/v1/member", r, hk.MapHandlerFunc{ + "GET /bpjs/{cardNumber}/{sepDate}": member.GetListByBpjsNumber, + "GET /nik/{nik}/{sepDate}": member.GetListByNik, + }) + /******************** actor ********************/ /******************** sources ********************/ diff --git a/internal/interface/bpjs-handler/member/handler.go b/internal/interface/bpjs-handler/member/handler.go new file mode 100644 index 00000000..80881ee3 --- /dev/null +++ b/internal/interface/bpjs-handler/member/handler.go @@ -0,0 +1,45 @@ +package member + +import ( + "net/http" + + e "simrs-vx/internal/domain/bpjs-entities/member" + u "simrs-vx/internal/use-case/bpjs-use-case/member" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" +) + +func GetListByBpjsNumber(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue1 := rw.ValidateString(w, "cardNumber", r.PathValue("cardNumber")) + if pValue1 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "cardNumber is required"}, nil) + } + pValue2 := rw.ValidateString(w, "sepDate", r.PathValue("sepDate")) + if pValue2 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "sepDate is required"}, nil) + } + dto.ReferenceType = e.RTBpjs + dto.PathValue1 = pValue1 + dto.PathValue2 = pValue2 + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListByNik(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue1 := rw.ValidateString(w, "nik", r.PathValue("nik")) + if pValue1 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "nik is required"}, nil) + } + pValue2 := rw.ValidateString(w, "sepDate", r.PathValue("sepDate")) + if pValue2 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "sepDate is required"}, nil) + } + dto.ReferenceType = e.RTNik + dto.PathValue1 = pValue1 + dto.PathValue2 = pValue2 + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/bpjs-handler/reference/handler.go b/internal/interface/bpjs-handler/reference/handler.go index d452ebc4..fb972af1 100644 --- a/internal/interface/bpjs-handler/reference/handler.go +++ b/internal/interface/bpjs-handler/reference/handler.go @@ -2,6 +2,7 @@ package reference import ( "net/http" + e "simrs-vx/internal/domain/bpjs-entities/reference" u "simrs-vx/internal/use-case/bpjs-use-case/reference" diff --git a/internal/use-case/bpjs-plugin/member/helper.go b/internal/use-case/bpjs-plugin/member/helper.go new file mode 100644 index 00000000..f5e2bc0e --- /dev/null +++ b/internal/use-case/bpjs-plugin/member/helper.go @@ -0,0 +1,18 @@ +package member + +import ( + "fmt" + e "simrs-vx/internal/domain/bpjs-entities/member" + ibpjs "simrs-vx/internal/infra/bpjs" +) + +func endpointMapper(input *e.ReadListDto) string { + switch input.ReferenceType { + case e.RTBpjs: + return fmt.Sprintf("%speserta/nokartu?noKartu=%s&tglpelayanan=%s", ibpjs.O.BaseUrl, input.PathValue1, input.PathValue2) + case e.RTNik: + return fmt.Sprintf("%speserta/nik?nik=%s&tglpelayanan=%s", ibpjs.O.BaseUrl, input.PathValue1, input.PathValue2) + default: + return "" + } +} diff --git a/internal/use-case/bpjs-plugin/member/plugin.go b/internal/use-case/bpjs-plugin/member/plugin.go new file mode 100644 index 00000000..7610a5ac --- /dev/null +++ b/internal/use-case/bpjs-plugin/member/plugin.go @@ -0,0 +1,37 @@ +package member + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + e "simrs-vx/internal/domain/bpjs-entities/member" + + "gorm.io/gorm" +) + +func ReadList(input *e.ReadListDto, data *e.Response, tx *gorm.DB) error { + endpoint := endpointMapper(input) + req, err := http.NewRequest("GET", endpoint, nil) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if err := json.Unmarshal(body, &data); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } + + return nil +} diff --git a/internal/use-case/bpjs-use-case/member/case.go b/internal/use-case/bpjs-use-case/member/case.go new file mode 100644 index 00000000..7c50ea76 --- /dev/null +++ b/internal/use-case/bpjs-use-case/member/case.go @@ -0,0 +1,50 @@ +package member + +import ( + e "simrs-vx/internal/domain/bpjs-entities/member" + + dg "github.com/karincake/apem/db-gorm-pg" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "member" + +func ReadList(input e.ReadListDto) (*e.Response, error) { + var data e.Response + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, &data); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, &data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &data, nil +} diff --git a/internal/use-case/bpjs-use-case/member/middleware-runner.go b/internal/use-case/bpjs-use-case/member/middleware-runner.go new file mode 100644 index 00000000..71061a1b --- /dev/null +++ b/internal/use-case/bpjs-use-case/member/middleware-runner.go @@ -0,0 +1,42 @@ +package member + +import ( + e "simrs-vx/internal/domain/bpjs-entities/member" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Response) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/bpjs-use-case/member/middleware.go b/internal/use-case/bpjs-use-case/member/middleware.go new file mode 100644 index 00000000..e2fd5584 --- /dev/null +++ b/internal/use-case/bpjs-use-case/member/middleware.go @@ -0,0 +1,12 @@ +package member + +import ( + pm "simrs-vx/internal/use-case/bpjs-plugin/member" +) + +func init() { + readListPreMw = append(readListPreMw, + readListMw{Name: "readList-member", Func: pm.ReadList}, + ) + +} diff --git a/internal/use-case/bpjs-use-case/member/tycovar.go b/internal/use-case/bpjs-use-case/member/tycovar.go new file mode 100644 index 00000000..7d04363f --- /dev/null +++ b/internal/use-case/bpjs-use-case/member/tycovar.go @@ -0,0 +1,18 @@ +/* +member is peserta +*/ +package member + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/member" +) + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Response, tx *gorm.DB) error +} + +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. diff --git a/internal/use-case/bpjs-use-case/reference/case.go b/internal/use-case/bpjs-use-case/reference/case.go index d753a955..bc9bb5d6 100644 --- a/internal/use-case/bpjs-use-case/reference/case.go +++ b/internal/use-case/bpjs-use-case/reference/case.go @@ -2,7 +2,6 @@ package reference import ( e "simrs-vx/internal/domain/bpjs-entities/reference" - // evsh "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" dg "github.com/karincake/apem/db-gorm-pg" @@ -16,7 +15,6 @@ const source = "reference" func ReadList(input e.ReadListDto) (*e.Response, error) { var data e.Response - // var dataList []e.Response var err error event := pl.Event{ @@ -35,10 +33,6 @@ func ReadList(input e.ReadListDto) (*e.Response, error) { return err } - // if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { - // return err - // } - mwRunner.setMwType(pu.MWTPost) // Run post-middleware if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, &data); err != nil { diff --git a/internal/use-case/bpjs-use-case/reference/helper.go b/internal/use-case/bpjs-use-case/reference/helper.go deleted file mode 100644 index 5f664320..00000000 --- a/internal/use-case/bpjs-use-case/reference/helper.go +++ /dev/null @@ -1,22 +0,0 @@ -/* -DESCRIPTION: -Any functions that are used internally by the use-case -*/ -package reference - -// import ( -// e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" -// ) - -// func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimSep) { -// var inputSrc *e.CreateDto -// if inputT, ok := any(input).(*e.CreateDto); ok { -// inputSrc = inputT -// } else { -// inputTemp := any(input).(*e.UpdateDto) -// inputSrc = &inputTemp.CreateDto -// } - -// data.Encounter_Id = inputSrc.Encounter_Id -// data.Number = inputSrc.Number -// } diff --git a/internal/use-case/bpjs-use-case/reference/lib.go b/internal/use-case/bpjs-use-case/reference/lib.go deleted file mode 100644 index bccaf5df..00000000 --- a/internal/use-case/bpjs-use-case/reference/lib.go +++ /dev/null @@ -1 +0,0 @@ -package reference From 2fb47d0d4856d2503324470214e959734323e1f4 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 16 Oct 2025 11:26:09 +0700 Subject: [PATCH 12/30] monitoring done --- internal/domain/bpjs-entities/member/dto.go | 1 + .../domain/bpjs-entities/monitoring/dto.go | 15 ++++++ .../domain/bpjs-entities/monitoring/entity.go | 43 ++++++++++++++++ .../interface/bpjs-handler/bpjs-handler.go | 6 +++ .../bpjs-handler/monitoring/handler.go | 50 +++++++++++++++++++ .../use-case/bpjs-plugin/monitoring/helper.go | 18 +++++++ .../use-case/bpjs-plugin/monitoring/plugin.go | 37 ++++++++++++++ .../use-case/bpjs-use-case/monitoring/case.go | 50 +++++++++++++++++++ .../monitoring/middleware-runner.go | 42 ++++++++++++++++ .../bpjs-use-case/monitoring/middleware.go | 12 +++++ .../bpjs-use-case/monitoring/tycovar.go | 18 +++++++ 11 files changed, 292 insertions(+) create mode 100644 internal/domain/bpjs-entities/monitoring/dto.go create mode 100644 internal/domain/bpjs-entities/monitoring/entity.go create mode 100644 internal/interface/bpjs-handler/monitoring/handler.go create mode 100644 internal/use-case/bpjs-plugin/monitoring/helper.go create mode 100644 internal/use-case/bpjs-plugin/monitoring/plugin.go create mode 100644 internal/use-case/bpjs-use-case/monitoring/case.go create mode 100644 internal/use-case/bpjs-use-case/monitoring/middleware-runner.go create mode 100644 internal/use-case/bpjs-use-case/monitoring/middleware.go create mode 100644 internal/use-case/bpjs-use-case/monitoring/tycovar.go diff --git a/internal/domain/bpjs-entities/member/dto.go b/internal/domain/bpjs-entities/member/dto.go index e61a9f74..f9c95655 100644 --- a/internal/domain/bpjs-entities/member/dto.go +++ b/internal/domain/bpjs-entities/member/dto.go @@ -4,6 +4,7 @@ type ReadListDto struct { ReferenceType ReferenceType `json:"-"` PathValue1 string `json:"-"` PathValue2 string `json:"-"` + PathValue3 string `json:"-"` } type ReferenceType string diff --git a/internal/domain/bpjs-entities/monitoring/dto.go b/internal/domain/bpjs-entities/monitoring/dto.go new file mode 100644 index 00000000..c5c1e0d1 --- /dev/null +++ b/internal/domain/bpjs-entities/monitoring/dto.go @@ -0,0 +1,15 @@ +package monitoring + +type ReadListDto struct { + ReferenceType ReferenceType `json:"-"` + PathValue1 string `json:"-"` + PathValue2 string `json:"-"` + PathValue3 string `json:"-"` +} + +type ReferenceType string + +const ( + RTVisit ReferenceType = "visit" + RTHist ReferenceType = "hist" +) diff --git a/internal/domain/bpjs-entities/monitoring/entity.go b/internal/domain/bpjs-entities/monitoring/entity.go new file mode 100644 index 00000000..eb604942 --- /dev/null +++ b/internal/domain/bpjs-entities/monitoring/entity.go @@ -0,0 +1,43 @@ +package monitoring + +type Response struct { + MetaData MetaData `json:"metaData"` + Response *BPJSDataRes `json:"response"` +} + +type MetaData struct { + Code string `json:"code"` + Message string `json:"message"` +} + +type BPJSDataRes struct { + Sep []Sep `json:"sep"` + Histori []Histori `json:"histori"` +} + +type Sep struct { + Diagnosa string `json:"diagnosa"` + JnsPelayanan string `json:"jnsPelayanan"` + KelasRawat string `json:"kelasRawat"` + Nama string `json:"nama"` + NoKartu string `json:"noKartu"` + NoSep string `json:"noSep"` + NoRujukan string `json:"noRujukan"` + Poli *string `json:"poli"` + TglPlgSep string `json:"tglPlgSep"` + TglSep string `json:"tglSep"` +} + +type Histori struct { + Diagnosa string `json:"diagnosa"` + JnsPelayanan string `json:"jnsPelayanan"` + KelasRawat *string `json:"kelasRawat"` + NamaPeserta string `json:"namaPeserta"` + NoKartu string `json:"noKartu"` + NoSep string `json:"noSep"` + NoRujukan string `json:"noRujukan"` + Poli string `json:"poli"` + PpkPelayanan string `json:"ppkPelayanan"` + TglPlgSep string `json:"tglPlgSep"` + TglSep string `json:"tglSep"` +} diff --git a/internal/interface/bpjs-handler/bpjs-handler.go b/internal/interface/bpjs-handler/bpjs-handler.go index b1a2c80a..175bb667 100644 --- a/internal/interface/bpjs-handler/bpjs-handler.go +++ b/internal/interface/bpjs-handler/bpjs-handler.go @@ -5,6 +5,7 @@ import ( /******************** main / transaction ********************/ member "simrs-vx/internal/interface/bpjs-handler/member" + monitoring "simrs-vx/internal/interface/bpjs-handler/monitoring" reference "simrs-vx/internal/interface/bpjs-handler/reference" vclaimsep "simrs-vx/internal/interface/bpjs-handler/vclaim-sep" vclaimsephist "simrs-vx/internal/interface/bpjs-handler/vclaim-sep-hist" @@ -77,6 +78,11 @@ func SetRoutes() http.Handler { "GET /nik/{nik}/{sepDate}": member.GetListByNik, }) + hk.GroupRoutes("/v1/monitoring", r, hk.MapHandlerFunc{ + "GET /visit/{date}/{serviceType}": monitoring.GetListVisit, + "GET /hist/{cardNumber}/{startDate}/{endDate}": monitoring.GetListHist, + }) + /******************** actor ********************/ /******************** sources ********************/ diff --git a/internal/interface/bpjs-handler/monitoring/handler.go b/internal/interface/bpjs-handler/monitoring/handler.go new file mode 100644 index 00000000..cf82a5b9 --- /dev/null +++ b/internal/interface/bpjs-handler/monitoring/handler.go @@ -0,0 +1,50 @@ +package monitoring + +import ( + "net/http" + + e "simrs-vx/internal/domain/bpjs-entities/monitoring" + u "simrs-vx/internal/use-case/bpjs-use-case/monitoring" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" +) + +func GetListVisit(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue1 := rw.ValidateString(w, "date", r.PathValue("date")) + if pValue1 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "date is required"}, nil) + } + pValue2 := rw.ValidateString(w, "serviceType", r.PathValue("serviceType")) + if pValue2 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "serviceType is required"}, nil) + } + dto.ReferenceType = e.RTVisit + dto.PathValue1 = pValue1 + dto.PathValue2 = pValue2 + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func GetListHist(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue1 := rw.ValidateString(w, "cardNumber", r.PathValue("cardNumber")) + if pValue1 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "cardNumber is required"}, nil) + } + pValue2 := rw.ValidateString(w, "startDate", r.PathValue("startDate")) + if pValue2 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "startDate is required"}, nil) + } + pValue3 := rw.ValidateString(w, "endDate", r.PathValue("endDate")) + if pValue3 == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "endDate is required"}, nil) + } + dto.ReferenceType = e.RTHist + dto.PathValue1 = pValue1 + dto.PathValue2 = pValue2 + dto.PathValue3 = pValue3 + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/bpjs-plugin/monitoring/helper.go b/internal/use-case/bpjs-plugin/monitoring/helper.go new file mode 100644 index 00000000..8f6d2c88 --- /dev/null +++ b/internal/use-case/bpjs-plugin/monitoring/helper.go @@ -0,0 +1,18 @@ +package monitoring + +import ( + "fmt" + e "simrs-vx/internal/domain/bpjs-entities/monitoring" + ibpjs "simrs-vx/internal/infra/bpjs" +) + +func endpointMapper(input *e.ReadListDto) string { + switch input.ReferenceType { + case e.RTHist: + return fmt.Sprintf("%smonitoring/history/%s?tglawal=%s&tglakhir=%s", ibpjs.O.BaseUrl, input.PathValue1, input.PathValue2, input.PathValue3) + case e.RTVisit: + return fmt.Sprintf("%smonitoring/kunjungan?tglpelayanan=%s&jnspelayanan=%s", ibpjs.O.BaseUrl, input.PathValue1, input.PathValue2) + default: + return "" + } +} diff --git a/internal/use-case/bpjs-plugin/monitoring/plugin.go b/internal/use-case/bpjs-plugin/monitoring/plugin.go new file mode 100644 index 00000000..2450e4e9 --- /dev/null +++ b/internal/use-case/bpjs-plugin/monitoring/plugin.go @@ -0,0 +1,37 @@ +package monitoring + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + e "simrs-vx/internal/domain/bpjs-entities/monitoring" + + "gorm.io/gorm" +) + +func ReadList(input *e.ReadListDto, data *e.Response, tx *gorm.DB) error { + endpoint := endpointMapper(input) + req, err := http.NewRequest("GET", endpoint, nil) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if err := json.Unmarshal(body, &data); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } + + return nil +} diff --git a/internal/use-case/bpjs-use-case/monitoring/case.go b/internal/use-case/bpjs-use-case/monitoring/case.go new file mode 100644 index 00000000..43109cca --- /dev/null +++ b/internal/use-case/bpjs-use-case/monitoring/case.go @@ -0,0 +1,50 @@ +package monitoring + +import ( + e "simrs-vx/internal/domain/bpjs-entities/monitoring" + + dg "github.com/karincake/apem/db-gorm-pg" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "monitoring" + +func ReadList(input e.ReadListDto) (*e.Response, error) { + var data e.Response + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, &data); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, &data); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &data, nil +} diff --git a/internal/use-case/bpjs-use-case/monitoring/middleware-runner.go b/internal/use-case/bpjs-use-case/monitoring/middleware-runner.go new file mode 100644 index 00000000..49bc5efe --- /dev/null +++ b/internal/use-case/bpjs-use-case/monitoring/middleware-runner.go @@ -0,0 +1,42 @@ +package monitoring + +import ( + e "simrs-vx/internal/domain/bpjs-entities/monitoring" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Response) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/bpjs-use-case/monitoring/middleware.go b/internal/use-case/bpjs-use-case/monitoring/middleware.go new file mode 100644 index 00000000..d5e77655 --- /dev/null +++ b/internal/use-case/bpjs-use-case/monitoring/middleware.go @@ -0,0 +1,12 @@ +package monitoring + +import ( + pm "simrs-vx/internal/use-case/bpjs-plugin/monitoring" +) + +func init() { + readListPreMw = append(readListPreMw, + readListMw{Name: "readList-monitoring", Func: pm.ReadList}, + ) + +} diff --git a/internal/use-case/bpjs-use-case/monitoring/tycovar.go b/internal/use-case/bpjs-use-case/monitoring/tycovar.go new file mode 100644 index 00000000..463109c7 --- /dev/null +++ b/internal/use-case/bpjs-use-case/monitoring/tycovar.go @@ -0,0 +1,18 @@ +/* +member is peserta +*/ +package monitoring + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/monitoring" +) + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Response, tx *gorm.DB) error +} + +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. From d4806d90fbc8d688eab9d1453304f56bd2f0fc3b Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 16 Oct 2025 12:16:51 +0700 Subject: [PATCH 13/30] feat (encounter): add flow to insert adm employee --- internal/domain/main-entities/encounter/dto.go | 6 +++++- internal/interface/main-handler/encounter/handler.go | 9 +++++++++ internal/interface/main-handler/main-handler.go | 2 +- internal/use-case/main-use-case/encounter/case.go | 8 ++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/internal/domain/main-entities/encounter/dto.go b/internal/domain/main-entities/encounter/dto.go index 7062d92a..269dccbe 100644 --- a/internal/domain/main-entities/encounter/dto.go +++ b/internal/domain/main-entities/encounter/dto.go @@ -15,6 +15,8 @@ import ( erc "simrs-vx/internal/domain/references/common" ere "simrs-vx/internal/domain/references/encounter" + + pa "simrs-vx/pkg/auth-helper" ) type CreateDto struct { @@ -33,10 +35,12 @@ type CreateDto struct { Ref_Number *string `json:"ref_number" validate:"maxLength=20"` Trx_Number *string `json:"trx_number" validate:"maxLength=20"` Appointment_Doctor_Id *uint `json:"appointment_doctor_id"` - Adm_Employee_Id *uint `json:"adm_employee_id"` + Adm_Employee_Id *uint `json:"-"` Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` RefSource_Name *string `json:"refSource_name" validate:"maxLength=100"` Appointment_Id *uint `json:"appointment_id"` + + pa.AuthInfo } type ReadListDto struct { diff --git a/internal/interface/main-handler/encounter/handler.go b/internal/interface/main-handler/encounter/handler.go index 7484b302..41414394 100644 --- a/internal/interface/main-handler/encounter/handler.go +++ b/internal/interface/main-handler/encounter/handler.go @@ -10,6 +10,10 @@ import ( e "simrs-vx/internal/domain/main-entities/encounter" u "simrs-vx/internal/use-case/main-use-case/encounter" + + pa "simrs-vx/pkg/auth-helper" + + d "github.com/karincake/dodol" ) type myBase struct{} @@ -17,10 +21,15 @@ type myBase struct{} var O myBase func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } dto := e.CreateDto{} if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } + dto.AuthInfo = *authInfo res, err := u.Create(dto) rw.DataResponse(w, res, err) } diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 7af27137..d3951e7b 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -162,7 +162,7 @@ func SetRoutes() http.Handler { "DELETE /{id}": mcuordersubitem.O.Delete, "PATCH /{id}/complete": mcuordersubitem.O.Complete, }) - hk.GroupRoutes("/v1/encounter", r, hk.MapHandlerFunc{ + hk.GroupRoutes("/v1/encounter", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": encounter.O.GetList, "GET /{id}": encounter.O.GetDetail, "POST /": encounter.O.Create, diff --git a/internal/use-case/main-use-case/encounter/case.go b/internal/use-case/main-use-case/encounter/case.go index 7d209041..2e89d83d 100644 --- a/internal/use-case/main-use-case/encounter/case.go +++ b/internal/use-case/main-use-case/encounter/case.go @@ -7,12 +7,14 @@ import ( ea "simrs-vx/internal/domain/main-entities/ambulatory" ec "simrs-vx/internal/domain/main-entities/chemo" ee "simrs-vx/internal/domain/main-entities/emergency" + eem "simrs-vx/internal/domain/main-entities/employee" e "simrs-vx/internal/domain/main-entities/encounter" ei "simrs-vx/internal/domain/main-entities/inpatient" ua "simrs-vx/internal/use-case/main-use-case/ambulatory" uc "simrs-vx/internal/use-case/main-use-case/chemo" ue "simrs-vx/internal/use-case/main-use-case/emergency" + uem "simrs-vx/internal/use-case/main-use-case/employee" ui "simrs-vx/internal/use-case/main-use-case/inpatient" erc "simrs-vx/internal/domain/references/common" @@ -48,6 +50,12 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + if emp, err := uem.ReadDetailData(eem.ReadDetailDto{User_Id: &input.AuthInfo.User_Id}, &event, tx); err != nil { + return err + } else { + input.Adm_Employee_Id = &emp.Id + } + if resData, err := CreateData(input, &event, tx); err != nil { return err } else { From 319da694afa164d74b480e8ed263e203ed4c15f2 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 17 Oct 2025 13:04:43 +0700 Subject: [PATCH 14/30] feat (patient): add search by identifier and nik only --- internal/domain/main-entities/patient/dto.go | 3 +- .../domain/main-entities/patient/tycovar.go | 8 +++++ .../interface/main-handler/main-handler.go | 15 +++++----- .../interface/main-handler/patient/handler.go | 15 ++++++++++ .../use-case/main-use-case/patient/lib.go | 30 +++++++++++++------ 5 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 internal/domain/main-entities/patient/tycovar.go diff --git a/internal/domain/main-entities/patient/dto.go b/internal/domain/main-entities/patient/dto.go index 1374eb97..00134b6e 100644 --- a/internal/domain/main-entities/patient/dto.go +++ b/internal/domain/main-entities/patient/dto.go @@ -57,7 +57,8 @@ type DeleteDto struct { } type SearchDto struct { - Search string `json:"search"` + Search string `json:"search"` + Mode SearchMode `json:"mode"` } type UploadDto struct { diff --git a/internal/domain/main-entities/patient/tycovar.go b/internal/domain/main-entities/patient/tycovar.go new file mode 100644 index 00000000..aa419b57 --- /dev/null +++ b/internal/domain/main-entities/patient/tycovar.go @@ -0,0 +1,8 @@ +package patient + +type SearchMode string + +const ( + SMNik SearchMode = "resident-identity" + SMIdent SearchMode = "identifier" +) diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 3a7f0374..bc4b0fa0 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -260,13 +260,14 @@ func SetRoutes() http.Handler { "PATCH /{id}/active": user.O.Active, }) hk.GroupRoutes("/v1/patient", r, hk.MapHandlerFunc{ - "GET /": patient.O.GetList, - "GET /{id}": patient.O.GetDetail, - "POST /": patient.O.Create, - "PATCH /{id}": patient.O.Update, - "DELETE /{id}": patient.O.Delete, - "GET /by-identifier": patient.O.Search, - "POST /{id}/upload": patient.O.Upload, + "GET /": patient.O.GetList, + "GET /{id}": patient.O.GetDetail, + "POST /": patient.O.Create, + "PATCH /{id}": patient.O.Update, + "DELETE /{id}": patient.O.Delete, + "GET /search/{keyword}": patient.O.Search, + "GET /by-resident-identity": patient.O.SearchByResidentIdentity, + "POST /{id}/upload": patient.O.Upload, }) /******************** sources ********************/ diff --git a/internal/interface/main-handler/patient/handler.go b/internal/interface/main-handler/patient/handler.go index 1bcdacee..2c5fcb5b 100644 --- a/internal/interface/main-handler/patient/handler.go +++ b/internal/interface/main-handler/patient/handler.go @@ -12,6 +12,8 @@ import ( u "simrs-vx/internal/use-case/main-use-case/patient" ere "simrs-vx/internal/domain/references/encounter" + + d "github.com/karincake/dodol" ) type myBase struct{} @@ -73,8 +75,21 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { } func (obj myBase) Search(w http.ResponseWriter, r *http.Request) { + dto := e.SearchDto{} + keyword := rw.ValidateString(w, "keyword", r.PathValue("keyword")) + if keyword == "" { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "keyword is required"}, nil) + } + dto.Mode = e.SMIdent + dto.Search = keyword + res, err := u.Search(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) SearchByResidentIdentity(w http.ResponseWriter, r *http.Request) { dto := e.SearchDto{} sf.UrlQueryParam(&dto, *r.URL) + dto.Mode = e.SMNik res, err := u.Search(dto) rw.DataResponse(w, res, err) } diff --git a/internal/use-case/main-use-case/patient/lib.go b/internal/use-case/main-use-case/patient/lib.go index e126ec0d..f35e3853 100644 --- a/internal/use-case/main-use-case/patient/lib.go +++ b/internal/use-case/main-use-case/patient/lib.go @@ -91,7 +91,8 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e Preload("Person.Contacts"). Preload("Person.Relatives.Village.District.Regency.Province"). Preload("Person.Addresses.Village.District.Regency.Province"). - Preload("Person.Addresses.PostalRegion.Village.District.Regency.Province") + Preload("Person.Addresses.PostalRegion.Village.District.Regency.Province"). + Preload("Person.Insurances.InsuranceCompany") if err := tx.First(&data, input.Id).Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { @@ -157,6 +158,7 @@ func SearchData(input e.SearchDto, event *pl.Event, dbx ...*gorm.DB) (*e.Patient pl.SetLogInfo(event, input, "started", "DBSearch") var patient e.Patient + var err error var tx *gorm.DB if len(dbx) > 0 { @@ -167,15 +169,25 @@ func SearchData(input e.SearchDto, event *pl.Event, dbx ...*gorm.DB) (*e.Patient // Preload associations for complete data tx = tx.Preload(clause.Associations) - tx = tx.Preload("Person.Addresses") - tx = tx.Preload("Person.Contacts") - tx = tx.Preload("Person.Relatives") + 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) - err := tx.Joins("JOIN \"Person\" ON \"Patient\".\"Person_Id\" = \"Person\".\"Id\""). - Where("\"Patient\".\"Number\" = ? OR \"Person\".\"ResidentIdentityNumber\" = ?", - input.Search, input.Search). - First(&patient).Error + switch input.Mode { + case e.SMIdent: + // Search by patient number OR person's resident identity number (exact match) OR person's name (partial match) + err = tx.Joins("JOIN \"Person\" ON \"Patient\".\"Person_Id\" = \"Person\".\"Id\""). + Where("\"Patient\".\"Number\" = ? OR \"Person\".\"ResidentIdentityNumber\" = ? OR \"Person\".\"Name\" ILIKE ?", + 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 processedErr := pu.HandleSearchError(err, event, source, input.Search, patient); processedErr != nil { From 0ff8c571d0243fe415d7936507dc9b9f8cfedf5c Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 17 Oct 2025 13:06:49 +0700 Subject: [PATCH 15/30] add type_code into medicalactionsrc --- cmd/main-migration/migrations/20251017060617.sql | 2 ++ cmd/main-migration/migrations/atlas.sum | 5 +++-- internal/domain/main-entities/medical-action-src/entity.go | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 cmd/main-migration/migrations/20251017060617.sql diff --git a/cmd/main-migration/migrations/20251017060617.sql b/cmd/main-migration/migrations/20251017060617.sql new file mode 100644 index 00000000..8e3acbd2 --- /dev/null +++ b/cmd/main-migration/migrations/20251017060617.sql @@ -0,0 +1,2 @@ +-- Modify "MedicalActionSrc" table +ALTER TABLE "public"."MedicalActionSrc" ADD COLUMN "Type_Code" character varying(20) NULL; diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index bb5cb4b0..1f920b2d 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:5BOKtrJDl7mHDO/coJzV0ot0hVU9OVg5eP5Wg+zsIGo= +h1:sU0SrZhFKtCYoF46RbBCtQHOoDtvLJtLcIfBvmeawkg= 20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= 20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= 20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= @@ -46,4 +46,5 @@ h1:5BOKtrJDl7mHDO/coJzV0ot0hVU9OVg5eP5Wg+zsIGo= 20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= 20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= 20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= -20251016062912.sql h1:v21euwdu/4JCN3E2LFO4Iav4d7FEiAVH0dyEltmIeMw= +20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= +20251017060617.sql h1:KzIbA9fYORIK9aGWMMf0te5/8oThYFCCCSQVktGO0K0= diff --git a/internal/domain/main-entities/medical-action-src/entity.go b/internal/domain/main-entities/medical-action-src/entity.go index fbbbdb28..60f15816 100644 --- a/internal/domain/main-entities/medical-action-src/entity.go +++ b/internal/domain/main-entities/medical-action-src/entity.go @@ -9,6 +9,7 @@ type MedicalActionSrc struct { ecore.Main // adjust this according to the needs Code string `json:"code" gorm:"unique;size:20"` Name string `json:"name" gorm:"size:50"` + Type_Code string `json:"type_code" gorm:"size:20"` Item_Id *uint `json:"item_id"` Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` } From 9ead9b7e763776bead8e1a03777cc6d43e036339 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 17 Oct 2025 13:08:58 +0700 Subject: [PATCH 16/30] feat (medical-action-src): add type code --- .../main-entities/medical-action-src/dto.go | 34 +++++++++++-------- .../medical-action-src/helper.go | 1 + 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/internal/domain/main-entities/medical-action-src/dto.go b/internal/domain/main-entities/medical-action-src/dto.go index c67a2429..a4796a75 100644 --- a/internal/domain/main-entities/medical-action-src/dto.go +++ b/internal/domain/main-entities/medical-action-src/dto.go @@ -6,9 +6,10 @@ import ( ) type CreateDto struct { - Code string `json:"code" validate:"maxLength=20"` - Name string `json:"name" validate:"maxLength=50"` - Item_Id *uint `json:"item_id"` + Code string `json:"code" validate:"maxLength=20"` + Name string `json:"name" validate:"maxLength=50"` + Type_Code string `json:"type_code" validate:"maxLength:20"` + Item_Id *uint `json:"item_id"` } type ReadListDto struct { @@ -19,10 +20,11 @@ type ReadListDto struct { } type FilterDto struct { - Code string `json:"code"` - Name string `json:"name"` - Item_Id *uint `json:"item-id"` - Search string `json:"search" gormhelper:"searchColumns=Code,Name"` + Code string `json:"code"` + Name string `json:"name"` + Type_Code string `json:"type_code"` + Item_Id *uint `json:"item-id"` + Search string `json:"search" gormhelper:"searchColumns=Code,Name"` } type ReadDetailDto struct { @@ -47,18 +49,20 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Code string `json:"code"` - Name string `json:"name"` - Item_Id *uint `json:"item_id"` - Item *ei.Item `json:"item,omitempty"` + Code string `json:"code"` + Name string `json:"name"` + Type_Code string `json:"type_code"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` } func (d MedicalActionSrc) ToResponse() ResponseDto { resp := ResponseDto{ - Code: d.Code, - Name: d.Name, - Item_Id: d.Item_Id, - Item: d.Item, + Code: d.Code, + Name: d.Name, + Type_Code: d.Type_Code, + Item_Id: d.Item_Id, + Item: d.Item, } resp.Main = d.Main return resp diff --git a/internal/use-case/main-use-case/medical-action-src/helper.go b/internal/use-case/main-use-case/medical-action-src/helper.go index 22c0d26d..3e54a3eb 100644 --- a/internal/use-case/main-use-case/medical-action-src/helper.go +++ b/internal/use-case/main-use-case/medical-action-src/helper.go @@ -19,5 +19,6 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicalActionSrc) { data.Code = inputSrc.Code data.Name = inputSrc.Name + data.Type_Code = inputSrc.Type_Code data.Item_Id = inputSrc.Item_Id } From 063c511777db36a2aa4fdd5d29bed7bb313799d3 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 17 Oct 2025 13:12:34 +0700 Subject: [PATCH 17/30] migration from server --- cmd/main-migration/migrations/atlas.sum | 100 ++++++++++++------------ 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index 1f920b2d..de419662 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,50 +1,50 @@ -h1:sU0SrZhFKtCYoF46RbBCtQHOoDtvLJtLcIfBvmeawkg= -20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= -20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= -20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= -20250908062323.sql h1:oXl6Z143tOpIl4EfP4B8JNU8LrMvVmHEtCgAfiB4gs8= -20250908073811.sql h1:m2aNXfnGxnLq1+rVWrh4f60q7fhyhV3gEwNu/OIqQlE= -20250908073839.sql h1:cPk54xjLdMs26uY8ZHjNWLuyfAMzV7Zb0/9oJQrsw04= -20250910055902.sql h1:5xwjAV6QbtZT9empTJKfhyAjdknbHzb15B0Ku5dzqtQ= -20250915123412.sql h1:D83xaU2YlDEd21HLup/YQpQ2easMToYCyy/oK6AFgQs= -20250916043819.sql h1:ekoTJsBqQZ8G8n0qJ03d13+eoNoc7sAUEQGA5D/CCxk= -20250917040616.sql h1:zoCnmcXuM7AVv85SmN7RmFglCgJnoDmpRWExH0LAc9Q= -20250917040751.sql h1:J1xyRrh32y1+lezwAyNwPcUQ6ABBSgbvzNLva4SVdQU= -20250917045138.sql h1:jKe1Z0uOLG4SGBYM+S/3P+/zMPztmgoderD5swnMuCg= -20250917093645.sql h1:cNI3Pbz1R3LxvIXLuexafJFCXUXrmuFCgXXJ2sG+FW0= -20250918073552.sql h1:RJ1SvMzP6aeWnoPVD3eVAmIQOkcp6Php8z3QRri6v4g= -20250918073742.sql h1:+cEsnJTJFybe2fR69ZoOiX2R6c6iITl4m6WTZ1hjyzY= -20250918074745.sql h1:2hNVQCXF/dVYXAh+T/7oBFgERGWxzVb2FXJjwkFWGCI= -20250923025134.sql h1:Ykz/qpHiGDXPsCsWTjydQFVSibZP2D+h2fIeb2h2JGA= -20250924051317.sql h1:yQuW6SwJxIOM5fcxeAaie5lSm1oLysU/C2hH2xNCVoQ= -20250929034321.sql h1:101FJ8VH12mrZWlt/X1gvKUGOhoiF8tFbjiapAjnHzg= -20250929034428.sql h1:i+pROD9p+g5dOmmZma6WF/0Hw5g3Ha28NN85iTo1K34= -20250930025550.sql h1:+F+CsCUXD/ql0tHGEow70GhPBX1ZybVn+bh/T4YMh7Y= -20250930140351.sql h1:9AAEG1AnOAH+o0+oHL5G7I8vqlWOhwRlCGyyCpT/y1Q= -20251002085604.sql h1:3xZ68eYp4urXRnvotNH1XvG2mYOSDV/j3zHEZ/txg5E= -20251003032030.sql h1:HB+mQ2lXMNomHDpaRhB/9IwYI9/YiDO5eOJ+nAQH/jw= -20251005060450.sql h1:LbtCE2b+8osM3CvnmQJH1uCPtn+d7WchsslBOz8bL3Q= -20251006041122.sql h1:MlS7f21z06sutnf9dIekt5fuHJr4lgcQ4uCuCXAGsfc= -20251006045658.sql h1:3FmGCPCzjgMPdWDRodZTsx3KVaodd9zB9ilib69aewk= -20251006045928.sql h1:Z5g31PmnzNwk/OKdODcxZGm8fjJQdMFK32Xfnt3bRHg= -20251007022859.sql h1:FO03zEfaNEk/aXwY81d5Lp3MoBB9kPQuXlXJ4BPiSR8= -20251008031337.sql h1:l+sxUAGvcTfj3I6kAFHo+T6AYodC9k9GkR+jaKO2xXc= -20251008031554.sql h1:AqrVfIhSzY3PCy8ZlP5W91wn2iznfIuj5qQfubp6/94= -20251008052346.sql h1:nxnXmooIJ6r1mmzwnw+6efxLfc/k9h2aE6RMptPRons= -20251008073620.sql h1:6YsJp1W4SmQJ1lxpqF27BBlDC1zqhw7Yhc7pLzQTY6M= -20251009042854.sql h1:nkBV+R6j0fg7/JY6wH3eb5Vv0asJLnXmb6lINfT/GLQ= -20251009052657.sql h1:EPvdsib5rzCGPryd10HShGKvFPwM/R5S2lIVwtYxpms= -20251010031743.sql h1:T8IZmx8/btRFKLzTe78MzcBsPJNodnLvB0tby9QkirQ= -20251010070721.sql h1:5NQUk/yOV6sABLCB7swx++YIOyJe6MnU+yt1nRzde5w= -20251010072711.sql h1:ZJNqR2piyu8xJhBvVABSlnGEoKSKae3wuEs+wshPe4k= -20251013044536.sql h1:0Xjw8fNILiT8nnfrJDZgQnPf3dntmIoilbapnih8AE4= -20251013051438.sql h1:lfSuw5mgJnePBJamvhZ81osFIouXeiIEiSZ/evdwo48= -20251013081808.sql h1:ijgjNX08G6GBjA/ks8EKtb7P7Y7Cg7zbhqEOruGnv6M= -20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= -20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= -20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= -20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= -20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= -20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= -20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= -20251017060617.sql h1:KzIbA9fYORIK9aGWMMf0te5/8oThYFCCCSQVktGO0K0= +h1:PWJpriYcc0hEbY3oTjYgrBDS1qxSmoXkz+7K8JPowf8= +20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= +20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= +20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI= +20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= +20250908073811.sql h1:gOi5cnGG1htlpfizybYmUIT0vYjZTBfXiI0nPSYK2u8= +20250908073839.sql h1:cWNDA4YikjoOteAJuNLFILjQUJPFB6o8Wxreiek4QyI= +20250910055902.sql h1:nxxOGnU0BbH/v3IPgeIOXOwH8d3tKomw7h6FTeMnnBs= +20250915123412.sql h1:mz7SiWfrdf0qE1VTSAAnA/147d6gyp6ry5vZ2bR9SH0= +20250916043819.sql h1:RHXVtmMkB6wfv06HfPyHMBmUfIpFt1xveafNz0kwKnE= +20250917040616.sql h1:MYVDht+akBlzQGKNu2hTTTLPEcH1bxT/Q8MK6WEtuhs= +20250917040751.sql h1:J79YyS2JzWgh5oKXMTgh67uo3gLxKaAsxRiZmSIfjBs= +20250917045138.sql h1:/SM1N4O8X3yxpoJgMEARmS1uOkuLKsTOy4PLsRCOKaQ= +20250917093645.sql h1:PNBTGZ7s10e5b5+Tie8YfVQBN0zKtJ5T34oK1iOUEb4= +20250918073552.sql h1:jG7+g3i8ODYaJdcdZz12v3nbsZ5mB9wG6kWnGyTQIRI= +20250918073742.sql h1:j+rgw7puxE7s+phqPVZHmPk0af3rcaA56Itp86y1suY= +20250918074745.sql h1:rPmP4DXs6OnY4Vp+xO/z9jFpJt/RrJ52SJJjIIxeDvc= +20250923025134.sql h1:2r6pcwnBSU5Y9Czk1OHBoh4yZXiMtEca9X8843fTEX0= +20250924051317.sql h1:iUAk2gsGoEGIPQ0lEEUp8maMSId8emNbP+kP712ABIA= +20250929034321.sql h1:UlpALNVmdi95zOIT0yc6ZyTj9bBjQEIpZhvgrc52M+k= +20250929034428.sql h1:feF+H4nDyHh5bdx48Oiz0A1qecZfi6v3qTTdjzJ45Dg= +20250930025550.sql h1:6XT1kXI3Z3ZIxxmvT7poufZWWCW0QiejZPaFV5wBnjI= +20250930140351.sql h1:HxnmAbh9gCy8jwl/9ycGktiByaUripsjFFvohofY2CY= +20251002085604.sql h1:SjLPi+ZN6qDccK3DaEQCgNsZpPwr5kynWXwbwEsziCI= +20251003032030.sql h1:oHfxNSuqTxU8Zaf9H+h8TuUb1Da03wcyc6hZjDrUQ2s= +20251005060450.sql h1:GIuCcrd4MwjmXpvbzDzPYL18BV3QaZZ+Y2FmEzjvi0E= +20251006041122.sql h1:uNDQbSw0M08lYoMvUNlQtS3iDzpPM1ixT13ugSAoWjE= +20251006045658.sql h1:z+t7yCK54Q4SSiF9kUyUhkYB2F+kzSW9TB7ogxd9wzw= +20251006045928.sql h1:1lATLFLp4BWwGZqAjZdP0Dc6ypNXiYcwjoNkqGa8NFE= +20251007022859.sql h1:HXXwWrkyvzJzJGAt9mGskCRBBV/c1JfPmfjDocmJhQ4= +20251008031337.sql h1:Ln5pCF3Hxa5foHZLcds+z/us2eH6VAhhEj3w0TAGlVs= +20251008031554.sql h1:aB4MUS2lmqG0//4HKUWorcPSpWya0VC4QItvGyskEVI= +20251008052346.sql h1:MI3AZgU5XcwZT2OvvlWAxdRtL0eJ3jjRwt56IY1+pRU= +20251008073620.sql h1:sztWXuSNYwpEraaSapSsYwno75LO5H/N7ob7OJQ8X/A= +20251009042854.sql h1:TnPXj+dCJls3IU//cuqJZymyBzZMKs7ayazfgtAFRxM= +20251009052657.sql h1:leXbs0CP8r5dRilmYyLRk1MICqak3ea1/LWMtFrijqQ= +20251010031743.sql h1:SgHNY/lQ88G2F4nZyMfiOkDntb+gtOR+nEQLqXBTwv4= +20251010070721.sql h1:AnJnhXsMzDvK4AFgYw6B16Kpo/hljrZtcpc9m2VOSHQ= +20251010072711.sql h1:aXPTtNwLcTuw8C/yAxwxvqs0ayEjNzI1uuE0vE3ERa8= +20251013044536.sql h1:7Pq6JcvTpPBYDCW2dz3HdgUwY65HlhEVWy9TiG8iONE= +20251013051438.sql h1:X6t8bkqpUYYokBunSufMQUe5vCg0VyO6dxbm7ngosUc= +20251013081808.sql h1:495pLguXL2Ozh+ycn4UYZgZbn6WbjXNbyZUc3JU8qhI= +20251014060047.sql h1:nCgImMRGHhziiW57O1ofWaXCAPGaCOHN7PldQ3OSmM4= +20251014063537.sql h1:2cLmID79jP6cuQ1YJaWTtghFiM1GtHMC0ZQl30Hpy1M= +20251014063720.sql h1:bzLKKVAjSHgDFoiI/glj7t1ETlSAKx+AlsIAaP0ru2g= +20251015045455.sql h1:S547+UugQhlTRcn1Lm1IfqT5RNPttIWIiD+RTx69YaE= +20251016010845.sql h1:c9DUvxl17pUkf0azdYGM/YDzYxIJkLcfZOcMI4rL+R0= +20251016011023.sql h1:u3ivg83bXgYHBbojbWpemLxPE9Dmmj53B6LXo664jxw= +20251016062912.sql h1:W9n1hWchfYkqNX9LO9uxFxEXAb/iY+Pexjnhmp6PbgI= +20251017060617.sql h1:VU6yZ2+LfHpDZ3+TIH40t3F5YXPCpTppuF9+uSqa4b8= From ded271dc6d980b576f0a7612e86bd540e9344395 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 17 Oct 2025 15:19:43 +0700 Subject: [PATCH 18/30] feat (medical-action-src): add create item --- .../main-entities/medical-action-src/dto.go | 2 +- .../references/organization/organization.go | 1 + .../main-use-case/medical-action-src/case.go | 3 +++ .../medical-action-src/helper.go | 25 +++++++++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/internal/domain/main-entities/medical-action-src/dto.go b/internal/domain/main-entities/medical-action-src/dto.go index a4796a75..32e248d8 100644 --- a/internal/domain/main-entities/medical-action-src/dto.go +++ b/internal/domain/main-entities/medical-action-src/dto.go @@ -8,7 +8,7 @@ import ( type CreateDto struct { Code string `json:"code" validate:"maxLength=20"` Name string `json:"name" validate:"maxLength=50"` - Type_Code string `json:"type_code" validate:"maxLength:20"` + Type_Code string `json:"type_code" validate:"maxLength=20"` Item_Id *uint `json:"item_id"` } diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index bf11fbd6..04c4fa2a 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -30,6 +30,7 @@ const ( ITGCMCUSub ItemGroupCode = "mcuSub" ITGCEmpFee ItemGroupCode = "employee-fee" ITGCDocFee ItemGroupCode = "doctor-fee" + ITGCMedAct ItemGroupCode = "medical-action" IFGCBuilding InfraGroupCode = "building" // Bangunan IFGCFloor InfraGroupCode = "floor" // Lantai diff --git a/internal/use-case/main-use-case/medical-action-src/case.go b/internal/use-case/main-use-case/medical-action-src/case.go index d3fb840b..cd42766c 100644 --- a/internal/use-case/main-use-case/medical-action-src/case.go +++ b/internal/use-case/main-use-case/medical-action-src/case.go @@ -34,6 +34,9 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + if err := createItem(&input, &event, tx); err != nil { + return err + } if resData, err := CreateData(input, &event, tx); err != nil { return err } else { diff --git a/internal/use-case/main-use-case/medical-action-src/helper.go b/internal/use-case/main-use-case/medical-action-src/helper.go index 3e54a3eb..c955274d 100644 --- a/internal/use-case/main-use-case/medical-action-src/helper.go +++ b/internal/use-case/main-use-case/medical-action-src/helper.go @@ -5,7 +5,17 @@ Any functions that are used internally by the use-case package medicalactionsrc import ( + ei "simrs-vx/internal/domain/main-entities/item" e "simrs-vx/internal/domain/main-entities/medical-action-src" + + ero "simrs-vx/internal/domain/references/organization" + + ui "simrs-vx/internal/use-case/main-use-case/item" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" ) func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicalActionSrc) { @@ -22,3 +32,18 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicalActionSrc) { data.Type_Code = inputSrc.Type_Code data.Item_Id = inputSrc.Item_Id } + +func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + itemCreate := ei.CreateDto{ + Code: pu.AddPrefix("medAct-", input.Code), + Name: input.Name, + ItemGroup_Code: ero.ITGCMedAct, + } + item, err := ui.CreateData(itemCreate, event, tx) + if err != nil { + return err + } + + input.Item_Id = &item.Id + return nil +} From 3bfabc9e4c8ba4b67e070a70fe8035a332465827 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 17 Oct 2025 15:22:24 +0700 Subject: [PATCH 19/30] update size item group code --- .../migrations/20251017082207.sql | 2 + cmd/main-migration/migrations/atlas.sum | 101 +++++++++--------- internal/domain/main-entities/item/entity.go | 2 +- 3 files changed, 54 insertions(+), 51 deletions(-) create mode 100644 cmd/main-migration/migrations/20251017082207.sql diff --git a/cmd/main-migration/migrations/20251017082207.sql b/cmd/main-migration/migrations/20251017082207.sql new file mode 100644 index 00000000..732c8d71 --- /dev/null +++ b/cmd/main-migration/migrations/20251017082207.sql @@ -0,0 +1,2 @@ +-- Modify "Item" table +ALTER TABLE "public"."Item" ALTER COLUMN "ItemGroup_Code" TYPE character varying(15); diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index de419662..77732bde 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,50 +1,51 @@ -h1:PWJpriYcc0hEbY3oTjYgrBDS1qxSmoXkz+7K8JPowf8= -20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= -20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= -20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI= -20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= -20250908073811.sql h1:gOi5cnGG1htlpfizybYmUIT0vYjZTBfXiI0nPSYK2u8= -20250908073839.sql h1:cWNDA4YikjoOteAJuNLFILjQUJPFB6o8Wxreiek4QyI= -20250910055902.sql h1:nxxOGnU0BbH/v3IPgeIOXOwH8d3tKomw7h6FTeMnnBs= -20250915123412.sql h1:mz7SiWfrdf0qE1VTSAAnA/147d6gyp6ry5vZ2bR9SH0= -20250916043819.sql h1:RHXVtmMkB6wfv06HfPyHMBmUfIpFt1xveafNz0kwKnE= -20250917040616.sql h1:MYVDht+akBlzQGKNu2hTTTLPEcH1bxT/Q8MK6WEtuhs= -20250917040751.sql h1:J79YyS2JzWgh5oKXMTgh67uo3gLxKaAsxRiZmSIfjBs= -20250917045138.sql h1:/SM1N4O8X3yxpoJgMEARmS1uOkuLKsTOy4PLsRCOKaQ= -20250917093645.sql h1:PNBTGZ7s10e5b5+Tie8YfVQBN0zKtJ5T34oK1iOUEb4= -20250918073552.sql h1:jG7+g3i8ODYaJdcdZz12v3nbsZ5mB9wG6kWnGyTQIRI= -20250918073742.sql h1:j+rgw7puxE7s+phqPVZHmPk0af3rcaA56Itp86y1suY= -20250918074745.sql h1:rPmP4DXs6OnY4Vp+xO/z9jFpJt/RrJ52SJJjIIxeDvc= -20250923025134.sql h1:2r6pcwnBSU5Y9Czk1OHBoh4yZXiMtEca9X8843fTEX0= -20250924051317.sql h1:iUAk2gsGoEGIPQ0lEEUp8maMSId8emNbP+kP712ABIA= -20250929034321.sql h1:UlpALNVmdi95zOIT0yc6ZyTj9bBjQEIpZhvgrc52M+k= -20250929034428.sql h1:feF+H4nDyHh5bdx48Oiz0A1qecZfi6v3qTTdjzJ45Dg= -20250930025550.sql h1:6XT1kXI3Z3ZIxxmvT7poufZWWCW0QiejZPaFV5wBnjI= -20250930140351.sql h1:HxnmAbh9gCy8jwl/9ycGktiByaUripsjFFvohofY2CY= -20251002085604.sql h1:SjLPi+ZN6qDccK3DaEQCgNsZpPwr5kynWXwbwEsziCI= -20251003032030.sql h1:oHfxNSuqTxU8Zaf9H+h8TuUb1Da03wcyc6hZjDrUQ2s= -20251005060450.sql h1:GIuCcrd4MwjmXpvbzDzPYL18BV3QaZZ+Y2FmEzjvi0E= -20251006041122.sql h1:uNDQbSw0M08lYoMvUNlQtS3iDzpPM1ixT13ugSAoWjE= -20251006045658.sql h1:z+t7yCK54Q4SSiF9kUyUhkYB2F+kzSW9TB7ogxd9wzw= -20251006045928.sql h1:1lATLFLp4BWwGZqAjZdP0Dc6ypNXiYcwjoNkqGa8NFE= -20251007022859.sql h1:HXXwWrkyvzJzJGAt9mGskCRBBV/c1JfPmfjDocmJhQ4= -20251008031337.sql h1:Ln5pCF3Hxa5foHZLcds+z/us2eH6VAhhEj3w0TAGlVs= -20251008031554.sql h1:aB4MUS2lmqG0//4HKUWorcPSpWya0VC4QItvGyskEVI= -20251008052346.sql h1:MI3AZgU5XcwZT2OvvlWAxdRtL0eJ3jjRwt56IY1+pRU= -20251008073620.sql h1:sztWXuSNYwpEraaSapSsYwno75LO5H/N7ob7OJQ8X/A= -20251009042854.sql h1:TnPXj+dCJls3IU//cuqJZymyBzZMKs7ayazfgtAFRxM= -20251009052657.sql h1:leXbs0CP8r5dRilmYyLRk1MICqak3ea1/LWMtFrijqQ= -20251010031743.sql h1:SgHNY/lQ88G2F4nZyMfiOkDntb+gtOR+nEQLqXBTwv4= -20251010070721.sql h1:AnJnhXsMzDvK4AFgYw6B16Kpo/hljrZtcpc9m2VOSHQ= -20251010072711.sql h1:aXPTtNwLcTuw8C/yAxwxvqs0ayEjNzI1uuE0vE3ERa8= -20251013044536.sql h1:7Pq6JcvTpPBYDCW2dz3HdgUwY65HlhEVWy9TiG8iONE= -20251013051438.sql h1:X6t8bkqpUYYokBunSufMQUe5vCg0VyO6dxbm7ngosUc= -20251013081808.sql h1:495pLguXL2Ozh+ycn4UYZgZbn6WbjXNbyZUc3JU8qhI= -20251014060047.sql h1:nCgImMRGHhziiW57O1ofWaXCAPGaCOHN7PldQ3OSmM4= -20251014063537.sql h1:2cLmID79jP6cuQ1YJaWTtghFiM1GtHMC0ZQl30Hpy1M= -20251014063720.sql h1:bzLKKVAjSHgDFoiI/glj7t1ETlSAKx+AlsIAaP0ru2g= -20251015045455.sql h1:S547+UugQhlTRcn1Lm1IfqT5RNPttIWIiD+RTx69YaE= -20251016010845.sql h1:c9DUvxl17pUkf0azdYGM/YDzYxIJkLcfZOcMI4rL+R0= -20251016011023.sql h1:u3ivg83bXgYHBbojbWpemLxPE9Dmmj53B6LXo664jxw= -20251016062912.sql h1:W9n1hWchfYkqNX9LO9uxFxEXAb/iY+Pexjnhmp6PbgI= -20251017060617.sql h1:VU6yZ2+LfHpDZ3+TIH40t3F5YXPCpTppuF9+uSqa4b8= +h1:/NZRnBd4SNPxw+Sv7Fhn/VBxN0wRNU4OldkTUn6GtbI= +20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= +20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= +20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= +20250908062323.sql h1:oXl6Z143tOpIl4EfP4B8JNU8LrMvVmHEtCgAfiB4gs8= +20250908073811.sql h1:m2aNXfnGxnLq1+rVWrh4f60q7fhyhV3gEwNu/OIqQlE= +20250908073839.sql h1:cPk54xjLdMs26uY8ZHjNWLuyfAMzV7Zb0/9oJQrsw04= +20250910055902.sql h1:5xwjAV6QbtZT9empTJKfhyAjdknbHzb15B0Ku5dzqtQ= +20250915123412.sql h1:D83xaU2YlDEd21HLup/YQpQ2easMToYCyy/oK6AFgQs= +20250916043819.sql h1:ekoTJsBqQZ8G8n0qJ03d13+eoNoc7sAUEQGA5D/CCxk= +20250917040616.sql h1:zoCnmcXuM7AVv85SmN7RmFglCgJnoDmpRWExH0LAc9Q= +20250917040751.sql h1:J1xyRrh32y1+lezwAyNwPcUQ6ABBSgbvzNLva4SVdQU= +20250917045138.sql h1:jKe1Z0uOLG4SGBYM+S/3P+/zMPztmgoderD5swnMuCg= +20250917093645.sql h1:cNI3Pbz1R3LxvIXLuexafJFCXUXrmuFCgXXJ2sG+FW0= +20250918073552.sql h1:RJ1SvMzP6aeWnoPVD3eVAmIQOkcp6Php8z3QRri6v4g= +20250918073742.sql h1:+cEsnJTJFybe2fR69ZoOiX2R6c6iITl4m6WTZ1hjyzY= +20250918074745.sql h1:2hNVQCXF/dVYXAh+T/7oBFgERGWxzVb2FXJjwkFWGCI= +20250923025134.sql h1:Ykz/qpHiGDXPsCsWTjydQFVSibZP2D+h2fIeb2h2JGA= +20250924051317.sql h1:yQuW6SwJxIOM5fcxeAaie5lSm1oLysU/C2hH2xNCVoQ= +20250929034321.sql h1:101FJ8VH12mrZWlt/X1gvKUGOhoiF8tFbjiapAjnHzg= +20250929034428.sql h1:i+pROD9p+g5dOmmZma6WF/0Hw5g3Ha28NN85iTo1K34= +20250930025550.sql h1:+F+CsCUXD/ql0tHGEow70GhPBX1ZybVn+bh/T4YMh7Y= +20250930140351.sql h1:9AAEG1AnOAH+o0+oHL5G7I8vqlWOhwRlCGyyCpT/y1Q= +20251002085604.sql h1:3xZ68eYp4urXRnvotNH1XvG2mYOSDV/j3zHEZ/txg5E= +20251003032030.sql h1:HB+mQ2lXMNomHDpaRhB/9IwYI9/YiDO5eOJ+nAQH/jw= +20251005060450.sql h1:LbtCE2b+8osM3CvnmQJH1uCPtn+d7WchsslBOz8bL3Q= +20251006041122.sql h1:MlS7f21z06sutnf9dIekt5fuHJr4lgcQ4uCuCXAGsfc= +20251006045658.sql h1:3FmGCPCzjgMPdWDRodZTsx3KVaodd9zB9ilib69aewk= +20251006045928.sql h1:Z5g31PmnzNwk/OKdODcxZGm8fjJQdMFK32Xfnt3bRHg= +20251007022859.sql h1:FO03zEfaNEk/aXwY81d5Lp3MoBB9kPQuXlXJ4BPiSR8= +20251008031337.sql h1:l+sxUAGvcTfj3I6kAFHo+T6AYodC9k9GkR+jaKO2xXc= +20251008031554.sql h1:AqrVfIhSzY3PCy8ZlP5W91wn2iznfIuj5qQfubp6/94= +20251008052346.sql h1:nxnXmooIJ6r1mmzwnw+6efxLfc/k9h2aE6RMptPRons= +20251008073620.sql h1:6YsJp1W4SmQJ1lxpqF27BBlDC1zqhw7Yhc7pLzQTY6M= +20251009042854.sql h1:nkBV+R6j0fg7/JY6wH3eb5Vv0asJLnXmb6lINfT/GLQ= +20251009052657.sql h1:EPvdsib5rzCGPryd10HShGKvFPwM/R5S2lIVwtYxpms= +20251010031743.sql h1:T8IZmx8/btRFKLzTe78MzcBsPJNodnLvB0tby9QkirQ= +20251010070721.sql h1:5NQUk/yOV6sABLCB7swx++YIOyJe6MnU+yt1nRzde5w= +20251010072711.sql h1:ZJNqR2piyu8xJhBvVABSlnGEoKSKae3wuEs+wshPe4k= +20251013044536.sql h1:0Xjw8fNILiT8nnfrJDZgQnPf3dntmIoilbapnih8AE4= +20251013051438.sql h1:lfSuw5mgJnePBJamvhZ81osFIouXeiIEiSZ/evdwo48= +20251013081808.sql h1:ijgjNX08G6GBjA/ks8EKtb7P7Y7Cg7zbhqEOruGnv6M= +20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= +20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= +20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= +20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= +20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= +20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= +20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= +20251017060617.sql h1:4T3t9ifWrEQTPMSM0XJ98pF7Qdt+UfgtMui17bhrnWI= +20251017082207.sql h1:M3k5WPGt8gxv/4kB71di+78L/FyXrxhgGtXxGedwEps= diff --git a/internal/domain/main-entities/item/entity.go b/internal/domain/main-entities/item/entity.go index 9ac471ad..e0ff4e21 100644 --- a/internal/domain/main-entities/item/entity.go +++ b/internal/domain/main-entities/item/entity.go @@ -11,7 +11,7 @@ type Item struct { ecore.Main // adjust this according to the needs Code string `json:"code" gorm:"unique;size:50"` Name string `json:"name" gorm:"size:100"` - ItemGroup_Code ero.ItemGroupCode `json:"itemGroup_code" gorm:"size:10"` + ItemGroup_Code ero.ItemGroupCode `json:"itemGroup_code" gorm:"size:15"` Uom_Code *string `json:"uom_code" gorm:"size:10"` Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` Infra_Id *uint16 `json:"infra_id"` From c82ee6a96c26682df623255c36fd6489be6cddbc Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 17 Oct 2025 15:29:56 +0700 Subject: [PATCH 20/30] migration from server --- cmd/main-migration/migrations/atlas.sum | 102 ++++++++++++------------ 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index 77732bde..42636d28 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,51 +1,51 @@ -h1:/NZRnBd4SNPxw+Sv7Fhn/VBxN0wRNU4OldkTUn6GtbI= -20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= -20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= -20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= -20250908062323.sql h1:oXl6Z143tOpIl4EfP4B8JNU8LrMvVmHEtCgAfiB4gs8= -20250908073811.sql h1:m2aNXfnGxnLq1+rVWrh4f60q7fhyhV3gEwNu/OIqQlE= -20250908073839.sql h1:cPk54xjLdMs26uY8ZHjNWLuyfAMzV7Zb0/9oJQrsw04= -20250910055902.sql h1:5xwjAV6QbtZT9empTJKfhyAjdknbHzb15B0Ku5dzqtQ= -20250915123412.sql h1:D83xaU2YlDEd21HLup/YQpQ2easMToYCyy/oK6AFgQs= -20250916043819.sql h1:ekoTJsBqQZ8G8n0qJ03d13+eoNoc7sAUEQGA5D/CCxk= -20250917040616.sql h1:zoCnmcXuM7AVv85SmN7RmFglCgJnoDmpRWExH0LAc9Q= -20250917040751.sql h1:J1xyRrh32y1+lezwAyNwPcUQ6ABBSgbvzNLva4SVdQU= -20250917045138.sql h1:jKe1Z0uOLG4SGBYM+S/3P+/zMPztmgoderD5swnMuCg= -20250917093645.sql h1:cNI3Pbz1R3LxvIXLuexafJFCXUXrmuFCgXXJ2sG+FW0= -20250918073552.sql h1:RJ1SvMzP6aeWnoPVD3eVAmIQOkcp6Php8z3QRri6v4g= -20250918073742.sql h1:+cEsnJTJFybe2fR69ZoOiX2R6c6iITl4m6WTZ1hjyzY= -20250918074745.sql h1:2hNVQCXF/dVYXAh+T/7oBFgERGWxzVb2FXJjwkFWGCI= -20250923025134.sql h1:Ykz/qpHiGDXPsCsWTjydQFVSibZP2D+h2fIeb2h2JGA= -20250924051317.sql h1:yQuW6SwJxIOM5fcxeAaie5lSm1oLysU/C2hH2xNCVoQ= -20250929034321.sql h1:101FJ8VH12mrZWlt/X1gvKUGOhoiF8tFbjiapAjnHzg= -20250929034428.sql h1:i+pROD9p+g5dOmmZma6WF/0Hw5g3Ha28NN85iTo1K34= -20250930025550.sql h1:+F+CsCUXD/ql0tHGEow70GhPBX1ZybVn+bh/T4YMh7Y= -20250930140351.sql h1:9AAEG1AnOAH+o0+oHL5G7I8vqlWOhwRlCGyyCpT/y1Q= -20251002085604.sql h1:3xZ68eYp4urXRnvotNH1XvG2mYOSDV/j3zHEZ/txg5E= -20251003032030.sql h1:HB+mQ2lXMNomHDpaRhB/9IwYI9/YiDO5eOJ+nAQH/jw= -20251005060450.sql h1:LbtCE2b+8osM3CvnmQJH1uCPtn+d7WchsslBOz8bL3Q= -20251006041122.sql h1:MlS7f21z06sutnf9dIekt5fuHJr4lgcQ4uCuCXAGsfc= -20251006045658.sql h1:3FmGCPCzjgMPdWDRodZTsx3KVaodd9zB9ilib69aewk= -20251006045928.sql h1:Z5g31PmnzNwk/OKdODcxZGm8fjJQdMFK32Xfnt3bRHg= -20251007022859.sql h1:FO03zEfaNEk/aXwY81d5Lp3MoBB9kPQuXlXJ4BPiSR8= -20251008031337.sql h1:l+sxUAGvcTfj3I6kAFHo+T6AYodC9k9GkR+jaKO2xXc= -20251008031554.sql h1:AqrVfIhSzY3PCy8ZlP5W91wn2iznfIuj5qQfubp6/94= -20251008052346.sql h1:nxnXmooIJ6r1mmzwnw+6efxLfc/k9h2aE6RMptPRons= -20251008073620.sql h1:6YsJp1W4SmQJ1lxpqF27BBlDC1zqhw7Yhc7pLzQTY6M= -20251009042854.sql h1:nkBV+R6j0fg7/JY6wH3eb5Vv0asJLnXmb6lINfT/GLQ= -20251009052657.sql h1:EPvdsib5rzCGPryd10HShGKvFPwM/R5S2lIVwtYxpms= -20251010031743.sql h1:T8IZmx8/btRFKLzTe78MzcBsPJNodnLvB0tby9QkirQ= -20251010070721.sql h1:5NQUk/yOV6sABLCB7swx++YIOyJe6MnU+yt1nRzde5w= -20251010072711.sql h1:ZJNqR2piyu8xJhBvVABSlnGEoKSKae3wuEs+wshPe4k= -20251013044536.sql h1:0Xjw8fNILiT8nnfrJDZgQnPf3dntmIoilbapnih8AE4= -20251013051438.sql h1:lfSuw5mgJnePBJamvhZ81osFIouXeiIEiSZ/evdwo48= -20251013081808.sql h1:ijgjNX08G6GBjA/ks8EKtb7P7Y7Cg7zbhqEOruGnv6M= -20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= -20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= -20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= -20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= -20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= -20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= -20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= -20251017060617.sql h1:4T3t9ifWrEQTPMSM0XJ98pF7Qdt+UfgtMui17bhrnWI= -20251017082207.sql h1:M3k5WPGt8gxv/4kB71di+78L/FyXrxhgGtXxGedwEps= +h1:8zie3PyS55y+G80bxoc2K/aE8n0tDc8iH3Tc+FUB4o8= +20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= +20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= +20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI= +20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= +20250908073811.sql h1:gOi5cnGG1htlpfizybYmUIT0vYjZTBfXiI0nPSYK2u8= +20250908073839.sql h1:cWNDA4YikjoOteAJuNLFILjQUJPFB6o8Wxreiek4QyI= +20250910055902.sql h1:nxxOGnU0BbH/v3IPgeIOXOwH8d3tKomw7h6FTeMnnBs= +20250915123412.sql h1:mz7SiWfrdf0qE1VTSAAnA/147d6gyp6ry5vZ2bR9SH0= +20250916043819.sql h1:RHXVtmMkB6wfv06HfPyHMBmUfIpFt1xveafNz0kwKnE= +20250917040616.sql h1:MYVDht+akBlzQGKNu2hTTTLPEcH1bxT/Q8MK6WEtuhs= +20250917040751.sql h1:J79YyS2JzWgh5oKXMTgh67uo3gLxKaAsxRiZmSIfjBs= +20250917045138.sql h1:/SM1N4O8X3yxpoJgMEARmS1uOkuLKsTOy4PLsRCOKaQ= +20250917093645.sql h1:PNBTGZ7s10e5b5+Tie8YfVQBN0zKtJ5T34oK1iOUEb4= +20250918073552.sql h1:jG7+g3i8ODYaJdcdZz12v3nbsZ5mB9wG6kWnGyTQIRI= +20250918073742.sql h1:j+rgw7puxE7s+phqPVZHmPk0af3rcaA56Itp86y1suY= +20250918074745.sql h1:rPmP4DXs6OnY4Vp+xO/z9jFpJt/RrJ52SJJjIIxeDvc= +20250923025134.sql h1:2r6pcwnBSU5Y9Czk1OHBoh4yZXiMtEca9X8843fTEX0= +20250924051317.sql h1:iUAk2gsGoEGIPQ0lEEUp8maMSId8emNbP+kP712ABIA= +20250929034321.sql h1:UlpALNVmdi95zOIT0yc6ZyTj9bBjQEIpZhvgrc52M+k= +20250929034428.sql h1:feF+H4nDyHh5bdx48Oiz0A1qecZfi6v3qTTdjzJ45Dg= +20250930025550.sql h1:6XT1kXI3Z3ZIxxmvT7poufZWWCW0QiejZPaFV5wBnjI= +20250930140351.sql h1:HxnmAbh9gCy8jwl/9ycGktiByaUripsjFFvohofY2CY= +20251002085604.sql h1:SjLPi+ZN6qDccK3DaEQCgNsZpPwr5kynWXwbwEsziCI= +20251003032030.sql h1:oHfxNSuqTxU8Zaf9H+h8TuUb1Da03wcyc6hZjDrUQ2s= +20251005060450.sql h1:GIuCcrd4MwjmXpvbzDzPYL18BV3QaZZ+Y2FmEzjvi0E= +20251006041122.sql h1:uNDQbSw0M08lYoMvUNlQtS3iDzpPM1ixT13ugSAoWjE= +20251006045658.sql h1:z+t7yCK54Q4SSiF9kUyUhkYB2F+kzSW9TB7ogxd9wzw= +20251006045928.sql h1:1lATLFLp4BWwGZqAjZdP0Dc6ypNXiYcwjoNkqGa8NFE= +20251007022859.sql h1:HXXwWrkyvzJzJGAt9mGskCRBBV/c1JfPmfjDocmJhQ4= +20251008031337.sql h1:Ln5pCF3Hxa5foHZLcds+z/us2eH6VAhhEj3w0TAGlVs= +20251008031554.sql h1:aB4MUS2lmqG0//4HKUWorcPSpWya0VC4QItvGyskEVI= +20251008052346.sql h1:MI3AZgU5XcwZT2OvvlWAxdRtL0eJ3jjRwt56IY1+pRU= +20251008073620.sql h1:sztWXuSNYwpEraaSapSsYwno75LO5H/N7ob7OJQ8X/A= +20251009042854.sql h1:TnPXj+dCJls3IU//cuqJZymyBzZMKs7ayazfgtAFRxM= +20251009052657.sql h1:leXbs0CP8r5dRilmYyLRk1MICqak3ea1/LWMtFrijqQ= +20251010031743.sql h1:SgHNY/lQ88G2F4nZyMfiOkDntb+gtOR+nEQLqXBTwv4= +20251010070721.sql h1:AnJnhXsMzDvK4AFgYw6B16Kpo/hljrZtcpc9m2VOSHQ= +20251010072711.sql h1:aXPTtNwLcTuw8C/yAxwxvqs0ayEjNzI1uuE0vE3ERa8= +20251013044536.sql h1:7Pq6JcvTpPBYDCW2dz3HdgUwY65HlhEVWy9TiG8iONE= +20251013051438.sql h1:X6t8bkqpUYYokBunSufMQUe5vCg0VyO6dxbm7ngosUc= +20251013081808.sql h1:495pLguXL2Ozh+ycn4UYZgZbn6WbjXNbyZUc3JU8qhI= +20251014060047.sql h1:nCgImMRGHhziiW57O1ofWaXCAPGaCOHN7PldQ3OSmM4= +20251014063537.sql h1:2cLmID79jP6cuQ1YJaWTtghFiM1GtHMC0ZQl30Hpy1M= +20251014063720.sql h1:bzLKKVAjSHgDFoiI/glj7t1ETlSAKx+AlsIAaP0ru2g= +20251015045455.sql h1:S547+UugQhlTRcn1Lm1IfqT5RNPttIWIiD+RTx69YaE= +20251016010845.sql h1:c9DUvxl17pUkf0azdYGM/YDzYxIJkLcfZOcMI4rL+R0= +20251016011023.sql h1:u3ivg83bXgYHBbojbWpemLxPE9Dmmj53B6LXo664jxw= +20251016062912.sql h1:W9n1hWchfYkqNX9LO9uxFxEXAb/iY+Pexjnhmp6PbgI= +20251017060617.sql h1:VU6yZ2+LfHpDZ3+TIH40t3F5YXPCpTppuF9+uSqa4b8= +20251017082207.sql h1:QshZslfedckz7iDpSGmPyY9sP6dy6ckHbs8L1TuXIA4= From 3d165447f52d8fccbec9f5b15f5528a0e6737524 Mon Sep 17 00:00:00 2001 From: Munawwirul Jamal Date: Sun, 19 Oct 2025 07:09:48 +0700 Subject: [PATCH 21/30] migration: + added intern + updated employee + updated user --- .../migrations/20251018032635.sql | 4 + .../migrations/20251018040322.sql | 13 +++ cmd/main-migration/migrations/atlas.sum | 104 +++++++++--------- .../domain/main-entities/employee/entity.go | 20 ++-- internal/domain/main-entities/intern/dto.go | 81 ++++++++++++++ .../domain/main-entities/intern/entity.go | 17 +++ internal/domain/main-entities/user/dto.go | 43 ++++---- internal/domain/main-entities/user/entity.go | 19 ++-- internal/interface/migration/main-entities.go | 2 + 9 files changed, 213 insertions(+), 90 deletions(-) create mode 100644 cmd/main-migration/migrations/20251018032635.sql create mode 100644 cmd/main-migration/migrations/20251018040322.sql create mode 100644 internal/domain/main-entities/intern/dto.go create mode 100644 internal/domain/main-entities/intern/entity.go diff --git a/cmd/main-migration/migrations/20251018032635.sql b/cmd/main-migration/migrations/20251018032635.sql new file mode 100644 index 00000000..d8c5a2c9 --- /dev/null +++ b/cmd/main-migration/migrations/20251018032635.sql @@ -0,0 +1,4 @@ +-- Modify "Employee" table +ALTER TABLE "public"."Employee" ADD COLUMN "Position_Code" character varying(20) NULL; +-- Rename a column from "Position_Code" to "ContractPosition_Code" +ALTER TABLE "public"."User" RENAME COLUMN "Position_Code" TO "ContractPosition_Code"; diff --git a/cmd/main-migration/migrations/20251018040322.sql b/cmd/main-migration/migrations/20251018040322.sql new file mode 100644 index 00000000..d35e9199 --- /dev/null +++ b/cmd/main-migration/migrations/20251018040322.sql @@ -0,0 +1,13 @@ +-- Create "Intern" table +CREATE TABLE "public"."Intern" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Person_Id" bigint NULL, + "Position_Code" character varying(20) NULL, + "User_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Intern_Person" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Intern_User" FOREIGN KEY ("User_Id") REFERENCES "public"."User" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index 42636d28..bf732e89 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,51 +1,53 @@ -h1:8zie3PyS55y+G80bxoc2K/aE8n0tDc8iH3Tc+FUB4o8= -20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= -20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= -20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI= -20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= -20250908073811.sql h1:gOi5cnGG1htlpfizybYmUIT0vYjZTBfXiI0nPSYK2u8= -20250908073839.sql h1:cWNDA4YikjoOteAJuNLFILjQUJPFB6o8Wxreiek4QyI= -20250910055902.sql h1:nxxOGnU0BbH/v3IPgeIOXOwH8d3tKomw7h6FTeMnnBs= -20250915123412.sql h1:mz7SiWfrdf0qE1VTSAAnA/147d6gyp6ry5vZ2bR9SH0= -20250916043819.sql h1:RHXVtmMkB6wfv06HfPyHMBmUfIpFt1xveafNz0kwKnE= -20250917040616.sql h1:MYVDht+akBlzQGKNu2hTTTLPEcH1bxT/Q8MK6WEtuhs= -20250917040751.sql h1:J79YyS2JzWgh5oKXMTgh67uo3gLxKaAsxRiZmSIfjBs= -20250917045138.sql h1:/SM1N4O8X3yxpoJgMEARmS1uOkuLKsTOy4PLsRCOKaQ= -20250917093645.sql h1:PNBTGZ7s10e5b5+Tie8YfVQBN0zKtJ5T34oK1iOUEb4= -20250918073552.sql h1:jG7+g3i8ODYaJdcdZz12v3nbsZ5mB9wG6kWnGyTQIRI= -20250918073742.sql h1:j+rgw7puxE7s+phqPVZHmPk0af3rcaA56Itp86y1suY= -20250918074745.sql h1:rPmP4DXs6OnY4Vp+xO/z9jFpJt/RrJ52SJJjIIxeDvc= -20250923025134.sql h1:2r6pcwnBSU5Y9Czk1OHBoh4yZXiMtEca9X8843fTEX0= -20250924051317.sql h1:iUAk2gsGoEGIPQ0lEEUp8maMSId8emNbP+kP712ABIA= -20250929034321.sql h1:UlpALNVmdi95zOIT0yc6ZyTj9bBjQEIpZhvgrc52M+k= -20250929034428.sql h1:feF+H4nDyHh5bdx48Oiz0A1qecZfi6v3qTTdjzJ45Dg= -20250930025550.sql h1:6XT1kXI3Z3ZIxxmvT7poufZWWCW0QiejZPaFV5wBnjI= -20250930140351.sql h1:HxnmAbh9gCy8jwl/9ycGktiByaUripsjFFvohofY2CY= -20251002085604.sql h1:SjLPi+ZN6qDccK3DaEQCgNsZpPwr5kynWXwbwEsziCI= -20251003032030.sql h1:oHfxNSuqTxU8Zaf9H+h8TuUb1Da03wcyc6hZjDrUQ2s= -20251005060450.sql h1:GIuCcrd4MwjmXpvbzDzPYL18BV3QaZZ+Y2FmEzjvi0E= -20251006041122.sql h1:uNDQbSw0M08lYoMvUNlQtS3iDzpPM1ixT13ugSAoWjE= -20251006045658.sql h1:z+t7yCK54Q4SSiF9kUyUhkYB2F+kzSW9TB7ogxd9wzw= -20251006045928.sql h1:1lATLFLp4BWwGZqAjZdP0Dc6ypNXiYcwjoNkqGa8NFE= -20251007022859.sql h1:HXXwWrkyvzJzJGAt9mGskCRBBV/c1JfPmfjDocmJhQ4= -20251008031337.sql h1:Ln5pCF3Hxa5foHZLcds+z/us2eH6VAhhEj3w0TAGlVs= -20251008031554.sql h1:aB4MUS2lmqG0//4HKUWorcPSpWya0VC4QItvGyskEVI= -20251008052346.sql h1:MI3AZgU5XcwZT2OvvlWAxdRtL0eJ3jjRwt56IY1+pRU= -20251008073620.sql h1:sztWXuSNYwpEraaSapSsYwno75LO5H/N7ob7OJQ8X/A= -20251009042854.sql h1:TnPXj+dCJls3IU//cuqJZymyBzZMKs7ayazfgtAFRxM= -20251009052657.sql h1:leXbs0CP8r5dRilmYyLRk1MICqak3ea1/LWMtFrijqQ= -20251010031743.sql h1:SgHNY/lQ88G2F4nZyMfiOkDntb+gtOR+nEQLqXBTwv4= -20251010070721.sql h1:AnJnhXsMzDvK4AFgYw6B16Kpo/hljrZtcpc9m2VOSHQ= -20251010072711.sql h1:aXPTtNwLcTuw8C/yAxwxvqs0ayEjNzI1uuE0vE3ERa8= -20251013044536.sql h1:7Pq6JcvTpPBYDCW2dz3HdgUwY65HlhEVWy9TiG8iONE= -20251013051438.sql h1:X6t8bkqpUYYokBunSufMQUe5vCg0VyO6dxbm7ngosUc= -20251013081808.sql h1:495pLguXL2Ozh+ycn4UYZgZbn6WbjXNbyZUc3JU8qhI= -20251014060047.sql h1:nCgImMRGHhziiW57O1ofWaXCAPGaCOHN7PldQ3OSmM4= -20251014063537.sql h1:2cLmID79jP6cuQ1YJaWTtghFiM1GtHMC0ZQl30Hpy1M= -20251014063720.sql h1:bzLKKVAjSHgDFoiI/glj7t1ETlSAKx+AlsIAaP0ru2g= -20251015045455.sql h1:S547+UugQhlTRcn1Lm1IfqT5RNPttIWIiD+RTx69YaE= -20251016010845.sql h1:c9DUvxl17pUkf0azdYGM/YDzYxIJkLcfZOcMI4rL+R0= -20251016011023.sql h1:u3ivg83bXgYHBbojbWpemLxPE9Dmmj53B6LXo664jxw= -20251016062912.sql h1:W9n1hWchfYkqNX9LO9uxFxEXAb/iY+Pexjnhmp6PbgI= -20251017060617.sql h1:VU6yZ2+LfHpDZ3+TIH40t3F5YXPCpTppuF9+uSqa4b8= -20251017082207.sql h1:QshZslfedckz7iDpSGmPyY9sP6dy6ckHbs8L1TuXIA4= +h1:S3ggQSrIa2Lwhkx+yWmD9N2hZxRuVwCMZcEpsk83PJY= +20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= +20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= +20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= +20250908062323.sql h1:oXl6Z143tOpIl4EfP4B8JNU8LrMvVmHEtCgAfiB4gs8= +20250908073811.sql h1:m2aNXfnGxnLq1+rVWrh4f60q7fhyhV3gEwNu/OIqQlE= +20250908073839.sql h1:cPk54xjLdMs26uY8ZHjNWLuyfAMzV7Zb0/9oJQrsw04= +20250910055902.sql h1:5xwjAV6QbtZT9empTJKfhyAjdknbHzb15B0Ku5dzqtQ= +20250915123412.sql h1:D83xaU2YlDEd21HLup/YQpQ2easMToYCyy/oK6AFgQs= +20250916043819.sql h1:ekoTJsBqQZ8G8n0qJ03d13+eoNoc7sAUEQGA5D/CCxk= +20250917040616.sql h1:zoCnmcXuM7AVv85SmN7RmFglCgJnoDmpRWExH0LAc9Q= +20250917040751.sql h1:J1xyRrh32y1+lezwAyNwPcUQ6ABBSgbvzNLva4SVdQU= +20250917045138.sql h1:jKe1Z0uOLG4SGBYM+S/3P+/zMPztmgoderD5swnMuCg= +20250917093645.sql h1:cNI3Pbz1R3LxvIXLuexafJFCXUXrmuFCgXXJ2sG+FW0= +20250918073552.sql h1:RJ1SvMzP6aeWnoPVD3eVAmIQOkcp6Php8z3QRri6v4g= +20250918073742.sql h1:+cEsnJTJFybe2fR69ZoOiX2R6c6iITl4m6WTZ1hjyzY= +20250918074745.sql h1:2hNVQCXF/dVYXAh+T/7oBFgERGWxzVb2FXJjwkFWGCI= +20250923025134.sql h1:Ykz/qpHiGDXPsCsWTjydQFVSibZP2D+h2fIeb2h2JGA= +20250924051317.sql h1:yQuW6SwJxIOM5fcxeAaie5lSm1oLysU/C2hH2xNCVoQ= +20250929034321.sql h1:101FJ8VH12mrZWlt/X1gvKUGOhoiF8tFbjiapAjnHzg= +20250929034428.sql h1:i+pROD9p+g5dOmmZma6WF/0Hw5g3Ha28NN85iTo1K34= +20250930025550.sql h1:+F+CsCUXD/ql0tHGEow70GhPBX1ZybVn+bh/T4YMh7Y= +20250930140351.sql h1:9AAEG1AnOAH+o0+oHL5G7I8vqlWOhwRlCGyyCpT/y1Q= +20251002085604.sql h1:3xZ68eYp4urXRnvotNH1XvG2mYOSDV/j3zHEZ/txg5E= +20251003032030.sql h1:HB+mQ2lXMNomHDpaRhB/9IwYI9/YiDO5eOJ+nAQH/jw= +20251005060450.sql h1:LbtCE2b+8osM3CvnmQJH1uCPtn+d7WchsslBOz8bL3Q= +20251006041122.sql h1:MlS7f21z06sutnf9dIekt5fuHJr4lgcQ4uCuCXAGsfc= +20251006045658.sql h1:3FmGCPCzjgMPdWDRodZTsx3KVaodd9zB9ilib69aewk= +20251006045928.sql h1:Z5g31PmnzNwk/OKdODcxZGm8fjJQdMFK32Xfnt3bRHg= +20251007022859.sql h1:FO03zEfaNEk/aXwY81d5Lp3MoBB9kPQuXlXJ4BPiSR8= +20251008031337.sql h1:l+sxUAGvcTfj3I6kAFHo+T6AYodC9k9GkR+jaKO2xXc= +20251008031554.sql h1:AqrVfIhSzY3PCy8ZlP5W91wn2iznfIuj5qQfubp6/94= +20251008052346.sql h1:nxnXmooIJ6r1mmzwnw+6efxLfc/k9h2aE6RMptPRons= +20251008073620.sql h1:6YsJp1W4SmQJ1lxpqF27BBlDC1zqhw7Yhc7pLzQTY6M= +20251009042854.sql h1:nkBV+R6j0fg7/JY6wH3eb5Vv0asJLnXmb6lINfT/GLQ= +20251009052657.sql h1:EPvdsib5rzCGPryd10HShGKvFPwM/R5S2lIVwtYxpms= +20251010031743.sql h1:T8IZmx8/btRFKLzTe78MzcBsPJNodnLvB0tby9QkirQ= +20251010070721.sql h1:5NQUk/yOV6sABLCB7swx++YIOyJe6MnU+yt1nRzde5w= +20251010072711.sql h1:ZJNqR2piyu8xJhBvVABSlnGEoKSKae3wuEs+wshPe4k= +20251013044536.sql h1:0Xjw8fNILiT8nnfrJDZgQnPf3dntmIoilbapnih8AE4= +20251013051438.sql h1:lfSuw5mgJnePBJamvhZ81osFIouXeiIEiSZ/evdwo48= +20251013081808.sql h1:ijgjNX08G6GBjA/ks8EKtb7P7Y7Cg7zbhqEOruGnv6M= +20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= +20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= +20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= +20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= +20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= +20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= +20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= +20251017060617.sql h1:4T3t9ifWrEQTPMSM0XJ98pF7Qdt+UfgtMui17bhrnWI= +20251017082207.sql h1:8vLG1l/saRRMHXkyA4nelJyjaSddhZd6r7R+Uo4JS/c= +20251018032635.sql h1:UltiY1Jm1KjAyBx/oRbhKzwEl3Aqh3o+eaOIfWdroJ8= +20251018040322.sql h1:24VgOPgO2pxfwTcAv7xCv8BHiRPqmIbHUCXNLyvrGfc= diff --git a/internal/domain/main-entities/employee/entity.go b/internal/domain/main-entities/employee/entity.go index 8113fc96..2e8cd953 100644 --- a/internal/domain/main-entities/employee/entity.go +++ b/internal/domain/main-entities/employee/entity.go @@ -6,16 +6,18 @@ import ( ep "simrs-vx/internal/domain/main-entities/person" eu "simrs-vx/internal/domain/main-entities/user" erc "simrs-vx/internal/domain/references/common" + erg "simrs-vx/internal/domain/references/organization" ) type Employee struct { - ecore.Main // adjust this according to the needs - User_Id *uint `json:"user_id"` - User *eu.User `json:"user,omitempty" gorm:"foreignKey:User_Id;references:Id"` - Person_Id *uint `json:"person_id"` - Person *ep.Person `json:"person,omitempty" gorm:"foreignKey:Person_Id;references:Id"` - Division_Code *string `json:"division_code"` - Division *ed.Division `json:"division,omitempty" gorm:"foreignKey:Division_Code;references:Code"` - Number *string `json:"number" gorm:"size:20"` - Status_Code erc.ActiveStatusCode `json:"status_code" gorm:"not null;size:10"` + ecore.Main // adjust this according to the needs + User_Id *uint `json:"user_id"` + User *eu.User `json:"user,omitempty" gorm:"foreignKey:User_Id;references:Id"` + Person_Id *uint `json:"person_id"` + Person *ep.Person `json:"person,omitempty" gorm:"foreignKey:Person_Id;references:Id"` + Position_Code *erg.EmployeePosisitionCode `json:"position_code" gorm:"size:20"` + Division_Code *string `json:"division_code"` + Division *ed.Division `json:"division,omitempty" gorm:"foreignKey:Division_Code;references:Code"` + Number *string `json:"number" gorm:"size:20"` + Status_Code erc.ActiveStatusCode `json:"status_code" gorm:"not null;size:10"` } diff --git a/internal/domain/main-entities/intern/dto.go b/internal/domain/main-entities/intern/dto.go new file mode 100644 index 00000000..b8c60aee --- /dev/null +++ b/internal/domain/main-entities/intern/dto.go @@ -0,0 +1,81 @@ +package intern + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ep "simrs-vx/internal/domain/main-entities/person" + es "simrs-vx/internal/domain/main-entities/specialist" + ess "simrs-vx/internal/domain/main-entities/subspecialist" + eu "simrs-vx/internal/domain/main-entities/user" +) + +type CreateDto struct { + Person_Id *uint `json:"person_id"` + Specialist_Id *uint16 `json:"specialist_id"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + User_Id *uint `json:"user_id"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Person_Id *uint `json:"person_id"` + Specialist_Id *uint16 `json:"specialist_id"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + User_Id *uint `json:"user_id"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + User_Id *uint `json:"user_id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Person_Id *uint `json:"person_id"` + Person *ep.Person `json:"person,omitempty"` + Specialist_Id *uint16 `json:"specialist_id"` + Specialist *es.Specialist `json:"specialist,omitempty"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` + User_Id *uint `json:"user_id"` + User *eu.User `json:"user,omitempty"` +} + +func (d Intern) ToResponse() ResponseDto { + resp := ResponseDto{ + Person_Id: d.Person_Id, + Person: d.Person, + User_Id: d.User_Id, + User: d.User, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Intern) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/intern/entity.go b/internal/domain/main-entities/intern/entity.go new file mode 100644 index 00000000..5ac2df49 --- /dev/null +++ b/internal/domain/main-entities/intern/entity.go @@ -0,0 +1,17 @@ +package intern + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ep "simrs-vx/internal/domain/main-entities/person" + eu "simrs-vx/internal/domain/main-entities/user" + erg "simrs-vx/internal/domain/references/organization" +) + +type Intern struct { + ecore.Main // adjust this according to the needs + Person_Id *uint `json:"person_id"` + Person *ep.Person `json:"person,omitempty" gorm:"foreignKey:Person_Id"` + Position_Code *erg.InternPosisitionCode `json:"position_code" gorm:"size:20"` + User_Id *uint `json:"user_id"` + User *eu.User `json:"user,omitempty" gorm:"foreignKey:User_Id"` +} diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index 62a0c587..21f16c3f 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -13,21 +13,21 @@ import ( ) type CreateDto struct { - Name string `json:"name" validate:"maxLength=25"` - Password string `json:"password" validate:"maxLength=255"` - Status_Code erc.UserStatusCode `json:"status_code" validate:"maxLength=10"` - Position_Code ero.UserPosisitionCode `json:"position_code" validate:"maxLength=20"` - Person_Id *uint `json:"-"` - Person *ep.UpdateDto `json:"person"` - PersonAddresses []epa.UpdateDto `json:"personAddresses"` - PersonContacts []epc.UpdateDto `json:"personContacts"` - Employee *EmployeUpdateDto `json:"employee"` - IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` - SIP_Number *string `json:"sip_number" validate:"maxLength=20"` - Unit_Id *uint16 `json:"unit_id"` - Infra_Id *uint16 `json:"infra_id"` - Specialist_Id *uint16 `json:"specialist_id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` + Name string `json:"name" validate:"maxLength=25"` + Password string `json:"password" validate:"maxLength=255"` + Status_Code erc.UserStatusCode `json:"status_code" validate:"maxLength=10"` + ContractPosition_Code ero.ContractPositionCode `json:"contractPosition_code" validate:"maxLength=20"` + Person_Id *uint `json:"-"` + Person *ep.UpdateDto `json:"person"` + PersonAddresses []epa.UpdateDto `json:"personAddresses"` + PersonContacts []epc.UpdateDto `json:"personContacts"` + Employee *EmployeUpdateDto `json:"employee"` + IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` + SIP_Number *string `json:"sip_number" validate:"maxLength=20"` + Unit_Id *uint16 `json:"unit_id"` + Infra_Id *uint16 `json:"infra_id"` + Specialist_Id *uint16 `json:"specialist_id"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` } type ReadListDto struct { @@ -84,12 +84,13 @@ func (d *User) ToResponse() ResponseDto { } type EmployeUpdateDto struct { - Id uint `json:"id"` - User_Id *uint `json:"-"` - Person_Id *uint `json:"-"` - Division_Code *string `json:"division_code"` - Number *string `json:"number" validate:"maxLength=20"` - Status_Code erc.ActiveStatusCode `json:"status_code" validate:"maxLength=10"` + Id uint `json:"id"` + User_Id *uint `json:"-"` + Person_Id *uint `json:"-"` + Division_Code *string `json:"division_code"` + Number *string `json:"number" validate:"maxLength=20"` + Position_Code ero.EmployeePosisitionCode `json:"status_code" validate:"maxLength=10"` + Status_Code erc.ActiveStatusCode `json:"status_code" validate:"maxLength=10"` } func ToResponseList(data []User) []ResponseDto { diff --git a/internal/domain/main-entities/user/entity.go b/internal/domain/main-entities/user/entity.go index 4f7d8792..7a644262 100644 --- a/internal/domain/main-entities/user/entity.go +++ b/internal/domain/main-entities/user/entity.go @@ -9,13 +9,14 @@ import ( ) type User struct { - ecore.Main // adjust this according to the needs - Name string `json:"name" gorm:"unique;not null;size:25"` - Password string `json:"password" gorm:"not null;size:255"` - Status_Code erc.UserStatusCode `json:"status_code" gorm:"not null;size:10"` - FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` - Position_Code ero.UserPosisitionCode `json:"position_code" gorm:"not null;size:20"` - LoginAttemptCount int `json:"-"` - LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"` - LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` + ecore.Main // adjust this according to the needs + Name string `json:"name" gorm:"unique;not null;size:25"` + Password string `json:"password" gorm:"not null;size:255"` + Status_Code erc.UserStatusCode `json:"status_code" gorm:"not null;size:10"` + FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` + // Position_Code ero.EmployeePosisitionCode `json:"position_code" gorm:"not null;size:20"` + ContractPosition_Code ero.ContractPositionCode `json:"contractPosition_Code" gorm:"not null;size:20"` + LoginAttemptCount int `json:"-"` + LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"` + LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` } diff --git a/internal/interface/migration/main-entities.go b/internal/interface/migration/main-entities.go index ae155e9c..131b2972 100644 --- a/internal/interface/migration/main-entities.go +++ b/internal/interface/migration/main-entities.go @@ -25,6 +25,7 @@ import ( inpatient "simrs-vx/internal/domain/main-entities/inpatient" installation "simrs-vx/internal/domain/main-entities/installation" insurancecompany "simrs-vx/internal/domain/main-entities/insurance-company" + intern "simrs-vx/internal/domain/main-entities/intern" internalreference "simrs-vx/internal/domain/main-entities/internal-reference" item "simrs-vx/internal/domain/main-entities/item" itemprice "simrs-vx/internal/domain/main-entities/item-price" @@ -105,6 +106,7 @@ func getMainEntities() []any { &diagnosesrc.DiagnoseSrc{}, &proceduresrc.ProcedureSrc{}, &employee.Employee{}, + &intern.Intern{}, &doctor.Doctor{}, &nurse.Nurse{}, &nutritionist.Nutritionist{}, From d6c56b96b45b3561edf261db78dc752d4d6b1e5a Mon Sep 17 00:00:00 2001 From: Munawwirul Jamal Date: Sun, 19 Oct 2025 09:07:25 +0700 Subject: [PATCH 22/30] Merge dev into feat/user --- internal/domain/main-entities/user/dto.go | 8 +- internal/domain/main-entities/user/entity.go | 15 ++- .../references/organization/organization.go | 41 ++++--- .../main-use-case/authentication/case.go | 104 +++++++++++------- .../main-use-case/encounter/helper.go | 15 ++- internal/use-case/main-use-case/user/case.go | 64 +++-------- .../use-case/main-use-case/user/helper.go | 26 ++--- pkg/auth-helper/tycovar.go | 61 +++++++--- 8 files changed, 180 insertions(+), 154 deletions(-) diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index 093a597e..55a53686 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -1,22 +1,21 @@ package user import ( + ecore "simrs-vx/internal/domain/base-entities/core" "time" - ecore "simrs-vx/internal/domain/base-entities/core" ep "simrs-vx/internal/domain/main-entities/person" epa "simrs-vx/internal/domain/main-entities/person-address" epc "simrs-vx/internal/domain/main-entities/person-contact" erc "simrs-vx/internal/domain/references/common" - ero "simrs-vx/internal/domain/references/organization" + erg "simrs-vx/internal/domain/references/organization" ) type CreateDto struct { Name string `json:"name" validate:"maxLength=25"` Password string `json:"password" validate:"maxLength=255"` Status_Code erc.UserStatusCode `json:"status_code" validate:"maxLength=10"` - ContractPosition_Code ero.ContractPositionCode `json:"contractPosition_code" validate:"maxLength=20"` Person_Id *uint `json:"-"` Person *ep.UpdateDto `json:"person"` PersonAddresses []epa.UpdateDto `json:"personAddresses"` @@ -28,6 +27,7 @@ type CreateDto struct { Infra_Id *uint16 `json:"infra_id"` Specialist_Id *uint16 `json:"specialist_id"` Subspecialist_Id *uint16 `json:"subspecialist_id"` + ContractPosition_Code erg.ContractPositionCode `json:"contractPosition_code" gorm:"not null;size:20"` } type ReadListDto struct { @@ -89,7 +89,7 @@ type EmployeUpdateDto struct { Person_Id *uint `json:"-"` Division_Code *string `json:"division_code"` Number *string `json:"number" validate:"maxLength=20"` - Position_Code ero.EmployeePosisitionCode `json:"status_code" validate:"maxLength=10"` + Position_Code erg.EmployeePosisitionCode `json:"status_code" validate:"maxLength=10"` Status_Code erc.ActiveStatusCode `json:"status_code" validate:"maxLength=10"` } diff --git a/internal/domain/main-entities/user/entity.go b/internal/domain/main-entities/user/entity.go index 7a644262..f51dbf14 100644 --- a/internal/domain/main-entities/user/entity.go +++ b/internal/domain/main-entities/user/entity.go @@ -5,17 +5,16 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" erc "simrs-vx/internal/domain/references/common" - ero "simrs-vx/internal/domain/references/organization" + erg "simrs-vx/internal/domain/references/organization" ) type User struct { - ecore.Main // adjust this according to the needs - Name string `json:"name" gorm:"unique;not null;size:25"` - Password string `json:"password" gorm:"not null;size:255"` - Status_Code erc.UserStatusCode `json:"status_code" gorm:"not null;size:10"` - FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` - // Position_Code ero.EmployeePosisitionCode `json:"position_code" gorm:"not null;size:20"` - ContractPosition_Code ero.ContractPositionCode `json:"contractPosition_Code" gorm:"not null;size:20"` + ecore.Main // adjust this according to the needs + Name string `json:"name" gorm:"unique;not null;size:25"` + Password string `json:"password" gorm:"not null;size:255"` + Status_Code erc.UserStatusCode `json:"status_code" gorm:"not null;size:10"` + ContractPosition_Code erg.ContractPositionCode `json:"contractPosition_code" gorm:"not null;size:20"` + FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` LoginAttemptCount int `json:"-"` LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"` LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index 04c4fa2a..60270a93 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -1,26 +1,33 @@ package organization type ( - UserPosisitionCode string - ItemGroupCode string - InfraGroupCode string - UnitTypeCode string - DoctorFeeTypeCode string + ContractPositionCode string + EmployeePosisitionCode string + InternPosisitionCode string + ItemGroupCode string + InfraGroupCode string + UnitTypeCode string + DoctorFeeTypeCode string ) const ( - UPCReg UserPosisitionCode = "registration" // Admisi/Pendaftaran - UPCNur UserPosisitionCode = "nurse" // Perawat - UPCDoc UserPosisitionCode = "doctor" // Dokter - UPCNut UserPosisitionCode = "nutritionist" // Ahli gizi - UPCMwi UserPosisitionCode = "mid-wife" // Bidan - UPCLab UserPosisitionCode = "laborant" // Laboran - UPCPha UserPosisitionCode = "pharmacy" // Farmasi - UPCPay UserPosisitionCode = "payment" // Pembayaran - UPCHur UserPosisitionCode = "human-resource" // Sumber Daya Manusia - UPCGea UserPosisitionCode = "general-affair" // Bagian Umum - UPCInt UserPosisitionCode = "specialist-intern" // PPDS - UPCMan UserPosisitionCode = "management" // Manajemen + CSCEmp ContractPositionCode = "employee" // Pegawai + CSCSpi ContractPositionCode = "intern" // PPDS + + EPCReg EmployeePosisitionCode = "registration" // Admisi/Pendaftaran + EPCNur EmployeePosisitionCode = "nurse" // Perawat + EPCDoc EmployeePosisitionCode = "doctor" // Dokter + EPCNut EmployeePosisitionCode = "nutritionist" // Ahli gizi + EPCMwi EmployeePosisitionCode = "mid-wife" // Bidan + EPCLab EmployeePosisitionCode = "laborant" // Laboran + EPCPha EmployeePosisitionCode = "pharmacy" // Farmasi + EPCPay EmployeePosisitionCode = "payment" // Pembayaran + EPCHur EmployeePosisitionCode = "human-resource" // Sumber Daya Manusia + EPCGea EmployeePosisitionCode = "general-affair" // Bagian Umum + EPCMan EmployeePosisitionCode = "management" // Manajemen + + IPCSpecialist = "specialist-intern" + IPCNurse = "nurse-intern" ITGCInfra ItemGroupCode = "infra" ITGCMedicine ItemGroupCode = "medicine" diff --git a/internal/use-case/main-use-case/authentication/case.go b/internal/use-case/main-use-case/authentication/case.go index b6e9f2f4..e03b0293 100644 --- a/internal/use-case/main-use-case/authentication/case.go +++ b/internal/use-case/main-use-case/authentication/case.go @@ -11,12 +11,14 @@ import ( "github.com/google/uuid" eu "simrs-vx/internal/domain/main-entities/user" - erc "simrs-vx/internal/domain/references/common" pa "simrs-vx/pkg/auth-helper" el "simrs-vx/pkg/logger" p "simrs-vx/pkg/password" + ee "simrs-vx/internal/domain/main-entities/employee" + erc "simrs-vx/internal/domain/references/common" + a "github.com/karincake/apem" dg "github.com/karincake/apem/db-gorm-pg" ms "github.com/karincake/apem/ms-redis" @@ -90,11 +92,26 @@ func GenToken(input eu.LoginDto) (*d.Data, error) { atExpires := time.Now().Add(duration).Unix() atSecretKey := authCfg.AtSecretKey + // extra + role := []string{} + if user.ContractPosition_Code == "employee" { + employee := ee.Employee{} + dg.I.Where("user_id = ?", user.Id).First(&employee) + role = append(role, "emp-"+string(*employee.Position_Code)) + } else if user.ContractPosition_Code == "intern" { + // specialistIntern := esi.SpecialistIntern{} + // dg.I.Where("user_id = ?", user.Id).First(&specialistIntern) + role = append(role, "spi") + } + // Creating Access Token atClaims := jwt.MapClaims{} atClaims["user_id"] = user.Id atClaims["user_name"] = user.Name - atClaims["user_position_code"] = user.Position_Code + // atClaims["user_email"] = user.Email + // atClaims["user_position_code"] = user.Position_Code + atClaims["user_employementStatus_code"] = user.ContractPosition_Code + // atClaims["user_ref_id"] = user.Ref_Id atClaims["exp"] = atExpires atClaims["uuid"] = aUuid atClaims["user_division_positions"] = userDivisionPositions @@ -104,6 +121,15 @@ func GenToken(input eu.LoginDto) (*d.Data, error) { return nil, d.FieldErrors{"user": d.FieldError{Code: "token-sign-err", Message: el.GenMessage("token-sign-err")}} } + outputData := d.II{ + "user_id": strconv.Itoa(int(user.Id)), + "user_name": user.Name, + // "user_email": user.Email, + "user_contractPosition_code": user.ContractPosition_Code, + // "user_ref_id": user.Ref_Id, + "accessToken": ats, + } + // Save to redis now := time.Now() atx := time.Unix(atExpires, 0) //converting Unix to UTC(to Time object) @@ -125,13 +151,7 @@ func GenToken(input eu.LoginDto) (*d.Data, error) { "structure": "single-data", "status": "verified", }, - Data: d.II{ - "user_id": strconv.Itoa(int(user.Id)), - "user_name": user.Name, - "user_position_code": user.Position_Code, - "accessToken": ats, - "user_division_positions": userDivisionPositions, - }, + Data: outputData, }, nil } @@ -186,41 +206,41 @@ func ExtractToken(r *http.Request, tokenType TokenType) (data *pa.AuthInfo, err return nil, d.FieldError{Code: "token-unidentified", Message: el.GenMessage("token-unidentified")} } user_name := fmt.Sprintf("%v", claims["user_name"]) + // user_email := "" + // if v, exist := claims["user_email"]; exist && v != nil { + // user_email = v.(string) + // } + // ref_id := 0 + // if v, exist := claims["user_ref_id"]; exist && v != nil { + // tmp := v.(float64) + // ref_id = int(tmp) + // } + // position_code := "" + // if v, exist := claims["user_position_code"]; exist && v != nil { + // position_code = v.(string) + // } + // data = &AuthInfo{ + // Uuid: accessUuid, + // User_Id: int(user_id), + // User_Name: user_name, + // User_Email: user_email, + // User_Ref_Id: ref_id, + // User_Position_Code: position_code, + contractPosition_code := "" + if v, exist := claims["contractPosition_code"]; exist && v != nil { + contractPosition_code = v.(string) + } + employee_position_code := "" + if v, exist := claims["employee_position_code"]; exist && v != nil { + employee_position_code = v.(string) + } - var userDivisionPositions []pa.DivisionPosition - raw := claims["user_division_positions"] - if raw == nil { - fmt.Println("No user_division_positions found in claims") - } else { - list, ok := raw.([]interface{}) - if !ok { - fmt.Printf("user_division_positions is not []interface{}, but %T\n", raw) - } else { - fmt.Printf("Found %d division positions\n", len(list)) - for i, item := range list { - if m, ok := item.(map[string]interface{}); ok { - fmt.Printf("Item %d: %v\n", i, m) - dp := pa.DivisionPosition{ - Division_Code: fmt.Sprintf("%v", m["division_code"]), - DivisionPosition_Code: fmt.Sprintf("%v", m["divisionPosition_code"]), - } - userDivisionPositions = append(userDivisionPositions, dp) - } else { - fmt.Printf("Item %d not map[string]interface{} but %T\n", i, item) - } - } - } - } - position_code := "" - if v, exist := claims["user_position_code"]; exist && v != nil { - position_code = v.(string) - } data = &pa.AuthInfo{ - Uuid: accessUuid, - User_Id: uint(user_id), - User_Name: user_name, - User_Position_Code: position_code, - User_DivisionPositions: userDivisionPositions, + Uuid: accessUuid, + User_Id: uint(user_id), + User_Name: user_name, + User_ContractPosition_code: contractPosition_code, + Employee_Position_Code: &employee_position_code, } return } diff --git a/internal/use-case/main-use-case/encounter/helper.go b/internal/use-case/main-use-case/encounter/helper.go index 20abadd1..0ee5d2cd 100644 --- a/internal/use-case/main-use-case/encounter/helper.go +++ b/internal/use-case/main-use-case/encounter/helper.go @@ -9,8 +9,10 @@ import ( "fmt" "strings" - e "simrs-vx/internal/domain/main-entities/encounter" - es "simrs-vx/internal/domain/main-entities/soapi" + "gorm.io/gorm" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" edo "simrs-vx/internal/domain/main-entities/device-order" emo "simrs-vx/internal/domain/main-entities/material-order" @@ -23,6 +25,7 @@ import ( epi "simrs-vx/internal/domain/main-entities/prescription-item" // udo "simrs-vx/internal/use-case/main-use-case/device-order" + es "simrs-vx/internal/domain/main-entities/soapi" um "simrs-vx/internal/use-case/main-use-case/medication" umei "simrs-vx/internal/use-case/main-use-case/medication-item" umi "simrs-vx/internal/use-case/main-use-case/medicine-mix" @@ -30,13 +33,9 @@ import ( up "simrs-vx/internal/use-case/main-use-case/prescription" upi "simrs-vx/internal/use-case/main-use-case/prescription-item" - pl "simrs-vx/pkg/logger" - pu "simrs-vx/pkg/use-case-helper" - + e "simrs-vx/internal/domain/main-entities/encounter" erc "simrs-vx/internal/domain/references/common" ero "simrs-vx/internal/domain/references/organization" - - "gorm.io/gorm" ) func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) { @@ -114,7 +113,7 @@ func checkSoapiByDocExists(encounter_id uint, event *pl.Event, tx *gorm.DB) erro } for _, s := range soapies { - if s.Employee != nil && s.Employee.User != nil && s.Employee.User.Position_Code == ero.UPCDoc { + if s.Employee != nil && s.Employee.User != nil && *s.Employee.Position_Code == ero.EPCDoc { return nil } } diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index ba5859ee..ca5d0485 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -9,7 +9,6 @@ import ( ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/employee" el "simrs-vx/internal/domain/main-entities/laborant" - em "simrs-vx/internal/domain/main-entities/midwife" en "simrs-vx/internal/domain/main-entities/nurse" et "simrs-vx/internal/domain/main-entities/nutritionist" ep "simrs-vx/internal/domain/main-entities/pharmacist" @@ -19,7 +18,6 @@ import ( ud "simrs-vx/internal/use-case/main-use-case/doctor" ue "simrs-vx/internal/use-case/main-use-case/employee" ul "simrs-vx/internal/use-case/main-use-case/laborant" - um "simrs-vx/internal/use-case/main-use-case/midwife" un "simrs-vx/internal/use-case/main-use-case/nurse" ut "simrs-vx/internal/use-case/main-use-case/nutritionist" upe "simrs-vx/internal/use-case/main-use-case/person" @@ -85,7 +83,7 @@ func Create(input e.CreateDto) (*d.Data, error) { data = *resData } - if input.Position_Code == ero.UPCInt { + if input.ContractPosition_Code == ero.CSCSpi { createInt := esi.CreateDto{ Person_Id: input.Person_Id, Specialist_Id: input.Specialist_Id, @@ -105,8 +103,8 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } - switch input.Position_Code { - case ero.UPCDoc: + switch input.Employee.Position_Code { + case ero.EPCDoc: createDoc := ed.CreateDto{ Employee_Id: &employeeData.Id, IHS_Number: input.IHS_Number, @@ -118,7 +116,7 @@ func Create(input e.CreateDto) (*d.Data, error) { if _, err := ud.CreateData(createDoc, &event, tx); err != nil { return err } - case ero.UPCNur: + case ero.EPCNur: createNurse := en.CreateDto{ Employee_Id: &employeeData.Id, IHS_Number: input.IHS_Number, @@ -128,7 +126,7 @@ func Create(input e.CreateDto) (*d.Data, error) { if _, err := un.CreateData(createNurse, &event, tx); err != nil { return err } - case ero.UPCNut: + case ero.EPCNut: createNutritionist := et.CreateDto{ Employee_Id: &employeeData.Id, IHS_Number: input.IHS_Number, @@ -136,7 +134,7 @@ func Create(input e.CreateDto) (*d.Data, error) { if _, err := ut.CreateData(createNutritionist, &event, tx); err != nil { return err } - case ero.UPCPha: + case ero.EPCPha: createPharmacist := ep.CreateDto{ Employee_Id: &employeeData.Id, IHS_Number: input.IHS_Number, @@ -144,7 +142,7 @@ func Create(input e.CreateDto) (*d.Data, error) { if _, err := up.CreateData(createPharmacist, &event, tx); err != nil { return err } - case ero.UPCLab: + case ero.EPCLab: createLaborant := el.CreateDto{ Employee_Id: &employeeData.Id, IHS_Number: input.IHS_Number, @@ -152,16 +150,6 @@ func Create(input e.CreateDto) (*d.Data, error) { if _, err := ul.CreateData(createLaborant, &event, tx); err != nil { return err } - case ero.UPCMwi: - createMidwife := em.CreateDto{ - Employee_Id: &employeeData.Id, - IHS_Number: input.IHS_Number, - } - if _, err := um.CreateData(em.CreateDto(createMidwife), &event, tx); err != nil { - return err - } - case ero.UPCReg, ero.UPCHur, ero.UPCGea, ero.UPCMan: - // do nothing default: return errors.New("invalid employee position") } @@ -317,7 +305,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - person_id, err := getPersonIdByUserId(data.Id, input.Position_Code, &event, tx) + person_id, err := getPersonIdByUserId(data.Id, input.ContractPosition_Code, &event, tx) if err != nil { return err } else { @@ -348,7 +336,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - if input.Position_Code == ero.UPCInt { + if input.ContractPosition_Code == ero.CSCSpi { readInt := esi.ReadDetailDto{User_Id: &data.Id} readIntData, err := usi.ReadDetailData(readInt, &event, tx) if err != nil { @@ -384,8 +372,8 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - switch input.Position_Code { - case ero.UPCDoc: + switch input.Employee.Position_Code { + case ero.EPCDoc: readDoc := ed.ReadDetailDto{Employee_Id: &employeeData.Id} readDocData, err := ud.ReadDetailData(readDoc, &event, tx) if err != nil { @@ -407,7 +395,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { if _, err := ud.CreateData(createDoc, &event, tx); err != nil { return err } - case ero.UPCNur: + case ero.EPCNur: readNur := en.ReadDetailDto{Employee_Id: &employeeData.Id} readNurData, err := un.ReadDetailData(readNur, &event, tx) if err != nil { @@ -427,7 +415,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { if _, err := un.CreateData(createNur, &event, tx); err != nil { return err } - case ero.UPCNut: + case ero.EPCNut: readNut := et.ReadDetailDto{Employee_Id: &employeeData.Id} readNutData, err := ut.ReadDetailData(readNut, &event, tx) if err != nil { @@ -447,7 +435,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { if _, err := ut.CreateData(createNut, &event, tx); err != nil { return err } - case ero.UPCPha: + case ero.EPCPha: readPha := ep.ReadDetailDto{Employee_Id: &employeeData.Id} readPhaData, err := up.ReadDetailData(readPha, &event, tx) if err != nil { @@ -467,7 +455,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { if _, err := up.CreateData(createPha, &event, tx); err != nil { return err } - case ero.UPCLab: + case ero.EPCLab: readLab := el.ReadDetailDto{Employee_Id: &employeeData.Id} readLabData, err := ul.ReadDetailData(readLab, &event, tx) if err != nil { @@ -487,28 +475,6 @@ func Update(input e.UpdateDto) (*d.Data, error) { if _, err := ul.CreateData(createLab, &event, tx); err != nil { return err } - case ero.UPCMwi: - readMidwife := em.ReadDetailDto{Employee_Id: &employeeData.Id} - readMidwifeData, err := um.ReadDetailData(readMidwife, &event, tx) - if err != nil { - return err - } - createMidwife := em.CreateDto{ - Employee_Id: &employeeData.Id, - IHS_Number: input.IHS_Number, - } - if readMidwifeData != nil { - if err := um.UpdateData(em.UpdateDto{CreateDto: createMidwife}, readMidwifeData, &event, tx); err != nil { - return err - } - return nil - } - - if _, err := um.CreateData(createMidwife, &event, tx); err != nil { - return err - } - case ero.UPCReg, ero.UPCHur, ero.UPCGea, ero.UPCMan: - // do nothing default: return errors.New("invalid employee position") } diff --git a/internal/use-case/main-use-case/user/helper.go b/internal/use-case/main-use-case/user/helper.go index 111d333f..4ce0259d 100644 --- a/internal/use-case/main-use-case/user/helper.go +++ b/internal/use-case/main-use-case/user/helper.go @@ -6,19 +6,19 @@ package user import ( "errors" - ee "simrs-vx/internal/domain/main-entities/employee" - esi "simrs-vx/internal/domain/main-entities/specialist-intern" - e "simrs-vx/internal/domain/main-entities/user" - ue "simrs-vx/internal/use-case/main-use-case/employee" - usi "simrs-vx/internal/use-case/main-use-case/specialist-intern" - - ero "simrs-vx/internal/domain/references/organization" + "gorm.io/gorm" pl "simrs-vx/pkg/logger" p "simrs-vx/pkg/password" - "gorm.io/gorm" + ue "simrs-vx/internal/use-case/main-use-case/employee" + usi "simrs-vx/internal/use-case/main-use-case/specialist-intern" + + ee "simrs-vx/internal/domain/main-entities/employee" + esi "simrs-vx/internal/domain/main-entities/specialist-intern" + e "simrs-vx/internal/domain/main-entities/user" + erg "simrs-vx/internal/domain/references/organization" ) func setCreate(src e.CreateDto, dst *e.User) error { @@ -30,15 +30,14 @@ func setCreate(src e.CreateDto, dst *e.User) error { dst.Name = src.Name dst.Password = pass dst.Status_Code = src.Status_Code - dst.Position_Code = src.Position_Code + dst.ContractPosition_Code = src.ContractPosition_Code return nil } func setUpdate(src e.UpdateDto, dst *e.User) { dst.Status_Code = src.Status_Code - dst.Position_Code = src.Position_Code - + dst.ContractPosition_Code = src.ContractPosition_Code } func setDataEmployeeUpdate(src e.EmployeUpdateDto) ee.UpdateDto { @@ -54,9 +53,10 @@ func setDataEmployeeUpdate(src e.EmployeUpdateDto) ee.UpdateDto { } } -func getPersonIdByUserId(userId uint, positionCode ero.UserPosisitionCode, event *pl.Event, tx *gorm.DB) (*uint, error) { +func getPersonIdByUserId(userId uint, positionCode erg.ContractPositionCode, event *pl.Event, tx *gorm.DB) (*uint, error) { pl.SetLogInfo(event, nil, "started", "DBGetPersonIdByUserId") - if positionCode == ero.UPCInt { + if positionCode == erg.CSCEmp { + } else if positionCode == erg.CSCSpi { specInt, err := usi.ReadDetailData(esi.ReadDetailDto{User_Id: &userId}, event, tx) if err != nil { return nil, err diff --git a/pkg/auth-helper/tycovar.go b/pkg/auth-helper/tycovar.go index 288c9d21..06618350 100644 --- a/pkg/auth-helper/tycovar.go +++ b/pkg/auth-helper/tycovar.go @@ -7,11 +7,15 @@ import ( type AuthKey struct{} type AuthInfo struct { - Uuid string - User_Id uint - User_Name string - User_DivisionPositions []DivisionPosition - User_Position_Code string + Uuid string + User_Id uint + User_Name string + User_ContractPosition_code string + Employee_Position_Code *string + Intern_Position_Code *string + User_DivisionPositions []DivisionPosition + // User_DivisionPositions []DivisionPosition + // User_Position_Code string } type DivisionPosition struct { @@ -20,33 +24,64 @@ type DivisionPosition struct { } func (a AuthInfo) IsDoctor() bool { - return a.User_Position_Code == string(ero.UPCDoc) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCDoc) } func (a AuthInfo) IsNurse() bool { - return a.User_Position_Code == string(ero.UPCNur) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCNur) } func (a AuthInfo) IsNutritionist() bool { - return a.User_Position_Code == string(ero.UPCNut) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCNut) } func (a AuthInfo) IsLaborant() bool { - return a.User_Position_Code == string(ero.UPCLab) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCLab) } func (a AuthInfo) IsPharmacist() bool { - return a.User_Position_Code == string(ero.UPCPha) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCPha) } func (a AuthInfo) IsPayment() bool { - return a.User_Position_Code == string(ero.UPCPay) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCPay) } func (a AuthInfo) IsManagement() bool { - return a.User_Position_Code == string(ero.UPCMan) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCMan) } func (a AuthInfo) IsSpecialistIntern() bool { - return a.User_Position_Code == string(ero.UPCInt) + if a.Intern_Position_Code == nil { + return false + } + return *a.Intern_Position_Code == string(ero.IPCSpecialist) +} + +func (a AuthInfo) IsNurseIntern() bool { + if a.Intern_Position_Code == nil { + return false + } + return *a.Intern_Position_Code == string(ero.IPCNurse) } From 19e5ddf65d575f64965764170645302738fb0db6 Mon Sep 17 00:00:00 2001 From: Munawwirul Jamal Date: Sun, 19 Oct 2025 15:10:14 +0700 Subject: [PATCH 23/30] feat/user: reworking auth --- .../references/organization/organization.go | 2 +- .../main-use-case/authentication/case.go | 76 ++++++++++++------- .../main-use-case/authentication/helper.go | 2 +- internal/use-case/main-use-case/user/case.go | 4 +- .../use-case/main-use-case/user/helper.go | 2 +- 5 files changed, 53 insertions(+), 33 deletions(-) diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index 60270a93..93eabe63 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -12,7 +12,7 @@ type ( const ( CSCEmp ContractPositionCode = "employee" // Pegawai - CSCSpi ContractPositionCode = "intern" // PPDS + CSCInt ContractPositionCode = "intern" // PPDS EPCReg EmployeePosisitionCode = "registration" // Admisi/Pendaftaran EPCNur EmployeePosisitionCode = "nurse" // Perawat diff --git a/internal/use-case/main-use-case/authentication/case.go b/internal/use-case/main-use-case/authentication/case.go index e03b0293..f9aec70c 100644 --- a/internal/use-case/main-use-case/authentication/case.go +++ b/internal/use-case/main-use-case/authentication/case.go @@ -10,14 +10,17 @@ import ( "github.com/golang-jwt/jwt" "github.com/google/uuid" + "simrs-vx/internal/domain/main-entities/intern" eu "simrs-vx/internal/domain/main-entities/user" pa "simrs-vx/pkg/auth-helper" el "simrs-vx/pkg/logger" p "simrs-vx/pkg/password" + ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/employee" erc "simrs-vx/internal/domain/references/common" + erg "simrs-vx/internal/domain/references/organization" a "github.com/karincake/apem" dg "github.com/karincake/apem/db-gorm-pg" @@ -92,43 +95,60 @@ func GenToken(input eu.LoginDto) (*d.Data, error) { atExpires := time.Now().Add(duration).Unix() atSecretKey := authCfg.AtSecretKey - // extra - role := []string{} - if user.ContractPosition_Code == "employee" { - employee := ee.Employee{} - dg.I.Where("user_id = ?", user.Id).First(&employee) - role = append(role, "emp-"+string(*employee.Position_Code)) - } else if user.ContractPosition_Code == "intern" { - // specialistIntern := esi.SpecialistIntern{} - // dg.I.Where("user_id = ?", user.Id).First(&specialistIntern) - role = append(role, "spi") - } - - // Creating Access Token + // Create Claim atClaims := jwt.MapClaims{} atClaims["user_id"] = user.Id atClaims["user_name"] = user.Name - // atClaims["user_email"] = user.Email - // atClaims["user_position_code"] = user.Position_Code - atClaims["user_employementStatus_code"] = user.ContractPosition_Code - // atClaims["user_ref_id"] = user.Ref_Id - atClaims["exp"] = atExpires + atClaims["user_contractPosition_code"] = user.ContractPosition_Code + atClaims["division_positions"] = userDivisionPositions atClaims["uuid"] = aUuid - atClaims["user_division_positions"] = userDivisionPositions + atClaims["exp"] = atExpires + + // Create output + outputData := d.II{ + "user_id": strconv.Itoa(int(user.Id)), + "user_name": user.Name, + "user_contractPosition_code": user.ContractPosition_Code, + } + + // extra + role := []string{} + switch user.ContractPosition_Code { + case erg.CSCEmp: + // employee + employee := ee.Employee{} + dg.I.Where("\"User_Id\" = ?", user.Id).First(&employee) + role = append(role, "emp-"+string(*employee.Position_Code)) + atClaims["employee_division_code"] = employee.Division_Code + outputData["employee_division_code"] = employee.Division_Code + // doctor + if employee.Id > 0 && employee.Position_Code != nil && *employee.Position_Code == erg.EPCDoc { + doctor := ed.Doctor{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&doctor) + if doctor.Specialist_Id != nil { + atClaims["specialist_id"] = doctor.Specialist_Id + outputData["specialist_id"] = doctor.Specialist_Id + } + if doctor.Subspecialist_Id != nil { + atClaims["subspecialist_id"] = doctor.Subspecialist_Id + outputData["subspecialist_id"] = doctor.Subspecialist_Id + } + } + case erg.CSCInt: + intern := intern.Intern{} + dg.I.Where("\"User_Id\" = ?", user.Id).First(&intern) + role = append(role, "int-"+string(*intern.Position_Code)) + } + atClaims["roles"] = role + outputData["roles"] = role + + // Generate jwt at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims) ats, err := at.SignedString([]byte(atSecretKey)) if err != nil { return nil, d.FieldErrors{"user": d.FieldError{Code: "token-sign-err", Message: el.GenMessage("token-sign-err")}} } - - outputData := d.II{ - "user_id": strconv.Itoa(int(user.Id)), - "user_name": user.Name, - // "user_email": user.Email, - "user_contractPosition_code": user.ContractPosition_Code, - // "user_ref_id": user.Ref_Id, - "accessToken": ats, - } + outputData["accessToken"] = ats // Save to redis now := time.Now() diff --git a/internal/use-case/main-use-case/authentication/helper.go b/internal/use-case/main-use-case/authentication/helper.go index 50b0c8fd..fef5b07e 100644 --- a/internal/use-case/main-use-case/authentication/helper.go +++ b/internal/use-case/main-use-case/authentication/helper.go @@ -54,7 +54,7 @@ func getDivisionPosition(user_id uint) ([]pa.DivisionPosition, error) { result = append(result, pa.DivisionPosition{ Division_Code: func() string { if dp.Division != nil { - return dp.Division.Code + return "div-" + dp.Division.Code } return "" }(), diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index ca5d0485..7d2053de 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -83,7 +83,7 @@ func Create(input e.CreateDto) (*d.Data, error) { data = *resData } - if input.ContractPosition_Code == ero.CSCSpi { + if input.ContractPosition_Code == ero.CSCInt { createInt := esi.CreateDto{ Person_Id: input.Person_Id, Specialist_Id: input.Specialist_Id, @@ -336,7 +336,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - if input.ContractPosition_Code == ero.CSCSpi { + if input.ContractPosition_Code == ero.CSCInt { readInt := esi.ReadDetailDto{User_Id: &data.Id} readIntData, err := usi.ReadDetailData(readInt, &event, tx) if err != nil { diff --git a/internal/use-case/main-use-case/user/helper.go b/internal/use-case/main-use-case/user/helper.go index 4ce0259d..1663bb24 100644 --- a/internal/use-case/main-use-case/user/helper.go +++ b/internal/use-case/main-use-case/user/helper.go @@ -56,7 +56,7 @@ func setDataEmployeeUpdate(src e.EmployeUpdateDto) ee.UpdateDto { func getPersonIdByUserId(userId uint, positionCode erg.ContractPositionCode, event *pl.Event, tx *gorm.DB) (*uint, error) { pl.SetLogInfo(event, nil, "started", "DBGetPersonIdByUserId") if positionCode == erg.CSCEmp { - } else if positionCode == erg.CSCSpi { + } else if positionCode == erg.CSCInt { specInt, err := usi.ReadDetailData(esi.ReadDetailDto{User_Id: &userId}, event, tx) if err != nil { return nil, err From a8aa3a22f1f4e55e6d045d127cc02efda649d971 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sun, 19 Oct 2025 15:20:05 +0700 Subject: [PATCH 24/30] updated hash from server --- cmd/main-migration/migrations/atlas.sum | 102 ++++++++++++------------ 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index 77732bde..42636d28 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,51 +1,51 @@ -h1:/NZRnBd4SNPxw+Sv7Fhn/VBxN0wRNU4OldkTUn6GtbI= -20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= -20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= -20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= -20250908062323.sql h1:oXl6Z143tOpIl4EfP4B8JNU8LrMvVmHEtCgAfiB4gs8= -20250908073811.sql h1:m2aNXfnGxnLq1+rVWrh4f60q7fhyhV3gEwNu/OIqQlE= -20250908073839.sql h1:cPk54xjLdMs26uY8ZHjNWLuyfAMzV7Zb0/9oJQrsw04= -20250910055902.sql h1:5xwjAV6QbtZT9empTJKfhyAjdknbHzb15B0Ku5dzqtQ= -20250915123412.sql h1:D83xaU2YlDEd21HLup/YQpQ2easMToYCyy/oK6AFgQs= -20250916043819.sql h1:ekoTJsBqQZ8G8n0qJ03d13+eoNoc7sAUEQGA5D/CCxk= -20250917040616.sql h1:zoCnmcXuM7AVv85SmN7RmFglCgJnoDmpRWExH0LAc9Q= -20250917040751.sql h1:J1xyRrh32y1+lezwAyNwPcUQ6ABBSgbvzNLva4SVdQU= -20250917045138.sql h1:jKe1Z0uOLG4SGBYM+S/3P+/zMPztmgoderD5swnMuCg= -20250917093645.sql h1:cNI3Pbz1R3LxvIXLuexafJFCXUXrmuFCgXXJ2sG+FW0= -20250918073552.sql h1:RJ1SvMzP6aeWnoPVD3eVAmIQOkcp6Php8z3QRri6v4g= -20250918073742.sql h1:+cEsnJTJFybe2fR69ZoOiX2R6c6iITl4m6WTZ1hjyzY= -20250918074745.sql h1:2hNVQCXF/dVYXAh+T/7oBFgERGWxzVb2FXJjwkFWGCI= -20250923025134.sql h1:Ykz/qpHiGDXPsCsWTjydQFVSibZP2D+h2fIeb2h2JGA= -20250924051317.sql h1:yQuW6SwJxIOM5fcxeAaie5lSm1oLysU/C2hH2xNCVoQ= -20250929034321.sql h1:101FJ8VH12mrZWlt/X1gvKUGOhoiF8tFbjiapAjnHzg= -20250929034428.sql h1:i+pROD9p+g5dOmmZma6WF/0Hw5g3Ha28NN85iTo1K34= -20250930025550.sql h1:+F+CsCUXD/ql0tHGEow70GhPBX1ZybVn+bh/T4YMh7Y= -20250930140351.sql h1:9AAEG1AnOAH+o0+oHL5G7I8vqlWOhwRlCGyyCpT/y1Q= -20251002085604.sql h1:3xZ68eYp4urXRnvotNH1XvG2mYOSDV/j3zHEZ/txg5E= -20251003032030.sql h1:HB+mQ2lXMNomHDpaRhB/9IwYI9/YiDO5eOJ+nAQH/jw= -20251005060450.sql h1:LbtCE2b+8osM3CvnmQJH1uCPtn+d7WchsslBOz8bL3Q= -20251006041122.sql h1:MlS7f21z06sutnf9dIekt5fuHJr4lgcQ4uCuCXAGsfc= -20251006045658.sql h1:3FmGCPCzjgMPdWDRodZTsx3KVaodd9zB9ilib69aewk= -20251006045928.sql h1:Z5g31PmnzNwk/OKdODcxZGm8fjJQdMFK32Xfnt3bRHg= -20251007022859.sql h1:FO03zEfaNEk/aXwY81d5Lp3MoBB9kPQuXlXJ4BPiSR8= -20251008031337.sql h1:l+sxUAGvcTfj3I6kAFHo+T6AYodC9k9GkR+jaKO2xXc= -20251008031554.sql h1:AqrVfIhSzY3PCy8ZlP5W91wn2iznfIuj5qQfubp6/94= -20251008052346.sql h1:nxnXmooIJ6r1mmzwnw+6efxLfc/k9h2aE6RMptPRons= -20251008073620.sql h1:6YsJp1W4SmQJ1lxpqF27BBlDC1zqhw7Yhc7pLzQTY6M= -20251009042854.sql h1:nkBV+R6j0fg7/JY6wH3eb5Vv0asJLnXmb6lINfT/GLQ= -20251009052657.sql h1:EPvdsib5rzCGPryd10HShGKvFPwM/R5S2lIVwtYxpms= -20251010031743.sql h1:T8IZmx8/btRFKLzTe78MzcBsPJNodnLvB0tby9QkirQ= -20251010070721.sql h1:5NQUk/yOV6sABLCB7swx++YIOyJe6MnU+yt1nRzde5w= -20251010072711.sql h1:ZJNqR2piyu8xJhBvVABSlnGEoKSKae3wuEs+wshPe4k= -20251013044536.sql h1:0Xjw8fNILiT8nnfrJDZgQnPf3dntmIoilbapnih8AE4= -20251013051438.sql h1:lfSuw5mgJnePBJamvhZ81osFIouXeiIEiSZ/evdwo48= -20251013081808.sql h1:ijgjNX08G6GBjA/ks8EKtb7P7Y7Cg7zbhqEOruGnv6M= -20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= -20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= -20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= -20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= -20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= -20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= -20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= -20251017060617.sql h1:4T3t9ifWrEQTPMSM0XJ98pF7Qdt+UfgtMui17bhrnWI= -20251017082207.sql h1:M3k5WPGt8gxv/4kB71di+78L/FyXrxhgGtXxGedwEps= +h1:8zie3PyS55y+G80bxoc2K/aE8n0tDc8iH3Tc+FUB4o8= +20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= +20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= +20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI= +20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= +20250908073811.sql h1:gOi5cnGG1htlpfizybYmUIT0vYjZTBfXiI0nPSYK2u8= +20250908073839.sql h1:cWNDA4YikjoOteAJuNLFILjQUJPFB6o8Wxreiek4QyI= +20250910055902.sql h1:nxxOGnU0BbH/v3IPgeIOXOwH8d3tKomw7h6FTeMnnBs= +20250915123412.sql h1:mz7SiWfrdf0qE1VTSAAnA/147d6gyp6ry5vZ2bR9SH0= +20250916043819.sql h1:RHXVtmMkB6wfv06HfPyHMBmUfIpFt1xveafNz0kwKnE= +20250917040616.sql h1:MYVDht+akBlzQGKNu2hTTTLPEcH1bxT/Q8MK6WEtuhs= +20250917040751.sql h1:J79YyS2JzWgh5oKXMTgh67uo3gLxKaAsxRiZmSIfjBs= +20250917045138.sql h1:/SM1N4O8X3yxpoJgMEARmS1uOkuLKsTOy4PLsRCOKaQ= +20250917093645.sql h1:PNBTGZ7s10e5b5+Tie8YfVQBN0zKtJ5T34oK1iOUEb4= +20250918073552.sql h1:jG7+g3i8ODYaJdcdZz12v3nbsZ5mB9wG6kWnGyTQIRI= +20250918073742.sql h1:j+rgw7puxE7s+phqPVZHmPk0af3rcaA56Itp86y1suY= +20250918074745.sql h1:rPmP4DXs6OnY4Vp+xO/z9jFpJt/RrJ52SJJjIIxeDvc= +20250923025134.sql h1:2r6pcwnBSU5Y9Czk1OHBoh4yZXiMtEca9X8843fTEX0= +20250924051317.sql h1:iUAk2gsGoEGIPQ0lEEUp8maMSId8emNbP+kP712ABIA= +20250929034321.sql h1:UlpALNVmdi95zOIT0yc6ZyTj9bBjQEIpZhvgrc52M+k= +20250929034428.sql h1:feF+H4nDyHh5bdx48Oiz0A1qecZfi6v3qTTdjzJ45Dg= +20250930025550.sql h1:6XT1kXI3Z3ZIxxmvT7poufZWWCW0QiejZPaFV5wBnjI= +20250930140351.sql h1:HxnmAbh9gCy8jwl/9ycGktiByaUripsjFFvohofY2CY= +20251002085604.sql h1:SjLPi+ZN6qDccK3DaEQCgNsZpPwr5kynWXwbwEsziCI= +20251003032030.sql h1:oHfxNSuqTxU8Zaf9H+h8TuUb1Da03wcyc6hZjDrUQ2s= +20251005060450.sql h1:GIuCcrd4MwjmXpvbzDzPYL18BV3QaZZ+Y2FmEzjvi0E= +20251006041122.sql h1:uNDQbSw0M08lYoMvUNlQtS3iDzpPM1ixT13ugSAoWjE= +20251006045658.sql h1:z+t7yCK54Q4SSiF9kUyUhkYB2F+kzSW9TB7ogxd9wzw= +20251006045928.sql h1:1lATLFLp4BWwGZqAjZdP0Dc6ypNXiYcwjoNkqGa8NFE= +20251007022859.sql h1:HXXwWrkyvzJzJGAt9mGskCRBBV/c1JfPmfjDocmJhQ4= +20251008031337.sql h1:Ln5pCF3Hxa5foHZLcds+z/us2eH6VAhhEj3w0TAGlVs= +20251008031554.sql h1:aB4MUS2lmqG0//4HKUWorcPSpWya0VC4QItvGyskEVI= +20251008052346.sql h1:MI3AZgU5XcwZT2OvvlWAxdRtL0eJ3jjRwt56IY1+pRU= +20251008073620.sql h1:sztWXuSNYwpEraaSapSsYwno75LO5H/N7ob7OJQ8X/A= +20251009042854.sql h1:TnPXj+dCJls3IU//cuqJZymyBzZMKs7ayazfgtAFRxM= +20251009052657.sql h1:leXbs0CP8r5dRilmYyLRk1MICqak3ea1/LWMtFrijqQ= +20251010031743.sql h1:SgHNY/lQ88G2F4nZyMfiOkDntb+gtOR+nEQLqXBTwv4= +20251010070721.sql h1:AnJnhXsMzDvK4AFgYw6B16Kpo/hljrZtcpc9m2VOSHQ= +20251010072711.sql h1:aXPTtNwLcTuw8C/yAxwxvqs0ayEjNzI1uuE0vE3ERa8= +20251013044536.sql h1:7Pq6JcvTpPBYDCW2dz3HdgUwY65HlhEVWy9TiG8iONE= +20251013051438.sql h1:X6t8bkqpUYYokBunSufMQUe5vCg0VyO6dxbm7ngosUc= +20251013081808.sql h1:495pLguXL2Ozh+ycn4UYZgZbn6WbjXNbyZUc3JU8qhI= +20251014060047.sql h1:nCgImMRGHhziiW57O1ofWaXCAPGaCOHN7PldQ3OSmM4= +20251014063537.sql h1:2cLmID79jP6cuQ1YJaWTtghFiM1GtHMC0ZQl30Hpy1M= +20251014063720.sql h1:bzLKKVAjSHgDFoiI/glj7t1ETlSAKx+AlsIAaP0ru2g= +20251015045455.sql h1:S547+UugQhlTRcn1Lm1IfqT5RNPttIWIiD+RTx69YaE= +20251016010845.sql h1:c9DUvxl17pUkf0azdYGM/YDzYxIJkLcfZOcMI4rL+R0= +20251016011023.sql h1:u3ivg83bXgYHBbojbWpemLxPE9Dmmj53B6LXo664jxw= +20251016062912.sql h1:W9n1hWchfYkqNX9LO9uxFxEXAb/iY+Pexjnhmp6PbgI= +20251017060617.sql h1:VU6yZ2+LfHpDZ3+TIH40t3F5YXPCpTppuF9+uSqa4b8= +20251017082207.sql h1:QshZslfedckz7iDpSGmPyY9sP6dy6ckHbs8L1TuXIA4= From 11a07a96f4000529e251c998798a4feab222d381 Mon Sep 17 00:00:00 2001 From: Munawwirul Jamal Date: Sun, 19 Oct 2025 16:56:50 +0700 Subject: [PATCH 25/30] added intern --- .../migrations/20251019093915.sql | 15 +++ cmd/main-migration/migrations/atlas.sum | 103 +++++++++--------- internal/domain/main-entities/intern/dto.go | 81 ++++++++++++++ .../domain/main-entities/intern/entity.go | 17 +++ internal/domain/main-entities/user/dto.go | 47 ++++---- internal/domain/main-entities/user/entity.go | 20 ++-- .../references/organization/organization.go | 41 ++++--- internal/interface/migration/main-entities.go | 2 + pkg/auth-helper/tycovar.go | 61 ++++++++--- 9 files changed, 273 insertions(+), 114 deletions(-) create mode 100644 cmd/main-migration/migrations/20251019093915.sql create mode 100644 internal/domain/main-entities/intern/dto.go create mode 100644 internal/domain/main-entities/intern/entity.go diff --git a/cmd/main-migration/migrations/20251019093915.sql b/cmd/main-migration/migrations/20251019093915.sql new file mode 100644 index 00000000..31ac3655 --- /dev/null +++ b/cmd/main-migration/migrations/20251019093915.sql @@ -0,0 +1,15 @@ +-- Rename a column from "Position_Code" to "ContractPosition_Code" +ALTER TABLE "public"."User" RENAME COLUMN "Position_Code" TO "ContractPosition_Code"; +-- Create "Intern" table +CREATE TABLE "public"."Intern" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Person_Id" bigint NULL, + "Position_Code" character varying(20) NULL, + "User_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Intern_Person" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Intern_User" FOREIGN KEY ("User_Id") REFERENCES "public"."User" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index 42636d28..582b2527 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,51 +1,52 @@ -h1:8zie3PyS55y+G80bxoc2K/aE8n0tDc8iH3Tc+FUB4o8= -20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= -20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= -20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI= -20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= -20250908073811.sql h1:gOi5cnGG1htlpfizybYmUIT0vYjZTBfXiI0nPSYK2u8= -20250908073839.sql h1:cWNDA4YikjoOteAJuNLFILjQUJPFB6o8Wxreiek4QyI= -20250910055902.sql h1:nxxOGnU0BbH/v3IPgeIOXOwH8d3tKomw7h6FTeMnnBs= -20250915123412.sql h1:mz7SiWfrdf0qE1VTSAAnA/147d6gyp6ry5vZ2bR9SH0= -20250916043819.sql h1:RHXVtmMkB6wfv06HfPyHMBmUfIpFt1xveafNz0kwKnE= -20250917040616.sql h1:MYVDht+akBlzQGKNu2hTTTLPEcH1bxT/Q8MK6WEtuhs= -20250917040751.sql h1:J79YyS2JzWgh5oKXMTgh67uo3gLxKaAsxRiZmSIfjBs= -20250917045138.sql h1:/SM1N4O8X3yxpoJgMEARmS1uOkuLKsTOy4PLsRCOKaQ= -20250917093645.sql h1:PNBTGZ7s10e5b5+Tie8YfVQBN0zKtJ5T34oK1iOUEb4= -20250918073552.sql h1:jG7+g3i8ODYaJdcdZz12v3nbsZ5mB9wG6kWnGyTQIRI= -20250918073742.sql h1:j+rgw7puxE7s+phqPVZHmPk0af3rcaA56Itp86y1suY= -20250918074745.sql h1:rPmP4DXs6OnY4Vp+xO/z9jFpJt/RrJ52SJJjIIxeDvc= -20250923025134.sql h1:2r6pcwnBSU5Y9Czk1OHBoh4yZXiMtEca9X8843fTEX0= -20250924051317.sql h1:iUAk2gsGoEGIPQ0lEEUp8maMSId8emNbP+kP712ABIA= -20250929034321.sql h1:UlpALNVmdi95zOIT0yc6ZyTj9bBjQEIpZhvgrc52M+k= -20250929034428.sql h1:feF+H4nDyHh5bdx48Oiz0A1qecZfi6v3qTTdjzJ45Dg= -20250930025550.sql h1:6XT1kXI3Z3ZIxxmvT7poufZWWCW0QiejZPaFV5wBnjI= -20250930140351.sql h1:HxnmAbh9gCy8jwl/9ycGktiByaUripsjFFvohofY2CY= -20251002085604.sql h1:SjLPi+ZN6qDccK3DaEQCgNsZpPwr5kynWXwbwEsziCI= -20251003032030.sql h1:oHfxNSuqTxU8Zaf9H+h8TuUb1Da03wcyc6hZjDrUQ2s= -20251005060450.sql h1:GIuCcrd4MwjmXpvbzDzPYL18BV3QaZZ+Y2FmEzjvi0E= -20251006041122.sql h1:uNDQbSw0M08lYoMvUNlQtS3iDzpPM1ixT13ugSAoWjE= -20251006045658.sql h1:z+t7yCK54Q4SSiF9kUyUhkYB2F+kzSW9TB7ogxd9wzw= -20251006045928.sql h1:1lATLFLp4BWwGZqAjZdP0Dc6ypNXiYcwjoNkqGa8NFE= -20251007022859.sql h1:HXXwWrkyvzJzJGAt9mGskCRBBV/c1JfPmfjDocmJhQ4= -20251008031337.sql h1:Ln5pCF3Hxa5foHZLcds+z/us2eH6VAhhEj3w0TAGlVs= -20251008031554.sql h1:aB4MUS2lmqG0//4HKUWorcPSpWya0VC4QItvGyskEVI= -20251008052346.sql h1:MI3AZgU5XcwZT2OvvlWAxdRtL0eJ3jjRwt56IY1+pRU= -20251008073620.sql h1:sztWXuSNYwpEraaSapSsYwno75LO5H/N7ob7OJQ8X/A= -20251009042854.sql h1:TnPXj+dCJls3IU//cuqJZymyBzZMKs7ayazfgtAFRxM= -20251009052657.sql h1:leXbs0CP8r5dRilmYyLRk1MICqak3ea1/LWMtFrijqQ= -20251010031743.sql h1:SgHNY/lQ88G2F4nZyMfiOkDntb+gtOR+nEQLqXBTwv4= -20251010070721.sql h1:AnJnhXsMzDvK4AFgYw6B16Kpo/hljrZtcpc9m2VOSHQ= -20251010072711.sql h1:aXPTtNwLcTuw8C/yAxwxvqs0ayEjNzI1uuE0vE3ERa8= -20251013044536.sql h1:7Pq6JcvTpPBYDCW2dz3HdgUwY65HlhEVWy9TiG8iONE= -20251013051438.sql h1:X6t8bkqpUYYokBunSufMQUe5vCg0VyO6dxbm7ngosUc= -20251013081808.sql h1:495pLguXL2Ozh+ycn4UYZgZbn6WbjXNbyZUc3JU8qhI= -20251014060047.sql h1:nCgImMRGHhziiW57O1ofWaXCAPGaCOHN7PldQ3OSmM4= -20251014063537.sql h1:2cLmID79jP6cuQ1YJaWTtghFiM1GtHMC0ZQl30Hpy1M= -20251014063720.sql h1:bzLKKVAjSHgDFoiI/glj7t1ETlSAKx+AlsIAaP0ru2g= -20251015045455.sql h1:S547+UugQhlTRcn1Lm1IfqT5RNPttIWIiD+RTx69YaE= -20251016010845.sql h1:c9DUvxl17pUkf0azdYGM/YDzYxIJkLcfZOcMI4rL+R0= -20251016011023.sql h1:u3ivg83bXgYHBbojbWpemLxPE9Dmmj53B6LXo664jxw= -20251016062912.sql h1:W9n1hWchfYkqNX9LO9uxFxEXAb/iY+Pexjnhmp6PbgI= -20251017060617.sql h1:VU6yZ2+LfHpDZ3+TIH40t3F5YXPCpTppuF9+uSqa4b8= -20251017082207.sql h1:QshZslfedckz7iDpSGmPyY9sP6dy6ckHbs8L1TuXIA4= +h1:eCBVp2yPQk7VrLdSk2mDps+FXavKA5OcJ1/QRBh+ovI= +20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= +20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= +20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= +20250908062323.sql h1:oXl6Z143tOpIl4EfP4B8JNU8LrMvVmHEtCgAfiB4gs8= +20250908073811.sql h1:m2aNXfnGxnLq1+rVWrh4f60q7fhyhV3gEwNu/OIqQlE= +20250908073839.sql h1:cPk54xjLdMs26uY8ZHjNWLuyfAMzV7Zb0/9oJQrsw04= +20250910055902.sql h1:5xwjAV6QbtZT9empTJKfhyAjdknbHzb15B0Ku5dzqtQ= +20250915123412.sql h1:D83xaU2YlDEd21HLup/YQpQ2easMToYCyy/oK6AFgQs= +20250916043819.sql h1:ekoTJsBqQZ8G8n0qJ03d13+eoNoc7sAUEQGA5D/CCxk= +20250917040616.sql h1:zoCnmcXuM7AVv85SmN7RmFglCgJnoDmpRWExH0LAc9Q= +20250917040751.sql h1:J1xyRrh32y1+lezwAyNwPcUQ6ABBSgbvzNLva4SVdQU= +20250917045138.sql h1:jKe1Z0uOLG4SGBYM+S/3P+/zMPztmgoderD5swnMuCg= +20250917093645.sql h1:cNI3Pbz1R3LxvIXLuexafJFCXUXrmuFCgXXJ2sG+FW0= +20250918073552.sql h1:RJ1SvMzP6aeWnoPVD3eVAmIQOkcp6Php8z3QRri6v4g= +20250918073742.sql h1:+cEsnJTJFybe2fR69ZoOiX2R6c6iITl4m6WTZ1hjyzY= +20250918074745.sql h1:2hNVQCXF/dVYXAh+T/7oBFgERGWxzVb2FXJjwkFWGCI= +20250923025134.sql h1:Ykz/qpHiGDXPsCsWTjydQFVSibZP2D+h2fIeb2h2JGA= +20250924051317.sql h1:yQuW6SwJxIOM5fcxeAaie5lSm1oLysU/C2hH2xNCVoQ= +20250929034321.sql h1:101FJ8VH12mrZWlt/X1gvKUGOhoiF8tFbjiapAjnHzg= +20250929034428.sql h1:i+pROD9p+g5dOmmZma6WF/0Hw5g3Ha28NN85iTo1K34= +20250930025550.sql h1:+F+CsCUXD/ql0tHGEow70GhPBX1ZybVn+bh/T4YMh7Y= +20250930140351.sql h1:9AAEG1AnOAH+o0+oHL5G7I8vqlWOhwRlCGyyCpT/y1Q= +20251002085604.sql h1:3xZ68eYp4urXRnvotNH1XvG2mYOSDV/j3zHEZ/txg5E= +20251003032030.sql h1:HB+mQ2lXMNomHDpaRhB/9IwYI9/YiDO5eOJ+nAQH/jw= +20251005060450.sql h1:LbtCE2b+8osM3CvnmQJH1uCPtn+d7WchsslBOz8bL3Q= +20251006041122.sql h1:MlS7f21z06sutnf9dIekt5fuHJr4lgcQ4uCuCXAGsfc= +20251006045658.sql h1:3FmGCPCzjgMPdWDRodZTsx3KVaodd9zB9ilib69aewk= +20251006045928.sql h1:Z5g31PmnzNwk/OKdODcxZGm8fjJQdMFK32Xfnt3bRHg= +20251007022859.sql h1:FO03zEfaNEk/aXwY81d5Lp3MoBB9kPQuXlXJ4BPiSR8= +20251008031337.sql h1:l+sxUAGvcTfj3I6kAFHo+T6AYodC9k9GkR+jaKO2xXc= +20251008031554.sql h1:AqrVfIhSzY3PCy8ZlP5W91wn2iznfIuj5qQfubp6/94= +20251008052346.sql h1:nxnXmooIJ6r1mmzwnw+6efxLfc/k9h2aE6RMptPRons= +20251008073620.sql h1:6YsJp1W4SmQJ1lxpqF27BBlDC1zqhw7Yhc7pLzQTY6M= +20251009042854.sql h1:nkBV+R6j0fg7/JY6wH3eb5Vv0asJLnXmb6lINfT/GLQ= +20251009052657.sql h1:EPvdsib5rzCGPryd10HShGKvFPwM/R5S2lIVwtYxpms= +20251010031743.sql h1:T8IZmx8/btRFKLzTe78MzcBsPJNodnLvB0tby9QkirQ= +20251010070721.sql h1:5NQUk/yOV6sABLCB7swx++YIOyJe6MnU+yt1nRzde5w= +20251010072711.sql h1:ZJNqR2piyu8xJhBvVABSlnGEoKSKae3wuEs+wshPe4k= +20251013044536.sql h1:0Xjw8fNILiT8nnfrJDZgQnPf3dntmIoilbapnih8AE4= +20251013051438.sql h1:lfSuw5mgJnePBJamvhZ81osFIouXeiIEiSZ/evdwo48= +20251013081808.sql h1:ijgjNX08G6GBjA/ks8EKtb7P7Y7Cg7zbhqEOruGnv6M= +20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= +20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= +20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= +20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= +20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= +20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= +20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= +20251017060617.sql h1:4T3t9ifWrEQTPMSM0XJ98pF7Qdt+UfgtMui17bhrnWI= +20251017082207.sql h1:8vLG1l/saRRMHXkyA4nelJyjaSddhZd6r7R+Uo4JS/c= +20251019093915.sql h1:wsJMh1r45ONaY7zIq2c3rTcuGXN4mI0irZK7a96HZW8= diff --git a/internal/domain/main-entities/intern/dto.go b/internal/domain/main-entities/intern/dto.go new file mode 100644 index 00000000..b8c60aee --- /dev/null +++ b/internal/domain/main-entities/intern/dto.go @@ -0,0 +1,81 @@ +package intern + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ep "simrs-vx/internal/domain/main-entities/person" + es "simrs-vx/internal/domain/main-entities/specialist" + ess "simrs-vx/internal/domain/main-entities/subspecialist" + eu "simrs-vx/internal/domain/main-entities/user" +) + +type CreateDto struct { + Person_Id *uint `json:"person_id"` + Specialist_Id *uint16 `json:"specialist_id"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + User_Id *uint `json:"user_id"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Person_Id *uint `json:"person_id"` + Specialist_Id *uint16 `json:"specialist_id"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + User_Id *uint `json:"user_id"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + User_Id *uint `json:"user_id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Person_Id *uint `json:"person_id"` + Person *ep.Person `json:"person,omitempty"` + Specialist_Id *uint16 `json:"specialist_id"` + Specialist *es.Specialist `json:"specialist,omitempty"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` + User_Id *uint `json:"user_id"` + User *eu.User `json:"user,omitempty"` +} + +func (d Intern) ToResponse() ResponseDto { + resp := ResponseDto{ + Person_Id: d.Person_Id, + Person: d.Person, + User_Id: d.User_Id, + User: d.User, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Intern) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/intern/entity.go b/internal/domain/main-entities/intern/entity.go new file mode 100644 index 00000000..5ac2df49 --- /dev/null +++ b/internal/domain/main-entities/intern/entity.go @@ -0,0 +1,17 @@ +package intern + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ep "simrs-vx/internal/domain/main-entities/person" + eu "simrs-vx/internal/domain/main-entities/user" + erg "simrs-vx/internal/domain/references/organization" +) + +type Intern struct { + ecore.Main // adjust this according to the needs + Person_Id *uint `json:"person_id"` + Person *ep.Person `json:"person,omitempty" gorm:"foreignKey:Person_Id"` + Position_Code *erg.InternPosisitionCode `json:"position_code" gorm:"size:20"` + User_Id *uint `json:"user_id"` + User *eu.User `json:"user,omitempty" gorm:"foreignKey:User_Id"` +} diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index 9f948fe7..55a53686 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -1,33 +1,33 @@ package user import ( + ecore "simrs-vx/internal/domain/base-entities/core" "time" - ecore "simrs-vx/internal/domain/base-entities/core" ep "simrs-vx/internal/domain/main-entities/person" epa "simrs-vx/internal/domain/main-entities/person-address" epc "simrs-vx/internal/domain/main-entities/person-contact" erc "simrs-vx/internal/domain/references/common" - ero "simrs-vx/internal/domain/references/organization" + erg "simrs-vx/internal/domain/references/organization" ) type CreateDto struct { - Name string `json:"name" validate:"maxLength=25"` - Password string `json:"password" validate:"maxLength=255"` - Status_Code erc.UserStatusCode `json:"status_code" validate:"maxLength=10"` - Position_Code ero.UserPosisitionCode `json:"position_code" validate:"maxLength=20"` - Person_Id *uint `json:"-"` - Person *ep.UpdateDto `json:"person"` - PersonAddresses []epa.UpdateDto `json:"personAddresses"` - PersonContacts []epc.UpdateDto `json:"personContacts"` - Employee *EmployeUpdateDto `json:"employee"` - IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` - SIP_Number *string `json:"sip_number" validate:"maxLength=20"` - Unit_Id *uint16 `json:"unit_id"` - Infra_Id *uint16 `json:"infra_id"` - Specialist_Id *uint16 `json:"specialist_id"` - Subspecialist_Id *uint16 `json:"subspecialist_id"` + Name string `json:"name" validate:"maxLength=25"` + Password string `json:"password" validate:"maxLength=255"` + Status_Code erc.UserStatusCode `json:"status_code" validate:"maxLength=10"` + Person_Id *uint `json:"-"` + Person *ep.UpdateDto `json:"person"` + PersonAddresses []epa.UpdateDto `json:"personAddresses"` + PersonContacts []epc.UpdateDto `json:"personContacts"` + Employee *EmployeUpdateDto `json:"employee"` + IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` + SIP_Number *string `json:"sip_number" validate:"maxLength=20"` + Unit_Id *uint16 `json:"unit_id"` + Infra_Id *uint16 `json:"infra_id"` + Specialist_Id *uint16 `json:"specialist_id"` + Subspecialist_Id *uint16 `json:"subspecialist_id"` + ContractPosition_Code erg.ContractPositionCode `json:"contractPosition_code" gorm:"not null;size:20"` } type ReadListDto struct { @@ -84,12 +84,13 @@ func (d *User) ToResponse() ResponseDto { } type EmployeUpdateDto struct { - Id uint `json:"id"` - User_Id *uint `json:"-"` - Person_Id *uint `json:"-"` - Division_Code *string `json:"division_code"` - Number *string `json:"number" validate:"maxLength=20"` - Status_Code erc.ActiveStatusCode `json:"status_code" validate:"maxLength=10"` + Id uint `json:"id"` + User_Id *uint `json:"-"` + Person_Id *uint `json:"-"` + Division_Code *string `json:"division_code"` + Number *string `json:"number" validate:"maxLength=20"` + Position_Code erg.EmployeePosisitionCode `json:"status_code" validate:"maxLength=10"` + Status_Code erc.ActiveStatusCode `json:"status_code" validate:"maxLength=10"` } func ToResponseList(data []User) []ResponseDto { diff --git a/internal/domain/main-entities/user/entity.go b/internal/domain/main-entities/user/entity.go index 4f7d8792..f51dbf14 100644 --- a/internal/domain/main-entities/user/entity.go +++ b/internal/domain/main-entities/user/entity.go @@ -5,17 +5,17 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" erc "simrs-vx/internal/domain/references/common" - ero "simrs-vx/internal/domain/references/organization" + erg "simrs-vx/internal/domain/references/organization" ) type User struct { - ecore.Main // adjust this according to the needs - Name string `json:"name" gorm:"unique;not null;size:25"` - Password string `json:"password" gorm:"not null;size:255"` - Status_Code erc.UserStatusCode `json:"status_code" gorm:"not null;size:10"` - FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` - Position_Code ero.UserPosisitionCode `json:"position_code" gorm:"not null;size:20"` - LoginAttemptCount int `json:"-"` - LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"` - LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` + ecore.Main // adjust this according to the needs + Name string `json:"name" gorm:"unique;not null;size:25"` + Password string `json:"password" gorm:"not null;size:255"` + Status_Code erc.UserStatusCode `json:"status_code" gorm:"not null;size:10"` + ContractPosition_Code erg.ContractPositionCode `json:"contractPosition_code" gorm:"not null;size:20"` + FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` + LoginAttemptCount int `json:"-"` + LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"` + LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` } diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index 04c4fa2a..60270a93 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -1,26 +1,33 @@ package organization type ( - UserPosisitionCode string - ItemGroupCode string - InfraGroupCode string - UnitTypeCode string - DoctorFeeTypeCode string + ContractPositionCode string + EmployeePosisitionCode string + InternPosisitionCode string + ItemGroupCode string + InfraGroupCode string + UnitTypeCode string + DoctorFeeTypeCode string ) const ( - UPCReg UserPosisitionCode = "registration" // Admisi/Pendaftaran - UPCNur UserPosisitionCode = "nurse" // Perawat - UPCDoc UserPosisitionCode = "doctor" // Dokter - UPCNut UserPosisitionCode = "nutritionist" // Ahli gizi - UPCMwi UserPosisitionCode = "mid-wife" // Bidan - UPCLab UserPosisitionCode = "laborant" // Laboran - UPCPha UserPosisitionCode = "pharmacy" // Farmasi - UPCPay UserPosisitionCode = "payment" // Pembayaran - UPCHur UserPosisitionCode = "human-resource" // Sumber Daya Manusia - UPCGea UserPosisitionCode = "general-affair" // Bagian Umum - UPCInt UserPosisitionCode = "specialist-intern" // PPDS - UPCMan UserPosisitionCode = "management" // Manajemen + CSCEmp ContractPositionCode = "employee" // Pegawai + CSCSpi ContractPositionCode = "intern" // PPDS + + EPCReg EmployeePosisitionCode = "registration" // Admisi/Pendaftaran + EPCNur EmployeePosisitionCode = "nurse" // Perawat + EPCDoc EmployeePosisitionCode = "doctor" // Dokter + EPCNut EmployeePosisitionCode = "nutritionist" // Ahli gizi + EPCMwi EmployeePosisitionCode = "mid-wife" // Bidan + EPCLab EmployeePosisitionCode = "laborant" // Laboran + EPCPha EmployeePosisitionCode = "pharmacy" // Farmasi + EPCPay EmployeePosisitionCode = "payment" // Pembayaran + EPCHur EmployeePosisitionCode = "human-resource" // Sumber Daya Manusia + EPCGea EmployeePosisitionCode = "general-affair" // Bagian Umum + EPCMan EmployeePosisitionCode = "management" // Manajemen + + IPCSpecialist = "specialist-intern" + IPCNurse = "nurse-intern" ITGCInfra ItemGroupCode = "infra" ITGCMedicine ItemGroupCode = "medicine" diff --git a/internal/interface/migration/main-entities.go b/internal/interface/migration/main-entities.go index ae155e9c..131b2972 100644 --- a/internal/interface/migration/main-entities.go +++ b/internal/interface/migration/main-entities.go @@ -25,6 +25,7 @@ import ( inpatient "simrs-vx/internal/domain/main-entities/inpatient" installation "simrs-vx/internal/domain/main-entities/installation" insurancecompany "simrs-vx/internal/domain/main-entities/insurance-company" + intern "simrs-vx/internal/domain/main-entities/intern" internalreference "simrs-vx/internal/domain/main-entities/internal-reference" item "simrs-vx/internal/domain/main-entities/item" itemprice "simrs-vx/internal/domain/main-entities/item-price" @@ -105,6 +106,7 @@ func getMainEntities() []any { &diagnosesrc.DiagnoseSrc{}, &proceduresrc.ProcedureSrc{}, &employee.Employee{}, + &intern.Intern{}, &doctor.Doctor{}, &nurse.Nurse{}, &nutritionist.Nutritionist{}, diff --git a/pkg/auth-helper/tycovar.go b/pkg/auth-helper/tycovar.go index 288c9d21..06618350 100644 --- a/pkg/auth-helper/tycovar.go +++ b/pkg/auth-helper/tycovar.go @@ -7,11 +7,15 @@ import ( type AuthKey struct{} type AuthInfo struct { - Uuid string - User_Id uint - User_Name string - User_DivisionPositions []DivisionPosition - User_Position_Code string + Uuid string + User_Id uint + User_Name string + User_ContractPosition_code string + Employee_Position_Code *string + Intern_Position_Code *string + User_DivisionPositions []DivisionPosition + // User_DivisionPositions []DivisionPosition + // User_Position_Code string } type DivisionPosition struct { @@ -20,33 +24,64 @@ type DivisionPosition struct { } func (a AuthInfo) IsDoctor() bool { - return a.User_Position_Code == string(ero.UPCDoc) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCDoc) } func (a AuthInfo) IsNurse() bool { - return a.User_Position_Code == string(ero.UPCNur) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCNur) } func (a AuthInfo) IsNutritionist() bool { - return a.User_Position_Code == string(ero.UPCNut) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCNut) } func (a AuthInfo) IsLaborant() bool { - return a.User_Position_Code == string(ero.UPCLab) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCLab) } func (a AuthInfo) IsPharmacist() bool { - return a.User_Position_Code == string(ero.UPCPha) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCPha) } func (a AuthInfo) IsPayment() bool { - return a.User_Position_Code == string(ero.UPCPay) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCPay) } func (a AuthInfo) IsManagement() bool { - return a.User_Position_Code == string(ero.UPCMan) + if a.Employee_Position_Code == nil { + return false + } + return *a.Employee_Position_Code == string(ero.EPCMan) } func (a AuthInfo) IsSpecialistIntern() bool { - return a.User_Position_Code == string(ero.UPCInt) + if a.Intern_Position_Code == nil { + return false + } + return *a.Intern_Position_Code == string(ero.IPCSpecialist) +} + +func (a AuthInfo) IsNurseIntern() bool { + if a.Intern_Position_Code == nil { + return false + } + return *a.Intern_Position_Code == string(ero.IPCNurse) } From aeaa9b4f58e289b9a9414a008c4fcc32b328f46e Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sun, 19 Oct 2025 17:04:31 +0700 Subject: [PATCH 26/30] updated hash --- cmd/main-migration/migrations/atlas.sum | 104 ++++++++++++------------ 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index 582b2527..ff07efec 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,52 +1,52 @@ -h1:eCBVp2yPQk7VrLdSk2mDps+FXavKA5OcJ1/QRBh+ovI= -20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= -20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= -20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= -20250908062323.sql h1:oXl6Z143tOpIl4EfP4B8JNU8LrMvVmHEtCgAfiB4gs8= -20250908073811.sql h1:m2aNXfnGxnLq1+rVWrh4f60q7fhyhV3gEwNu/OIqQlE= -20250908073839.sql h1:cPk54xjLdMs26uY8ZHjNWLuyfAMzV7Zb0/9oJQrsw04= -20250910055902.sql h1:5xwjAV6QbtZT9empTJKfhyAjdknbHzb15B0Ku5dzqtQ= -20250915123412.sql h1:D83xaU2YlDEd21HLup/YQpQ2easMToYCyy/oK6AFgQs= -20250916043819.sql h1:ekoTJsBqQZ8G8n0qJ03d13+eoNoc7sAUEQGA5D/CCxk= -20250917040616.sql h1:zoCnmcXuM7AVv85SmN7RmFglCgJnoDmpRWExH0LAc9Q= -20250917040751.sql h1:J1xyRrh32y1+lezwAyNwPcUQ6ABBSgbvzNLva4SVdQU= -20250917045138.sql h1:jKe1Z0uOLG4SGBYM+S/3P+/zMPztmgoderD5swnMuCg= -20250917093645.sql h1:cNI3Pbz1R3LxvIXLuexafJFCXUXrmuFCgXXJ2sG+FW0= -20250918073552.sql h1:RJ1SvMzP6aeWnoPVD3eVAmIQOkcp6Php8z3QRri6v4g= -20250918073742.sql h1:+cEsnJTJFybe2fR69ZoOiX2R6c6iITl4m6WTZ1hjyzY= -20250918074745.sql h1:2hNVQCXF/dVYXAh+T/7oBFgERGWxzVb2FXJjwkFWGCI= -20250923025134.sql h1:Ykz/qpHiGDXPsCsWTjydQFVSibZP2D+h2fIeb2h2JGA= -20250924051317.sql h1:yQuW6SwJxIOM5fcxeAaie5lSm1oLysU/C2hH2xNCVoQ= -20250929034321.sql h1:101FJ8VH12mrZWlt/X1gvKUGOhoiF8tFbjiapAjnHzg= -20250929034428.sql h1:i+pROD9p+g5dOmmZma6WF/0Hw5g3Ha28NN85iTo1K34= -20250930025550.sql h1:+F+CsCUXD/ql0tHGEow70GhPBX1ZybVn+bh/T4YMh7Y= -20250930140351.sql h1:9AAEG1AnOAH+o0+oHL5G7I8vqlWOhwRlCGyyCpT/y1Q= -20251002085604.sql h1:3xZ68eYp4urXRnvotNH1XvG2mYOSDV/j3zHEZ/txg5E= -20251003032030.sql h1:HB+mQ2lXMNomHDpaRhB/9IwYI9/YiDO5eOJ+nAQH/jw= -20251005060450.sql h1:LbtCE2b+8osM3CvnmQJH1uCPtn+d7WchsslBOz8bL3Q= -20251006041122.sql h1:MlS7f21z06sutnf9dIekt5fuHJr4lgcQ4uCuCXAGsfc= -20251006045658.sql h1:3FmGCPCzjgMPdWDRodZTsx3KVaodd9zB9ilib69aewk= -20251006045928.sql h1:Z5g31PmnzNwk/OKdODcxZGm8fjJQdMFK32Xfnt3bRHg= -20251007022859.sql h1:FO03zEfaNEk/aXwY81d5Lp3MoBB9kPQuXlXJ4BPiSR8= -20251008031337.sql h1:l+sxUAGvcTfj3I6kAFHo+T6AYodC9k9GkR+jaKO2xXc= -20251008031554.sql h1:AqrVfIhSzY3PCy8ZlP5W91wn2iznfIuj5qQfubp6/94= -20251008052346.sql h1:nxnXmooIJ6r1mmzwnw+6efxLfc/k9h2aE6RMptPRons= -20251008073620.sql h1:6YsJp1W4SmQJ1lxpqF27BBlDC1zqhw7Yhc7pLzQTY6M= -20251009042854.sql h1:nkBV+R6j0fg7/JY6wH3eb5Vv0asJLnXmb6lINfT/GLQ= -20251009052657.sql h1:EPvdsib5rzCGPryd10HShGKvFPwM/R5S2lIVwtYxpms= -20251010031743.sql h1:T8IZmx8/btRFKLzTe78MzcBsPJNodnLvB0tby9QkirQ= -20251010070721.sql h1:5NQUk/yOV6sABLCB7swx++YIOyJe6MnU+yt1nRzde5w= -20251010072711.sql h1:ZJNqR2piyu8xJhBvVABSlnGEoKSKae3wuEs+wshPe4k= -20251013044536.sql h1:0Xjw8fNILiT8nnfrJDZgQnPf3dntmIoilbapnih8AE4= -20251013051438.sql h1:lfSuw5mgJnePBJamvhZ81osFIouXeiIEiSZ/evdwo48= -20251013081808.sql h1:ijgjNX08G6GBjA/ks8EKtb7P7Y7Cg7zbhqEOruGnv6M= -20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= -20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= -20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= -20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= -20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= -20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= -20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= -20251017060617.sql h1:4T3t9ifWrEQTPMSM0XJ98pF7Qdt+UfgtMui17bhrnWI= -20251017082207.sql h1:8vLG1l/saRRMHXkyA4nelJyjaSddhZd6r7R+Uo4JS/c= -20251019093915.sql h1:wsJMh1r45ONaY7zIq2c3rTcuGXN4mI0irZK7a96HZW8= +h1:uePVRnTbNXAgIcfonTLFDMb/Dor10LHhqO2JMvcG9oM= +20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= +20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= +20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI= +20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= +20250908073811.sql h1:gOi5cnGG1htlpfizybYmUIT0vYjZTBfXiI0nPSYK2u8= +20250908073839.sql h1:cWNDA4YikjoOteAJuNLFILjQUJPFB6o8Wxreiek4QyI= +20250910055902.sql h1:nxxOGnU0BbH/v3IPgeIOXOwH8d3tKomw7h6FTeMnnBs= +20250915123412.sql h1:mz7SiWfrdf0qE1VTSAAnA/147d6gyp6ry5vZ2bR9SH0= +20250916043819.sql h1:RHXVtmMkB6wfv06HfPyHMBmUfIpFt1xveafNz0kwKnE= +20250917040616.sql h1:MYVDht+akBlzQGKNu2hTTTLPEcH1bxT/Q8MK6WEtuhs= +20250917040751.sql h1:J79YyS2JzWgh5oKXMTgh67uo3gLxKaAsxRiZmSIfjBs= +20250917045138.sql h1:/SM1N4O8X3yxpoJgMEARmS1uOkuLKsTOy4PLsRCOKaQ= +20250917093645.sql h1:PNBTGZ7s10e5b5+Tie8YfVQBN0zKtJ5T34oK1iOUEb4= +20250918073552.sql h1:jG7+g3i8ODYaJdcdZz12v3nbsZ5mB9wG6kWnGyTQIRI= +20250918073742.sql h1:j+rgw7puxE7s+phqPVZHmPk0af3rcaA56Itp86y1suY= +20250918074745.sql h1:rPmP4DXs6OnY4Vp+xO/z9jFpJt/RrJ52SJJjIIxeDvc= +20250923025134.sql h1:2r6pcwnBSU5Y9Czk1OHBoh4yZXiMtEca9X8843fTEX0= +20250924051317.sql h1:iUAk2gsGoEGIPQ0lEEUp8maMSId8emNbP+kP712ABIA= +20250929034321.sql h1:UlpALNVmdi95zOIT0yc6ZyTj9bBjQEIpZhvgrc52M+k= +20250929034428.sql h1:feF+H4nDyHh5bdx48Oiz0A1qecZfi6v3qTTdjzJ45Dg= +20250930025550.sql h1:6XT1kXI3Z3ZIxxmvT7poufZWWCW0QiejZPaFV5wBnjI= +20250930140351.sql h1:HxnmAbh9gCy8jwl/9ycGktiByaUripsjFFvohofY2CY= +20251002085604.sql h1:SjLPi+ZN6qDccK3DaEQCgNsZpPwr5kynWXwbwEsziCI= +20251003032030.sql h1:oHfxNSuqTxU8Zaf9H+h8TuUb1Da03wcyc6hZjDrUQ2s= +20251005060450.sql h1:GIuCcrd4MwjmXpvbzDzPYL18BV3QaZZ+Y2FmEzjvi0E= +20251006041122.sql h1:uNDQbSw0M08lYoMvUNlQtS3iDzpPM1ixT13ugSAoWjE= +20251006045658.sql h1:z+t7yCK54Q4SSiF9kUyUhkYB2F+kzSW9TB7ogxd9wzw= +20251006045928.sql h1:1lATLFLp4BWwGZqAjZdP0Dc6ypNXiYcwjoNkqGa8NFE= +20251007022859.sql h1:HXXwWrkyvzJzJGAt9mGskCRBBV/c1JfPmfjDocmJhQ4= +20251008031337.sql h1:Ln5pCF3Hxa5foHZLcds+z/us2eH6VAhhEj3w0TAGlVs= +20251008031554.sql h1:aB4MUS2lmqG0//4HKUWorcPSpWya0VC4QItvGyskEVI= +20251008052346.sql h1:MI3AZgU5XcwZT2OvvlWAxdRtL0eJ3jjRwt56IY1+pRU= +20251008073620.sql h1:sztWXuSNYwpEraaSapSsYwno75LO5H/N7ob7OJQ8X/A= +20251009042854.sql h1:TnPXj+dCJls3IU//cuqJZymyBzZMKs7ayazfgtAFRxM= +20251009052657.sql h1:leXbs0CP8r5dRilmYyLRk1MICqak3ea1/LWMtFrijqQ= +20251010031743.sql h1:SgHNY/lQ88G2F4nZyMfiOkDntb+gtOR+nEQLqXBTwv4= +20251010070721.sql h1:AnJnhXsMzDvK4AFgYw6B16Kpo/hljrZtcpc9m2VOSHQ= +20251010072711.sql h1:aXPTtNwLcTuw8C/yAxwxvqs0ayEjNzI1uuE0vE3ERa8= +20251013044536.sql h1:7Pq6JcvTpPBYDCW2dz3HdgUwY65HlhEVWy9TiG8iONE= +20251013051438.sql h1:X6t8bkqpUYYokBunSufMQUe5vCg0VyO6dxbm7ngosUc= +20251013081808.sql h1:495pLguXL2Ozh+ycn4UYZgZbn6WbjXNbyZUc3JU8qhI= +20251014060047.sql h1:nCgImMRGHhziiW57O1ofWaXCAPGaCOHN7PldQ3OSmM4= +20251014063537.sql h1:2cLmID79jP6cuQ1YJaWTtghFiM1GtHMC0ZQl30Hpy1M= +20251014063720.sql h1:bzLKKVAjSHgDFoiI/glj7t1ETlSAKx+AlsIAaP0ru2g= +20251015045455.sql h1:S547+UugQhlTRcn1Lm1IfqT5RNPttIWIiD+RTx69YaE= +20251016010845.sql h1:c9DUvxl17pUkf0azdYGM/YDzYxIJkLcfZOcMI4rL+R0= +20251016011023.sql h1:u3ivg83bXgYHBbojbWpemLxPE9Dmmj53B6LXo664jxw= +20251016062912.sql h1:W9n1hWchfYkqNX9LO9uxFxEXAb/iY+Pexjnhmp6PbgI= +20251017060617.sql h1:VU6yZ2+LfHpDZ3+TIH40t3F5YXPCpTppuF9+uSqa4b8= +20251017082207.sql h1:QshZslfedckz7iDpSGmPyY9sP6dy6ckHbs8L1TuXIA4= +20251019093915.sql h1:XNEhxA1k6i+AnNjZr2jRVQrr6Q987UP+IdbwdWqHIEE= From b133aa311675d086f342165e5a48a09e856d8ce1 Mon Sep 17 00:00:00 2001 From: Munawwirul Jamal Date: Sun, 19 Oct 2025 17:16:15 +0700 Subject: [PATCH 27/30] updated sum --- cmd/main-migration/migrations/atlas.sum | 104 ++++++++++++------------ 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index ff07efec..582b2527 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,52 +1,52 @@ -h1:uePVRnTbNXAgIcfonTLFDMb/Dor10LHhqO2JMvcG9oM= -20250904105930.sql h1:Vv4vCurl7m7/ZB6TjRpkubHpQ4RYwSUn0QHdzfoGpzY= -20250904141448.sql h1:FYCHH9Os4KkrZMDu/jR8FMP+wLMRW+Mb0PkLU/9BRDg= -20250908062237.sql h1:oanBpKZd+akPu2I/xYhUSbd0G5tAFbXzKLER/Zs8ENI= -20250908062323.sql h1:miNG9COddXkD1jGTgaROMAZ618eT6oiLGiJhXWnQwhE= -20250908073811.sql h1:gOi5cnGG1htlpfizybYmUIT0vYjZTBfXiI0nPSYK2u8= -20250908073839.sql h1:cWNDA4YikjoOteAJuNLFILjQUJPFB6o8Wxreiek4QyI= -20250910055902.sql h1:nxxOGnU0BbH/v3IPgeIOXOwH8d3tKomw7h6FTeMnnBs= -20250915123412.sql h1:mz7SiWfrdf0qE1VTSAAnA/147d6gyp6ry5vZ2bR9SH0= -20250916043819.sql h1:RHXVtmMkB6wfv06HfPyHMBmUfIpFt1xveafNz0kwKnE= -20250917040616.sql h1:MYVDht+akBlzQGKNu2hTTTLPEcH1bxT/Q8MK6WEtuhs= -20250917040751.sql h1:J79YyS2JzWgh5oKXMTgh67uo3gLxKaAsxRiZmSIfjBs= -20250917045138.sql h1:/SM1N4O8X3yxpoJgMEARmS1uOkuLKsTOy4PLsRCOKaQ= -20250917093645.sql h1:PNBTGZ7s10e5b5+Tie8YfVQBN0zKtJ5T34oK1iOUEb4= -20250918073552.sql h1:jG7+g3i8ODYaJdcdZz12v3nbsZ5mB9wG6kWnGyTQIRI= -20250918073742.sql h1:j+rgw7puxE7s+phqPVZHmPk0af3rcaA56Itp86y1suY= -20250918074745.sql h1:rPmP4DXs6OnY4Vp+xO/z9jFpJt/RrJ52SJJjIIxeDvc= -20250923025134.sql h1:2r6pcwnBSU5Y9Czk1OHBoh4yZXiMtEca9X8843fTEX0= -20250924051317.sql h1:iUAk2gsGoEGIPQ0lEEUp8maMSId8emNbP+kP712ABIA= -20250929034321.sql h1:UlpALNVmdi95zOIT0yc6ZyTj9bBjQEIpZhvgrc52M+k= -20250929034428.sql h1:feF+H4nDyHh5bdx48Oiz0A1qecZfi6v3qTTdjzJ45Dg= -20250930025550.sql h1:6XT1kXI3Z3ZIxxmvT7poufZWWCW0QiejZPaFV5wBnjI= -20250930140351.sql h1:HxnmAbh9gCy8jwl/9ycGktiByaUripsjFFvohofY2CY= -20251002085604.sql h1:SjLPi+ZN6qDccK3DaEQCgNsZpPwr5kynWXwbwEsziCI= -20251003032030.sql h1:oHfxNSuqTxU8Zaf9H+h8TuUb1Da03wcyc6hZjDrUQ2s= -20251005060450.sql h1:GIuCcrd4MwjmXpvbzDzPYL18BV3QaZZ+Y2FmEzjvi0E= -20251006041122.sql h1:uNDQbSw0M08lYoMvUNlQtS3iDzpPM1ixT13ugSAoWjE= -20251006045658.sql h1:z+t7yCK54Q4SSiF9kUyUhkYB2F+kzSW9TB7ogxd9wzw= -20251006045928.sql h1:1lATLFLp4BWwGZqAjZdP0Dc6ypNXiYcwjoNkqGa8NFE= -20251007022859.sql h1:HXXwWrkyvzJzJGAt9mGskCRBBV/c1JfPmfjDocmJhQ4= -20251008031337.sql h1:Ln5pCF3Hxa5foHZLcds+z/us2eH6VAhhEj3w0TAGlVs= -20251008031554.sql h1:aB4MUS2lmqG0//4HKUWorcPSpWya0VC4QItvGyskEVI= -20251008052346.sql h1:MI3AZgU5XcwZT2OvvlWAxdRtL0eJ3jjRwt56IY1+pRU= -20251008073620.sql h1:sztWXuSNYwpEraaSapSsYwno75LO5H/N7ob7OJQ8X/A= -20251009042854.sql h1:TnPXj+dCJls3IU//cuqJZymyBzZMKs7ayazfgtAFRxM= -20251009052657.sql h1:leXbs0CP8r5dRilmYyLRk1MICqak3ea1/LWMtFrijqQ= -20251010031743.sql h1:SgHNY/lQ88G2F4nZyMfiOkDntb+gtOR+nEQLqXBTwv4= -20251010070721.sql h1:AnJnhXsMzDvK4AFgYw6B16Kpo/hljrZtcpc9m2VOSHQ= -20251010072711.sql h1:aXPTtNwLcTuw8C/yAxwxvqs0ayEjNzI1uuE0vE3ERa8= -20251013044536.sql h1:7Pq6JcvTpPBYDCW2dz3HdgUwY65HlhEVWy9TiG8iONE= -20251013051438.sql h1:X6t8bkqpUYYokBunSufMQUe5vCg0VyO6dxbm7ngosUc= -20251013081808.sql h1:495pLguXL2Ozh+ycn4UYZgZbn6WbjXNbyZUc3JU8qhI= -20251014060047.sql h1:nCgImMRGHhziiW57O1ofWaXCAPGaCOHN7PldQ3OSmM4= -20251014063537.sql h1:2cLmID79jP6cuQ1YJaWTtghFiM1GtHMC0ZQl30Hpy1M= -20251014063720.sql h1:bzLKKVAjSHgDFoiI/glj7t1ETlSAKx+AlsIAaP0ru2g= -20251015045455.sql h1:S547+UugQhlTRcn1Lm1IfqT5RNPttIWIiD+RTx69YaE= -20251016010845.sql h1:c9DUvxl17pUkf0azdYGM/YDzYxIJkLcfZOcMI4rL+R0= -20251016011023.sql h1:u3ivg83bXgYHBbojbWpemLxPE9Dmmj53B6LXo664jxw= -20251016062912.sql h1:W9n1hWchfYkqNX9LO9uxFxEXAb/iY+Pexjnhmp6PbgI= -20251017060617.sql h1:VU6yZ2+LfHpDZ3+TIH40t3F5YXPCpTppuF9+uSqa4b8= -20251017082207.sql h1:QshZslfedckz7iDpSGmPyY9sP6dy6ckHbs8L1TuXIA4= -20251019093915.sql h1:XNEhxA1k6i+AnNjZr2jRVQrr6Q987UP+IdbwdWqHIEE= +h1:eCBVp2yPQk7VrLdSk2mDps+FXavKA5OcJ1/QRBh+ovI= +20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= +20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= +20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= +20250908062323.sql h1:oXl6Z143tOpIl4EfP4B8JNU8LrMvVmHEtCgAfiB4gs8= +20250908073811.sql h1:m2aNXfnGxnLq1+rVWrh4f60q7fhyhV3gEwNu/OIqQlE= +20250908073839.sql h1:cPk54xjLdMs26uY8ZHjNWLuyfAMzV7Zb0/9oJQrsw04= +20250910055902.sql h1:5xwjAV6QbtZT9empTJKfhyAjdknbHzb15B0Ku5dzqtQ= +20250915123412.sql h1:D83xaU2YlDEd21HLup/YQpQ2easMToYCyy/oK6AFgQs= +20250916043819.sql h1:ekoTJsBqQZ8G8n0qJ03d13+eoNoc7sAUEQGA5D/CCxk= +20250917040616.sql h1:zoCnmcXuM7AVv85SmN7RmFglCgJnoDmpRWExH0LAc9Q= +20250917040751.sql h1:J1xyRrh32y1+lezwAyNwPcUQ6ABBSgbvzNLva4SVdQU= +20250917045138.sql h1:jKe1Z0uOLG4SGBYM+S/3P+/zMPztmgoderD5swnMuCg= +20250917093645.sql h1:cNI3Pbz1R3LxvIXLuexafJFCXUXrmuFCgXXJ2sG+FW0= +20250918073552.sql h1:RJ1SvMzP6aeWnoPVD3eVAmIQOkcp6Php8z3QRri6v4g= +20250918073742.sql h1:+cEsnJTJFybe2fR69ZoOiX2R6c6iITl4m6WTZ1hjyzY= +20250918074745.sql h1:2hNVQCXF/dVYXAh+T/7oBFgERGWxzVb2FXJjwkFWGCI= +20250923025134.sql h1:Ykz/qpHiGDXPsCsWTjydQFVSibZP2D+h2fIeb2h2JGA= +20250924051317.sql h1:yQuW6SwJxIOM5fcxeAaie5lSm1oLysU/C2hH2xNCVoQ= +20250929034321.sql h1:101FJ8VH12mrZWlt/X1gvKUGOhoiF8tFbjiapAjnHzg= +20250929034428.sql h1:i+pROD9p+g5dOmmZma6WF/0Hw5g3Ha28NN85iTo1K34= +20250930025550.sql h1:+F+CsCUXD/ql0tHGEow70GhPBX1ZybVn+bh/T4YMh7Y= +20250930140351.sql h1:9AAEG1AnOAH+o0+oHL5G7I8vqlWOhwRlCGyyCpT/y1Q= +20251002085604.sql h1:3xZ68eYp4urXRnvotNH1XvG2mYOSDV/j3zHEZ/txg5E= +20251003032030.sql h1:HB+mQ2lXMNomHDpaRhB/9IwYI9/YiDO5eOJ+nAQH/jw= +20251005060450.sql h1:LbtCE2b+8osM3CvnmQJH1uCPtn+d7WchsslBOz8bL3Q= +20251006041122.sql h1:MlS7f21z06sutnf9dIekt5fuHJr4lgcQ4uCuCXAGsfc= +20251006045658.sql h1:3FmGCPCzjgMPdWDRodZTsx3KVaodd9zB9ilib69aewk= +20251006045928.sql h1:Z5g31PmnzNwk/OKdODcxZGm8fjJQdMFK32Xfnt3bRHg= +20251007022859.sql h1:FO03zEfaNEk/aXwY81d5Lp3MoBB9kPQuXlXJ4BPiSR8= +20251008031337.sql h1:l+sxUAGvcTfj3I6kAFHo+T6AYodC9k9GkR+jaKO2xXc= +20251008031554.sql h1:AqrVfIhSzY3PCy8ZlP5W91wn2iznfIuj5qQfubp6/94= +20251008052346.sql h1:nxnXmooIJ6r1mmzwnw+6efxLfc/k9h2aE6RMptPRons= +20251008073620.sql h1:6YsJp1W4SmQJ1lxpqF27BBlDC1zqhw7Yhc7pLzQTY6M= +20251009042854.sql h1:nkBV+R6j0fg7/JY6wH3eb5Vv0asJLnXmb6lINfT/GLQ= +20251009052657.sql h1:EPvdsib5rzCGPryd10HShGKvFPwM/R5S2lIVwtYxpms= +20251010031743.sql h1:T8IZmx8/btRFKLzTe78MzcBsPJNodnLvB0tby9QkirQ= +20251010070721.sql h1:5NQUk/yOV6sABLCB7swx++YIOyJe6MnU+yt1nRzde5w= +20251010072711.sql h1:ZJNqR2piyu8xJhBvVABSlnGEoKSKae3wuEs+wshPe4k= +20251013044536.sql h1:0Xjw8fNILiT8nnfrJDZgQnPf3dntmIoilbapnih8AE4= +20251013051438.sql h1:lfSuw5mgJnePBJamvhZ81osFIouXeiIEiSZ/evdwo48= +20251013081808.sql h1:ijgjNX08G6GBjA/ks8EKtb7P7Y7Cg7zbhqEOruGnv6M= +20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= +20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= +20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= +20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= +20251016010845.sql h1:4BncQdDOasRZJkzVJrSJJA7091A9VPNVx/faUCUPhBM= +20251016011023.sql h1:9JB9eFZKURK5RoCVDKR6glSvdJ8NTXrN7K/4q51zkz4= +20251016062912.sql h1:ACNn0fe+EMqUt3hoY+Dr3uqAV/QICBa1+mIW7fUc9Fk= +20251017060617.sql h1:4T3t9ifWrEQTPMSM0XJ98pF7Qdt+UfgtMui17bhrnWI= +20251017082207.sql h1:8vLG1l/saRRMHXkyA4nelJyjaSddhZd6r7R+Uo4JS/c= +20251019093915.sql h1:wsJMh1r45ONaY7zIq2c3rTcuGXN4mI0irZK7a96HZW8= From 6ae8c88053b3ce4d4cd2a0b324f4af93f2ea5074 Mon Sep 17 00:00:00 2001 From: Munawwirul Jamal Date: Sun, 19 Oct 2025 17:24:42 +0700 Subject: [PATCH 28/30] minor const --- internal/domain/references/organization/organization.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index 60270a93..93eabe63 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -12,7 +12,7 @@ type ( const ( CSCEmp ContractPositionCode = "employee" // Pegawai - CSCSpi ContractPositionCode = "intern" // PPDS + CSCInt ContractPositionCode = "intern" // PPDS EPCReg EmployeePosisitionCode = "registration" // Admisi/Pendaftaran EPCNur EmployeePosisitionCode = "nurse" // Perawat From 0f407e5df353a56949aebc1e68093d1fbfbc9925 Mon Sep 17 00:00:00 2001 From: Munawwirul Jamal Date: Sun, 19 Oct 2025 18:10:20 +0700 Subject: [PATCH 29/30] feat/user: auth reworking --- .../main-use-case/authentication/case.go | 66 ++++++++++++++----- .../main-use-case/authentication/helper.go | 36 ++++------ 2 files changed, 61 insertions(+), 41 deletions(-) diff --git a/internal/use-case/main-use-case/authentication/case.go b/internal/use-case/main-use-case/authentication/case.go index f9aec70c..ffefa7ef 100644 --- a/internal/use-case/main-use-case/authentication/case.go +++ b/internal/use-case/main-use-case/authentication/case.go @@ -19,6 +19,7 @@ import ( ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/employee" + en "simrs-vx/internal/domain/main-entities/nurse" erc "simrs-vx/internal/domain/references/common" erg "simrs-vx/internal/domain/references/organization" @@ -77,11 +78,6 @@ func GenToken(input eu.LoginDto) (*d.Data, error) { return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-unverified", Message: el.GenMessage("auth-login-unverified")}} } - userDivisionPositions, err := getDivisionPosition(user.Id) - if err != nil { - return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-getData-failed", Message: el.GenMessage("auth-getData-failed")}} - } - // Access token prep id, err := uuid.NewRandom() if err != nil { @@ -100,7 +96,6 @@ func GenToken(input eu.LoginDto) (*d.Data, error) { atClaims["user_id"] = user.Id atClaims["user_name"] = user.Name atClaims["user_contractPosition_code"] = user.ContractPosition_Code - atClaims["division_positions"] = userDivisionPositions atClaims["uuid"] = aUuid atClaims["exp"] = atExpires @@ -118,21 +113,56 @@ func GenToken(input eu.LoginDto) (*d.Data, error) { // employee employee := ee.Employee{} dg.I.Where("\"User_Id\" = ?", user.Id).First(&employee) + if employee.Id == 0 { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noEmployee", Message: el.GenMessage("auth-noEmployee")}} + } + atClaims["employee_id"] = employee.Id + outputData["employee_id"] = employee.Id role = append(role, "emp-"+string(*employee.Position_Code)) - atClaims["employee_division_code"] = employee.Division_Code - outputData["employee_division_code"] = employee.Division_Code - // doctor - if employee.Id > 0 && employee.Position_Code != nil && *employee.Position_Code == erg.EPCDoc { - doctor := ed.Doctor{} - dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&doctor) - if doctor.Specialist_Id != nil { - atClaims["specialist_id"] = doctor.Specialist_Id - outputData["specialist_id"] = doctor.Specialist_Id + + if employee.Division_Code != nil { + atClaims["employee_division_code"] = employee.Division_Code + outputData["employee_division_code"] = employee.Division_Code + } + + // employee position + if employee.Id > 0 && employee.Position_Code != nil { + switch *employee.Position_Code { + case erg.EPCDoc: + doctor := ed.Doctor{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&doctor) + if doctor.Id == 0 { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noDoctor", Message: el.GenMessage("auth-noDoctor")}} + } + atClaims["doctor_id"] = doctor.Id + outputData["doctor_id"] = doctor.Id + + // specialist + if doctor.Specialist_Id != nil { + atClaims["specialist_id"] = doctor.Specialist_Id + outputData["specialist_id"] = doctor.Specialist_Id + } + if doctor.Subspecialist_Id != nil { + atClaims["subspecialist_id"] = doctor.Subspecialist_Id + outputData["subspecialist_id"] = doctor.Subspecialist_Id + } + case erg.EPCNur: + nurse := en.Nurse{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&nurse) + if nurse.Id == 0 { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noNurse", Message: el.GenMessage("auth-noNurse")}} + } + atClaims["nurse_id"] = nurse.Id + outputData["nurse_id"] = nurse.Id } - if doctor.Subspecialist_Id != nil { - atClaims["subspecialist_id"] = doctor.Subspecialist_Id - outputData["subspecialist_id"] = doctor.Subspecialist_Id + // division position + divsionPositions, err := getDivisionPosition(employee.Id) + if err != nil { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-getData-failed", Message: el.GenMessage("auth-getData-failed")}} } + role = append(role, divsionPositions...) + // atClaims["division_positions"] = divsionPositions + // outputData["division_positions"] = divsionPositions } case erg.CSCInt: intern := intern.Intern{} diff --git a/internal/use-case/main-use-case/authentication/helper.go b/internal/use-case/main-use-case/authentication/helper.go index fef5b07e..c4e67200 100644 --- a/internal/use-case/main-use-case/authentication/helper.go +++ b/internal/use-case/main-use-case/authentication/helper.go @@ -1,11 +1,7 @@ package authentication import ( - "errors" edp "simrs-vx/internal/domain/main-entities/division-position" - ee "simrs-vx/internal/domain/main-entities/employee" - - pa "simrs-vx/pkg/auth-helper" dg "github.com/karincake/apem/db-gorm-pg" "gorm.io/gorm" @@ -27,21 +23,21 @@ func getDocName(id uint) string { return "authentication" } -func getDivisionPosition(user_id uint) ([]pa.DivisionPosition, error) { - var result []pa.DivisionPosition +func getDivisionPosition(employee_id uint) ([]string, error) { + var result []string - var employee ee.Employee - if err := dg.I.Where("\"User_Id\" = ?", user_id).First(&employee).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return result, nil - } - return result, errors.New("no employee found") - } + // var employee ee.Employee + // if err := dg.I.Where("\"Employee_Id\" = ?", employee_id).First(&employee).Error; err != nil { + // if err == gorm.ErrRecordNotFound { + // return result, nil + // } + // return result, errors.New("no employee found") + // } var divisionPositions []edp.DivisionPosition err := dg.I. Preload("Division"). - Where("\"Employee_Id\" = ?", employee.Id). + Where("\"Employee_Id\" = ?", employee_id). Find(&divisionPositions).Error if err != nil { if err == gorm.ErrRecordNotFound { @@ -51,15 +47,9 @@ func getDivisionPosition(user_id uint) ([]pa.DivisionPosition, error) { } for _, dp := range divisionPositions { - result = append(result, pa.DivisionPosition{ - Division_Code: func() string { - if dp.Division != nil { - return "div-" + dp.Division.Code - } - return "" - }(), - DivisionPosition_Code: dp.Code, - }) + if dp.Division != nil { + result = append(result, "div-"+dp.Division.Code+"-"+dp.Code) + } } return result, nil From 57d9f99468a05d44700d0369283dcfee1dca15c0 Mon Sep 17 00:00:00 2001 From: Munawwirul Jamal Date: Sun, 19 Oct 2025 21:58:07 +0700 Subject: [PATCH 30/30] feat/encounter: improved the processing --- internal/domain/main-entities/encounter/dto.go | 7 ++++--- .../references/organization/organization.go | 17 +++++++++++------ .../interface/main-handler/encounter/handler.go | 1 + .../use-case/main-use-case/encounter/lib.go | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/internal/domain/main-entities/encounter/dto.go b/internal/domain/main-entities/encounter/dto.go index 73a9ec5b..67810d27 100644 --- a/internal/domain/main-entities/encounter/dto.go +++ b/internal/domain/main-entities/encounter/dto.go @@ -70,7 +70,8 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` + Id uint16 `json:"id"` + Includes string `json:"includes"` } type UpdateDto struct { @@ -119,8 +120,8 @@ type ResponseDto struct { Member_Number *string `json:"member_number"` Ref_Number *string `json:"ref_number"` Trx_Number *string `json:"trx_number"` - Appointment_Doctor_Id *uint `json:"assignment_doctor_id"` - Appointment_Doctor *ed.Doctor `json:"assignment_doctor,omitempty"` + Appointment_Doctor_Id *uint `json:"appointment_doctor_id"` + Appointment_Doctor *ed.Doctor `json:"appointment_doctor,omitempty"` Responsible_Doctor_Id *uint `json:"responsible_doctor_id"` Responsible_Doctor *ed.Doctor `json:"responsible_doctor,omitempty"` Adm_Employee_Id *uint `json:"adm_employee_id"` diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index b2de9772..93eabe63 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -33,15 +33,20 @@ const ( ITGCMedicine ItemGroupCode = "medicine" ITGCDevice ItemGroupCode = "device" ITGCMaterial ItemGroupCode = "material" + ITGCMCU ItemGroupCode = "mcu" + ITGCMCUSub ItemGroupCode = "mcuSub" ITGCEmpFee ItemGroupCode = "employee-fee" ITGCDocFee ItemGroupCode = "doctor-fee" + ITGCMedAct ItemGroupCode = "medical-action" - IFGCBuilding InfraGroupCode = "building" - IFGCFloor InfraGroupCode = "floor" - IFGCRoom InfraGroupCode = "room" - IFGCChamber InfraGroupCode = "chamber" - IFGCBed InfraGroupCode = "bed" - IFGCWarehouse InfraGroupCode = "warehouse" + IFGCBuilding InfraGroupCode = "building" // Bangunan + IFGCFloor InfraGroupCode = "floor" // Lantai + IFGCRoom InfraGroupCode = "room" // Ruang + IFGCChamber InfraGroupCode = "chamber" // Kamar + IFGCBed InfraGroupCode = "bed" // Ranjang + IFGCWarehouse InfraGroupCode = "warehouse" // Gudang/Depo + IFGCCounter InfraGroupCode = "counter" // Counter + IFGCPubScreen InfraGroupCode = "public-screen" // Public Screen UTCReg UnitTypeCode = "reg" // Registrasi UTCExa UnitTypeCode = "exa" // Pemeriksaan diff --git a/internal/interface/main-handler/encounter/handler.go b/internal/interface/main-handler/encounter/handler.go index 09191c96..96063298 100644 --- a/internal/interface/main-handler/encounter/handler.go +++ b/internal/interface/main-handler/encounter/handler.go @@ -49,6 +49,7 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { return } dto := e.ReadDetailDto{} + sf.UrlQueryParam(&dto, *r.URL) dto.Id = uint16(id) res, err := u.ReadDetail(dto) rw.DataResponse(w, res, err) diff --git a/internal/use-case/main-use-case/encounter/lib.go b/internal/use-case/main-use-case/encounter/lib.go index 2f4d69fa..ccc4b811 100644 --- a/internal/use-case/main-use-case/encounter/lib.go +++ b/internal/use-case/main-use-case/encounter/lib.go @@ -81,7 +81,7 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e tx = dg.I } - if err := tx.First(&data, input.Id).Error; err != nil { + if err := tx.Scopes(gh.Preload(input.Includes)).First(&data, input.Id).Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { return nil, processedErr }