From 9c49b90bb6939173fe97627b0de85424d2cdb9dd Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 14 Oct 2025 13:23:58 +0700 Subject: [PATCH 01/13] 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 02/13] 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 03/13] 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 04/13] 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 05/13] 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 06/13] 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 07/13] 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 a8e41f055c746a32100248f22d09b461e44a1f87 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 16 Oct 2025 08:12:54 +0700 Subject: [PATCH 08/13] add person-insurance, adjust person --- .../migrations/20251016010845.sql | 2 + .../migrations/20251016011023.sql | 17 ++++++ cmd/main-migration/migrations/atlas.sum | 6 +- .../domain/main-entities/encounter/entity.go | 2 +- .../main-entities/person-insurance/dto.go | 1 + .../main-entities/person-insurance/entity.go | 15 +++++ .../domain/main-entities/person/entity.go | 60 ++++++++++--------- internal/interface/migration/main-entities.go | 2 + 8 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 cmd/main-migration/migrations/20251016010845.sql create mode 100644 cmd/main-migration/migrations/20251016011023.sql create mode 100644 internal/domain/main-entities/person-insurance/dto.go create mode 100644 internal/domain/main-entities/person-insurance/entity.go diff --git a/cmd/main-migration/migrations/20251016010845.sql b/cmd/main-migration/migrations/20251016010845.sql new file mode 100644 index 00000000..edbbb414 --- /dev/null +++ b/cmd/main-migration/migrations/20251016010845.sql @@ -0,0 +1,2 @@ +-- Rename a column from "ClassCode" to "Class_Code" +ALTER TABLE "public"."Chemo" RENAME COLUMN "ClassCode" TO "Class_Code"; diff --git a/cmd/main-migration/migrations/20251016011023.sql b/cmd/main-migration/migrations/20251016011023.sql new file mode 100644 index 00000000..12e51e7d --- /dev/null +++ b/cmd/main-migration/migrations/20251016011023.sql @@ -0,0 +1,17 @@ +-- Create "PersonInsurance" table +CREATE TABLE "public"."PersonInsurance" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Person_Id" bigint NULL, + "InsuranceCompany_Id" bigint NULL, + "Ref_Number" character varying(20) NULL, + "DefaultStatus" boolean NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_PersonInsurance_Ref_Number" UNIQUE ("Ref_Number"), + CONSTRAINT "fk_PersonInsurance_InsuranceCompany" FOREIGN KEY ("InsuranceCompany_Id") REFERENCES "public"."InsuranceCompany" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Person_Insurances" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create index "idx_person_insurance" to table: "PersonInsurance" +CREATE UNIQUE INDEX "idx_person_insurance" ON "public"."PersonInsurance" ("Person_Id", "DefaultStatus"); diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index e3172704..05c66cea 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:Y15nC3Bp3DWNym7hAvXkF9zFwkHh8nQDpxcNrxQgYhE= +h1:qfP77w9XYWpAFDON1lo+vpqIYCSiPkVEyHXcYFC52Hk= 20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= 20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= 20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= @@ -43,4 +43,6 @@ h1:Y15nC3Bp3DWNym7hAvXkF9zFwkHh8nQDpxcNrxQgYhE= 20251014060047.sql h1:0jqj49WTtneEIMQDBoo4c095ZGi8sCrA8NnHBrPU6D8= 20251014063537.sql h1:VZLXol0PTsTW21Epg6vBPsztWkDtcxup9F/z88EGgIg= 20251014063720.sql h1:2HVUyCV0ud3BJJDH2GEKZN/+IWLFPCsN1KqhP6csO14= -20251015045455.sql h1:v120CzYYiFWmW81VmKWsjmjRiBIv5aFnPZXwQaQxqes= +20251015045455.sql h1:MeLWmMhAOAz8b15Dd7IAQnt6JxjSml02XCXK22C0Lpg= +20251016010845.sql h1:MSUh26glEDyZ5BFiteYOm9mUCWw7aG9vv5TxYY+EidU= +20251016011023.sql h1:8oUBzIpzAYTo03yex+wLKacv32YjXmn4MsXtBFiQtzY= diff --git a/internal/domain/main-entities/encounter/entity.go b/internal/domain/main-entities/encounter/entity.go index c9f81712..3e888356 100644 --- a/internal/domain/main-entities/encounter/entity.go +++ b/internal/domain/main-entities/encounter/entity.go @@ -32,10 +32,10 @@ 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"` diff --git a/internal/domain/main-entities/person-insurance/dto.go b/internal/domain/main-entities/person-insurance/dto.go new file mode 100644 index 00000000..5a2ee2a1 --- /dev/null +++ b/internal/domain/main-entities/person-insurance/dto.go @@ -0,0 +1 @@ +package personinsurance diff --git a/internal/domain/main-entities/person-insurance/entity.go b/internal/domain/main-entities/person-insurance/entity.go new file mode 100644 index 00000000..64057835 --- /dev/null +++ b/internal/domain/main-entities/person-insurance/entity.go @@ -0,0 +1,15 @@ +package personinsurance + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/insurance-company" +) + +type PersonInsurance struct { + ecore.Main + Person_Id *uint `json:"person_id" gorm:"uniqueIndex:idx_person_insurance"` + InsuranceCompany_Id *uint `json:"insurance_id"` + InsuranceCompany *ei.InsuranceCompany `json:"insurance,omitempty" gorm:"foreignKey:InsuranceCompany_Id;references:Id"` + Ref_Number *string `json:"ref_number" gorm:"unique;size:20"` + DefaultStatus *bool `json:"default_status" gorm:"uniqueIndex:idx_person_insurance"` +} diff --git a/internal/domain/main-entities/person/entity.go b/internal/domain/main-entities/person/entity.go index 8639df25..8932ca1b 100644 --- a/internal/domain/main-entities/person/entity.go +++ b/internal/domain/main-entities/person/entity.go @@ -6,6 +6,7 @@ import ( el "simrs-vx/internal/domain/main-entities/language" 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" er "simrs-vx/internal/domain/main-entities/regency" @@ -15,35 +16,36 @@ import ( ) type Person struct { - ecore.Main // adjust this according to the needs - Name string `json:"name" gorm:"not null;size:150"` - FrontTitle *string `json:"frontTitle" gorm:"size:50"` - EndTitle *string `json:"endTitle" gorm:"size:50"` - BirthDate *time.Time `json:"birthDate,omitempty"` - BirthRegency_Code *string `json:"birthRegency_code" gorm:"size:4"` - BirthRegency *er.Regency `json:"birthRegency,omitempty" gorm:"foreignKey:BirthRegency_Code;references:Code"` - Gender_Code *erp.GenderCode `json:"gender_code" gorm:"size:10"` - ResidentIdentityNumber *string `json:"residentIdentityNumber" gorm:"unique;size:16"` - PassportNumber *string `json:"passportNumber" gorm:"unique;size:20"` - DrivingLicenseNumber *string `json:"drivingLicenseNumber" gorm:"unique;size:20"` - Religion_Code *erp.ReligionCode `json:"religion_code" gorm:"size:10"` - Education_Code *erp.EducationCode `json:"education_code" gorm:"size:10"` - Ocupation_Code *erp.OcupationCode `json:"occupation_code" gorm:"size:15"` - Ocupation_Name *string `json:"occupation_name" gorm:"size:50"` - Nationality *string `json:"nationality": gorm:"size:50"` - Ethnic_Code *string `json:"ethnic_code" gorm:"size:20"` - Ethnic *ee.Ethnic `json:"ethnic,omitempty" gorm:"foreignKey:Ethnic_Code;references:Code"` - Addresses *[]epa.PersonAddress `json:"addresses" gorm:"foreignKey:Person_Id"` - Contacts *[]epc.PersonContact `json:"contacts" gorm:"foreignKey:Person_Id"` - Relatives *[]epr.PersonRelative `json:"relatives" gorm:"foreignKey:Person_Id"` - Language_Code *string `json:"language_code" gorm:"size:10"` - Language *el.Language `json:"language,omitempty" gorm:"foreignKey:Language_Code;references:Code"` - CommunicationIssueStatus bool `json:"communicationIssueStatus"` - Disability *string `json:"disability" gorm:"size:100"` - ResidentIdentityFileUrl *string `json:"residentIdentityFileUrl" gorm:"size:1024"` - PassportFileUrl *string `json:"passportFileUrl" gorm:"size:1024"` - DrivingLicenseFileUrl *string `json:"drivingLicenseFileUrl" gorm:"size:1024"` - FamilyIdentityFileUrl *string `json:"familyIdentityFileUrl" gorm:"size:1024"` + ecore.Main // adjust this according to the needs + Name string `json:"name" gorm:"not null;size:150"` + FrontTitle *string `json:"frontTitle" gorm:"size:50"` + EndTitle *string `json:"endTitle" gorm:"size:50"` + BirthDate *time.Time `json:"birthDate,omitempty"` + BirthRegency_Code *string `json:"birthRegency_code" gorm:"size:4"` + BirthRegency *er.Regency `json:"birthRegency,omitempty" gorm:"foreignKey:BirthRegency_Code;references:Code"` + Gender_Code *erp.GenderCode `json:"gender_code" gorm:"size:10"` + ResidentIdentityNumber *string `json:"residentIdentityNumber" gorm:"unique;size:16"` + PassportNumber *string `json:"passportNumber" gorm:"unique;size:20"` + DrivingLicenseNumber *string `json:"drivingLicenseNumber" gorm:"unique;size:20"` + Religion_Code *erp.ReligionCode `json:"religion_code" gorm:"size:10"` + Education_Code *erp.EducationCode `json:"education_code" gorm:"size:10"` + Ocupation_Code *erp.OcupationCode `json:"occupation_code" gorm:"size:15"` + Ocupation_Name *string `json:"occupation_name" gorm:"size:50"` + Nationality *string `json:"nationality": gorm:"size:50"` + Ethnic_Code *string `json:"ethnic_code" gorm:"size:20"` + Ethnic *ee.Ethnic `json:"ethnic,omitempty" gorm:"foreignKey:Ethnic_Code;references:Code"` + Language_Code *string `json:"language_code" gorm:"size:10"` + Language *el.Language `json:"language,omitempty" gorm:"foreignKey:Language_Code;references:Code"` + CommunicationIssueStatus bool `json:"communicationIssueStatus"` + Disability *string `json:"disability" gorm:"size:100"` + ResidentIdentityFileUrl *string `json:"residentIdentityFileUrl" gorm:"size:1024"` + PassportFileUrl *string `json:"passportFileUrl" gorm:"size:1024"` + DrivingLicenseFileUrl *string `json:"drivingLicenseFileUrl" gorm:"size:1024"` + FamilyIdentityFileUrl *string `json:"familyIdentityFileUrl" gorm:"size:1024"` + Addresses *[]epa.PersonAddress `json:"addresses" gorm:"foreignKey:Person_Id"` + Contacts *[]epc.PersonContact `json:"contacts" gorm:"foreignKey:Person_Id"` + Relatives *[]epr.PersonRelative `json:"relatives" gorm:"foreignKey:Person_Id"` + Insurances *[]epi.PersonInsurance `json:"insurances" gorm:"foreignKey:Person_Id"` } func (d Person) IsSameResidentIdentityNumber(input *string) bool { diff --git a/internal/interface/migration/main-entities.go b/internal/interface/migration/main-entities.go index 034495c3..ea8ec1c0 100644 --- a/internal/interface/migration/main-entities.go +++ b/internal/interface/migration/main-entities.go @@ -55,6 +55,7 @@ import ( person "simrs-vx/internal/domain/main-entities/person" personaddress "simrs-vx/internal/domain/main-entities/person-address" personcontact "simrs-vx/internal/domain/main-entities/person-contact" + personinsurance "simrs-vx/internal/domain/main-entities/person-insurance" personrelative "simrs-vx/internal/domain/main-entities/person-relative" pharmacist "simrs-vx/internal/domain/main-entities/pharmacist" pharmacycompany "simrs-vx/internal/domain/main-entities/pharmacy-company" @@ -96,6 +97,7 @@ func getMainEntities() []any { &person.Person{}, &personaddress.PersonAddress{}, &personcontact.PersonContact{}, + &personinsurance.PersonInsurance{}, &pharmacycompany.PharmacyCompany{}, &diagnosesrc.DiagnoseSrc{}, &proceduresrc.ProcedureSrc{}, From 609119c3060ae9435e675d16d0595076bdb6f06f Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 16 Oct 2025 08:39:22 +0700 Subject: [PATCH 09/13] 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/13] 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/13] 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/13] 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/13] 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 {