Merge pull request #215 from dikstub-rssa/feat/chemo-plan

Feat/chemo plan
This commit is contained in:
Dwi Atmoko Purbo Sakti
2025-12-15 15:22:41 +07:00
committed by GitHub
28 changed files with 1477 additions and 354 deletions
@@ -0,0 +1,317 @@
package chemo_plan
import (
ere "simrs-vx/internal/domain/references/encounter"
pl "simrs-vx/pkg/logger"
pu "simrs-vx/pkg/use-case-helper"
"strconv"
dg "github.com/karincake/apem/db-gorm-pg"
d "github.com/karincake/dodol"
"gorm.io/gorm"
erc "simrs-vx/internal/domain/references/common"
e "simrs-vx/internal/domain/main-entities/chemo-plan"
ep "simrs-vx/internal/domain/main-entities/chemo-protocol"
)
const source = "chemo-plan"
func Create(input ep.CreateDto) (*d.Data, error) {
data := []e.ChemoPlan{}
event := pl.Event{
Feature: "Create",
Source: source,
}
// Start log
pl.SetLogInfo(&event, input, "started", "create")
err := dg.I.Transaction(func(tx *gorm.DB) error {
input.Status_Code = erc.DVCNew
if resData, err := CreateData(&input, &event, tx); err != nil {
return err
} else {
data = *resData
}
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: e.ToResponseList(data),
}, nil
}
func ReadList(input e.ReadListDto) (*d.Data, error) {
var data *e.ChemoPlan
var dataList []e.ChemoPlan
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.ChemoPlan
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.ChemoPlan
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
}
if err := UpdateData(data, "", &event, tx); err != nil {
return err
}
pl.SetLogInfo(&event, nil, "complete")
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.ChemoPlan
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
}
func Fail(input e.FailDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: input.Id}
var data *e.ChemoPlan
var err error
event := pl.Event{
Feature: "Chemo-Fail",
Source: source,
}
// Start log
pl.SetLogInfo(&event, input, "started", "update")
if data, err = ReadDetailData(rdDto, &event); err != nil {
return nil, err
}
dataSoapi, err := getSoapiByEncounterId(*data.Encounter_Id, &event)
if err != nil {
return nil, err
}
if dataSoapi != nil && len(*dataSoapi) > 0 {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "soapi-exist",
Detail: "cancel soapi to proceed",
}
return nil, pl.SetLogError(&event, data)
}
if *data.Status != ere.SPCPlanned {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "invalid-chemo-status",
Detail: "only chemo plans with status 'planned' can be deleted.",
}
}
err = dg.I.Transaction(func(tx *gorm.DB) error {
if err := UpdateFailData(input, data, &event, tx); err != nil {
return err
}
pl.SetLogInfo(&event, nil, "complete")
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
}
@@ -0,0 +1,90 @@
/*
DESCRIPTION:
Any functions that are used internally by the use-case
*/
package chemo_plan
import (
"encoding/json"
pl "simrs-vx/pkg/logger"
pu "simrs-vx/pkg/use-case-helper"
"time"
dg "github.com/karincake/apem/db-gorm-pg"
ere "simrs-vx/internal/domain/references/encounter"
e "simrs-vx/internal/domain/main-entities/chemo-plan"
ep "simrs-vx/internal/domain/main-entities/chemo-protocol"
es "simrs-vx/internal/domain/main-entities/soapi"
)
var now = time.Now()
func setDataCreate(input *ep.CreateDto) (data []e.ChemoPlan) {
for _, c := range *input.ChemoPlans {
data = append(data, e.ChemoPlan{
Parent_Id: input.Chemo_Id,
Protocol_Id: input.Id,
SeriesNumber: c.SeriesNumber,
CycleNumber: c.CycleNumber,
PlanDate: c.PlanDate,
})
}
return
}
func setDataCreateSoapi(data *e.ChemoPlan) {
data.RealizationDate = &now
status := ere.SPCComplete
data.Status = &status
}
func setDataDeleteSoapi(data *e.ChemoPlan) {
status := ere.SPCPlanned
data.Status = &status
}
func setDatafail(input e.FailDto, data *e.ChemoPlan) {
data.RealizationDate = nil
status := ere.SPCSchedule
data.Status = &status
var reasons []e.FailReason
if data.Reasons != nil {
json.Unmarshal([]byte(*data.Reasons), &reasons)
}
reasons = append(reasons, e.FailReason{
FailReason: input.Reasons,
Date: &now,
Encounter_Id: data.Encounter_Id,
})
if b, err := json.Marshal(reasons); err == nil {
jsonStr := string(b)
data.Reasons = &jsonStr
}
}
func getSoapiByEncounterId(encounterId uint, event *pl.Event) (*[]es.Soapi, error) {
pl.SetLogInfo(event, encounterId, "started", "DBReadDetail")
var data []es.Soapi
var tx = dg.I
if err := tx.
Model(&es.Soapi{}).
Where(`"Encounter_Id" = ?`, encounterId).
Find(&data).Error; err != nil {
if processedErr := pu.HandleReadError(err, event, source, encounterId, data); processedErr != nil {
return nil, processedErr
}
}
pl.SetLogInfo(event, nil, "complete")
return &data, nil
}
@@ -0,0 +1,178 @@
package chemo_plan
import (
"errors"
plh "simrs-vx/pkg/lib-helper"
pl "simrs-vx/pkg/logger"
pu "simrs-vx/pkg/use-case-helper"
"gorm.io/gorm"
dg "github.com/karincake/apem/db-gorm-pg"
gh "github.com/karincake/getuk"
e "simrs-vx/internal/domain/main-entities/chemo-plan"
ep "simrs-vx/internal/domain/main-entities/chemo-protocol"
)
func CreateData(input *ep.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*[]e.ChemoPlan, error) {
pl.SetLogInfo(event, nil, "started", "DBCreate")
data := setDataCreate(input)
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.ChemoPlan, *e.MetaDto, error) {
pl.SetLogInfo(event, input, "started", "DBReadList")
data := []e.ChemoPlan{}
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.ChemoPlan{}).
Scopes(gh.Preload(input.Includes)).
Scopes(gh.Filter(input.FilterDto)).
Count(&count).
Scopes(gh.Paginate(input, &pagination)).
Order("\"CreatedAt\" DESC")
if err := tx.Find(&data).Error; err != nil {
if errors.Is(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.ChemoPlan, error) {
pl.SetLogInfo(event, input, "started", "DBReadDetail")
data := e.ChemoPlan{}
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
if err := tx.
Scopes(gh.Preload(input.Includes)).
First(&data, input.Id).
Error; err != nil {
if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil {
return nil, processedErr
}
}
pl.SetLogInfo(event, nil, "complete")
return &data, nil
}
func UpdateData(data *e.ChemoPlan, method string, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, data, "started", "DBUpdate")
switch method {
case "c":
setDataCreateSoapi(data)
case "d":
setDataDeleteSoapi(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, data)
}
pl.SetLogInfo(event, nil, "complete")
return nil
}
func DeleteData(data *e.ChemoPlan, 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 UpdateFailData(input e.FailDto, data *e.ChemoPlan, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, data, "started", "DBUpdate")
setDatafail(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, data)
}
pl.SetLogInfo(event, nil, "complete")
return nil
}
@@ -0,0 +1,103 @@
package chemo_plan
import (
e "simrs-vx/internal/domain/main-entities/chemo-plan"
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.ChemoPlan) 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.ChemoPlan) 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.ChemoPlan) 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.ChemoPlan) 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.ChemoPlan) 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
}
@@ -0,0 +1,9 @@
package chemo_plan
// example of middleware
// func init() {
// createPreMw = append(createPreMw,
// CreateMw{Name: "modif-input", Func: pm.ModifInput},
// CreateMw{Name: "check-data", Func: pm.CheckData},
// )
// }
@@ -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 chemo_plan
import (
"gorm.io/gorm"
e "simrs-vx/internal/domain/main-entities/chemo-plan"
)
type createMw struct {
Name string
Func func(input *e.CreateDto, data *e.ChemoPlan, tx *gorm.DB) error
}
type readListMw struct {
Name string
Func func(input *e.ReadListDto, data *e.ChemoPlan, tx *gorm.DB) error
}
type readDetailMw struct {
Name string
Func func(input *e.ReadDetailDto, data *e.ChemoPlan, 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
@@ -1,6 +1,7 @@
package chemo_protocol
import (
"errors"
"strconv"
dg "github.com/karincake/apem/db-gorm-pg"
@@ -11,13 +12,22 @@ import (
"gorm.io/gorm"
erc "simrs-vx/internal/domain/references/common"
ec "simrs-vx/internal/domain/main-entities/chemo"
e "simrs-vx/internal/domain/main-entities/chemo-protocol"
ee "simrs-vx/internal/domain/main-entities/encounter"
uc "simrs-vx/internal/use-case/main-use-case/chemo"
ucp "simrs-vx/internal/use-case/main-use-case/chemo-plan"
ue "simrs-vx/internal/use-case/main-use-case/encounter"
)
const source = "chemo-protocol"
func Create(input e.CreateDto) (*d.Data, error) {
data := e.ChemoProtocol{}
var err error
event := pl.Event{
Feature: "Create",
@@ -27,23 +37,43 @@ func Create(input e.CreateDto) (*d.Data, error) {
// 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 input.Patient_Id == nil {
// get encounter
dataEncounter, err := ue.ReadDetailData(ee.ReadDetailDto{Id: *input.Encounter_Id}, &event)
if err != nil {
return nil, err
}
input.Patient_Id = dataEncounter.Patient_Id
input.Status_Code = erc.DVCNew
}
// get chemo
dataChemo, err := uc.ReadDetailData(ec.ReadDetailDto{Id: *input.Chemo_Id}, &event)
if err != nil {
return nil, err
}
if dataChemo.Status_Code != erc.DVCVerified {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-validation-fail",
Detail: "chemo must be verified",
}
return nil, pl.SetLogError(&event, input)
}
err = dg.I.Transaction(func(tx *gorm.DB) error {
// Insert Chemo-Protocol
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 {
// Insert Chemo-Plans
input.Id = &data.Id
if data.ChemoPlans, err = ucp.CreateData(&input, &event, tx); err != nil {
return err
}
@@ -80,6 +110,15 @@ func ReadList(input e.ReadListDto) (*d.Data, error) {
// Start log
pl.SetLogInfo(&event, input, "started", "readList")
if input.Patient_Id == nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-validation-fail",
Detail: "patient-id is required",
}
return nil, pl.SetLogError(&event, input)
}
err = dg.I.Transaction(func(tx *gorm.DB) error {
mwRunner := newMiddlewareRunner(&event, tx)
mwRunner.setMwType(pu.MWTPre)
@@ -275,3 +314,65 @@ func Delete(input e.DeleteDto) (*d.Data, error) {
}, nil
}
func Verify(input e.VerifyDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: input.Id}
var data *e.ChemoProtocol
var err error
event := pl.Event{
Feature: "Verify",
Source: source,
}
// Start log
pl.SetLogInfo(&event, input, "started", "verify")
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
}
if data.Status_Code != erc.DVCNew {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-state-mismatch",
Detail: "data is not new",
Raw: errors.New("data is not new"),
}
return pl.SetLogError(&event, input)
}
data.VerifiedAt = pu.GetTimeNow()
data.Status_Code = erc.DVCVerified
data.VerifiedBy_User_Id = &input.AuthInfo.User_Id
err = tx.Save(&data).Error
if 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
})
if err != nil {
}
return &d.Data{
Meta: d.IS{
"source": source,
"structure": "single-data",
"status": "verify",
},
Data: data.ToResponse(),
}, nil
}
@@ -17,9 +17,15 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ChemoProtocol) {
inputSrc = &inputTemp.CreateDto
}
data.Chemo_Id = inputSrc.Chemo_Id
data.Patient_Weight = inputSrc.Patient_Weight
data.Patient_Height = inputSrc.Patient_Height
data.Diagnoses = inputSrc.Diagnoses
data.Interval = inputSrc.Interval
data.Cycle = inputSrc.Cycle
data.Series = inputSrc.Series
data.StartDate = inputSrc.StartDate
data.EndDate = inputSrc.EndDate
data.Status_Code = inputSrc.Status_Code
data.Patient_Id = inputSrc.Patient_Id
}
@@ -2,7 +2,6 @@ package chemo_protocol
import (
"errors"
plh "simrs-vx/pkg/lib-helper"
pl "simrs-vx/pkg/logger"
pu "simrs-vx/pkg/use-case-helper"
+26 -27
View File
@@ -4,10 +4,6 @@ import (
"errors"
"strconv"
e "simrs-vx/internal/domain/main-entities/chemo"
erc "simrs-vx/internal/domain/references/common"
dg "github.com/karincake/apem/db-gorm-pg"
d "github.com/karincake/dodol"
@@ -15,9 +11,13 @@ import (
pu "simrs-vx/pkg/use-case-helper"
"gorm.io/gorm"
erc "simrs-vx/internal/domain/references/common"
e "simrs-vx/internal/domain/main-entities/chemo"
)
const source = "division"
const source = "chemo"
func Create(input e.CreateDto) (*d.Data, error) {
data := e.Chemo{}
@@ -70,7 +70,6 @@ func Create(input e.CreateDto) (*d.Data, error) {
}
func ReadList(input e.ReadListDto) (*d.Data, error) {
var data *e.Chemo
var dataList []e.Chemo
var metaList *e.MetaDto
var err error
@@ -83,28 +82,17 @@ func ReadList(input e.ReadListDto) (*d.Data, error) {
// 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 input.Patient_Id == nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-validation-fail",
Detail: "patient-id is required",
}
return nil, pl.SetLogError(&event, input)
}
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 {
input.Encounter_Id = nil
if dataList, metaList, err = ReadListData(input, &event); err != nil {
return nil, err
}
@@ -134,6 +122,15 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) {
// Start log
pl.SetLogInfo(&event, input, "started", "readDetail")
if input.Encounter_Id == nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-validation-fail",
Detail: "Encounter-Id is required",
}
return nil, pl.SetLogError(&event, input)
}
err = dg.I.Transaction(func(tx *gorm.DB) error {
mwRunner := newMiddlewareRunner(&event, tx)
mwRunner.setMwType(pu.MWTPre)
@@ -309,10 +306,12 @@ func Verify(input e.VerifyDto) (*d.Data, error) {
}
data.VerifiedAt = pu.GetTimeNow()
data.Status_Code = input.Status_Code
data.Status_Code = erc.DVCVerified
data.VerifiedBy_User_Id = &input.AuthInfo.User_Id
data.Bed = input.Bed
data.Needs = input.Needs
data.Doctor_Code = input.Doctor_Code
data.NextChemoDate = input.NextChemoDate
err = tx.Save(&data).Error
if err != nil {
@@ -20,4 +20,5 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Chemo) {
data.Encounter_Id = inputSrc.Encounter_Id
data.Status_Code = inputSrc.Status_Code
data.Specialist_Code = inputSrc.Specialist_Code
data.Class_Code = inputSrc.Class_Code
}
+12 -1
View File
@@ -47,8 +47,16 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ch
tx = dg.I
}
if input.Class_Code != "" {
tx = tx.Where(`"Chemo"."Class_Code" = ?`, input.Class_Code)
input.Class_Code = ""
}
tx = tx.
Model(&e.Chemo{}).
Joins(`LEFT JOIN "Encounter" "e" ON "e"."Id" = "Chemo"."Encounter_Id"`).
Joins(`LEFT JOIN "Patient" "p" ON "e"."Patient_Id" = "p"."Id"`).
Where(`"p"."Id" = ?`, input.Patient_Id).
Scopes(gh.Preload(input.Includes)).
Scopes(gh.Filter(input.FilterDto)).
Count(&count).
@@ -81,7 +89,10 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e
tx = dg.I
}
if err := tx.First(&data, input.Id).Error; err != nil {
if err := tx.
Scopes(gh.Preload(input.Includes)).
Scopes(gh.Filter(input.FilterDto)).
First(&data, input.Id).Error; err != nil {
if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil {
return nil, processedErr
}
@@ -7,7 +7,6 @@ package encounter
import (
"errors"
"fmt"
un "simrs-vx/internal/use-case/main-use-case/nurse"
"strings"
"time"
@@ -24,9 +23,10 @@ import (
ere "simrs-vx/internal/domain/references/encounter"
erg "simrs-vx/internal/domain/references/organization"
eaeh "simrs-vx/internal/domain/main-entities/adm-employee-hist"
ea "simrs-vx/internal/domain/main-entities/ambulatory"
ec "simrs-vx/internal/domain/main-entities/chemo"
ecpl "simrs-vx/internal/domain/main-entities/chemo-plan"
ecp "simrs-vx/internal/domain/main-entities/chemo-protocol"
edo "simrs-vx/internal/domain/main-entities/device-order"
ed "simrs-vx/internal/domain/main-entities/doctor"
ee "simrs-vx/internal/domain/main-entities/emergency"
@@ -42,12 +42,9 @@ import (
ep "simrs-vx/internal/domain/main-entities/prescription"
epi "simrs-vx/internal/domain/main-entities/prescription-item"
er "simrs-vx/internal/domain/main-entities/rehab"
erdh "simrs-vx/internal/domain/main-entities/responsible-doctor-hist"
es "simrs-vx/internal/domain/main-entities/soapi"
esp "simrs-vx/internal/domain/main-entities/specialist"
// udo "simrs-vx/internal/use-case/main-use-case/device-order"
uaeh "simrs-vx/internal/use-case/main-use-case/adm-employee-hist"
ua "simrs-vx/internal/use-case/main-use-case/ambulatory"
uc "simrs-vx/internal/use-case/main-use-case/chemo"
ud "simrs-vx/internal/use-case/main-use-case/doctor"
@@ -58,10 +55,10 @@ import (
umi "simrs-vx/internal/use-case/main-use-case/medicine-mix"
ummi "simrs-vx/internal/use-case/main-use-case/medicine-mix-item"
_ "simrs-vx/internal/use-case/main-use-case/nurse"
un "simrs-vx/internal/use-case/main-use-case/nurse"
up "simrs-vx/internal/use-case/main-use-case/prescription"
upi "simrs-vx/internal/use-case/main-use-case/prescription-item"
ur "simrs-vx/internal/use-case/main-use-case/rehab"
urdh "simrs-vx/internal/use-case/main-use-case/responsible-doctor-hist"
us "simrs-vx/internal/use-case/main-use-case/soapi"
)
@@ -396,192 +393,6 @@ func getMcuOrders(encounter_id uint, event *pl.Event, tx *gorm.DB) error {
return nil
}
func upsertResponsibleDoctorHist(input erdh.CreateDto, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, nil, "started", "DBCreate")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
var latest erdh.ResponsibleDoctorHist
err := tx.
Where("\"Encounter_Id\" = ?", input.Encounter_Id).
Order("\"CreatedAt\" DESC").
Limit(1).
First(&latest).Error
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
// Insert
if _, err = urdh.CreateData(input, event, tx); err != nil {
return err
}
case err != nil:
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "read-fail",
Detail: "Failed to read responsible doctor history",
Raw: err,
}
return pl.SetLogError(event, input)
default:
// Update
if err := tx.Model(&latest).Updates(map[string]interface{}{
"Doctor_Code": input.Doctor_Code,
"StartedAt": input.StartedAt,
"UpdatedAt": time.Now(),
}).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "update-fail",
Detail: "Failed to update responsible doctor history",
Raw: err,
}
return pl.SetLogError(event, input)
}
}
pl.SetLogInfo(event, input, "complete")
return nil
}
func upsertAdmEmployeeHist(input eaeh.CreateDto, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, nil, "started", "DBCreate")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
var latest eaeh.AdmEmployeeHist
err := tx.
Where("\"Encounter_Id\" = ?", input.Encounter_Id).
Order("\"CreatedAt\" DESC").
Limit(1).
First(&latest).Error
switch {
case errors.Is(err, gorm.ErrRecordNotFound):
// Insert
if _, err = uaeh.CreateData(input, event, tx); err != nil {
return err
}
case err != nil:
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "read-fail",
Detail: "Failed to read responsible doctor history",
Raw: err,
}
return pl.SetLogError(event, input)
default:
// Update
if err := tx.Model(&latest).Updates(map[string]interface{}{
"Employee_Id": input.Employee_Id,
"StartedAt": input.StartedAt,
"UpdatedAt": time.Now(),
}).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "update-fail",
Detail: "Failed to update responsible doctor history",
Raw: err,
}
return pl.SetLogError(event, input)
}
}
pl.SetLogInfo(event, input, "complete")
return nil
}
func updateLatestResponsibleDoctorHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, "started", "DBUpdate")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
subQuery := tx.
Select("\"Id\"").
Model(&erdh.ResponsibleDoctorHist{}).
Where("\"Encounter_Id\" = ?", input.Id).
Order("\"CreatedAt\" DESC").
Limit(1)
result := tx.
Model(&erdh.ResponsibleDoctorHist{}).
Where("\"Id\" = (?)", subQuery).
Update("\"FinishedAt\"", input.FinishedAt)
if result.Error != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-update-fail",
Detail: "Database update failed",
Raw: result.Error,
}
return pl.SetLogError(event, input)
}
if result.RowsAffected == 0 {
pl.SetLogInfo(event, input, "no previous data found to update")
return nil
}
pl.SetLogInfo(event, nil, "complete")
return nil
}
func updateLatestAdmEmployeeHist(input e.CheckinDto, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, "started", "DBUpdate")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
subQuery := tx.
Select("\"Id\"").
Model(&eaeh.AdmEmployeeHist{}).
Where("\"Encounter_Id\" = ?", input.Id).
Order("\"CreatedAt\" DESC").
Limit(1)
result := tx.
Model(&eaeh.AdmEmployeeHist{}).
Where("\"Id\" = (?)", subQuery).
Update("\"FinishedAt\"", input.FinishedAt)
if result.Error != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-update-fail",
Detail: "Database update failed",
Raw: result.Error,
}
return pl.SetLogError(event, input)
}
if result.RowsAffected == 0 {
pl.SetLogInfo(event, input, "no previous data found to update")
return nil
}
pl.SetLogInfo(event, nil, "complete")
return nil
}
func getSoapiByResponsibleDoctor(enc e.Encounter, event *pl.Event) (data []es.Soapi, err error) {
pl.SetLogInfo(event, enc, "started", "DBReadList")
@@ -849,13 +660,31 @@ func insertdataClassCode(input e.CreateDto, soapiData []es.CreateDto, event *pl.
func insertDataSubClassAmbulatory(input e.CreateDto, soapiData []es.CreateDto, event *pl.Event, tx *gorm.DB) (err error) {
subCode := ere.AmbulatoryClassCode(*input.SubClass_Code)
var chemoPlan *ecpl.ChemoPlan
switch {
case subCode == ere.ACCChemo:
// validate if encounter Chemo valid
chemoPlan, err = validateChemo(*input.Patient_Id, event)
if err != nil {
return err
}
if chemoPlan == nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-not-found",
Detail: "chemo plan not found",
}
return pl.SetLogError(event, input)
}
chemoCreate := ec.CreateDto{
Encounter_Id: &input.Id,
Status_Code: erc.DVCNew,
Status_Code: erc.DVCVerified,
Specialist_Code: input.Specialist_Code,
Class_Code: ere.CCCAct,
}
// create data chemo
@@ -864,6 +693,13 @@ func insertDataSubClassAmbulatory(input e.CreateDto, soapiData []es.CreateDto, e
return err
}
// set chemo-plan to planned
chemoPlan.Encounter_Id = &input.Id
err = updateChemoPlan(chemoPlan, event, tx)
if err != nil {
return err
}
case subCode == ere.ACCRehab:
rehabData := er.CreateDto{
Encounter_Id: &input.Id,
@@ -1009,18 +845,18 @@ func getDoctors(doctorIds []string, event *pl.Event) ([]ed.Doctor, error) {
return doctors, nil
}
func validateSpecialistCodes(unitCodes map[string]struct{}, event *pl.Event) error {
if len(unitCodes) > 0 {
func validateSpecialistCodes(speCodes map[string]struct{}, event *pl.Event) error {
if len(speCodes) > 0 {
var codes []string
for code := range unitCodes {
for code := range speCodes {
codes = append(codes, code)
}
units, err := getSpecialists(codes, event)
specialists, err := getSpecialists(codes, event)
if err != nil {
return fmt.Errorf("failed to fetch units: %w", err)
}
if len(units) != len(codes) {
if len(specialists) != len(codes) {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-validation-fail",
@@ -1056,3 +892,127 @@ func validateDoctorCodes(doctorCodes map[string]struct{}, event *pl.Event) error
return nil
}
func updateChemoPlan(data *ecpl.ChemoPlan, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, nil, "started", "getChemoFromEncounter")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
err := tx.Model(&data).Updates(map[string]interface{}{
`"Status"`: ere.SPCPlanned,
`"Encounter_Id"`: data.Encounter_Id}).Error
if err != nil {
return err
}
pl.SetLogInfo(event, nil, "complete")
return nil
}
func getChemoProtocol(patientId uint, event *pl.Event) (*ecp.ChemoProtocol, error) {
pl.SetLogInfo(event, nil, "started", "getChemoProtocol")
data := ecp.ChemoProtocol{}
var tx = dg.I
tx = tx.Model(&ecp.ChemoProtocol{}).
Joins(`LEFT JOIN "ChemoPlan" cp ON cp."Protocol_Id" = "ChemoProtocol"."Id"`).
Where(`"ChemoProtocol"."Patient_Id" = ?`, patientId).
Preload("ChemoPlans", func(db *gorm.DB) *gorm.DB {
return db.
Where(`"Status" IS NULL OR "Status" = ?`, ere.SPCSchedule).
Order(`"Id" ASC`).
Limit(1)
}).
Order(`"CreatedAt" DESC`).
First(&data)
if err := tx.Error; err != nil {
return nil, err
}
pl.SetLogInfo(event, nil, "complete")
return &data, nil
}
func validateChemo(patientId uint, event *pl.Event) (*ecpl.ChemoPlan, error) {
// get chemo adm
chemoAdm, err := getChemoAdm(patientId, event)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-not-found",
Detail: "patient doesn't have active chemo",
}
return nil, pl.SetLogError(event, patientId)
}
return nil, err
}
// validate is chemo verified
if chemoAdm.Status_Code != erc.DVCVerified {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-not-match",
Detail: fmt.Sprintf("chemo not yet verified"),
}
return nil, pl.SetLogError(event, chemoAdm)
}
// get chemo protocol
chemoProtocol, err := getChemoProtocol(patientId, event)
if err != nil {
return nil, err
}
if chemoProtocol.Status_Code != erc.DVCVerified {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-not-match",
Detail: fmt.Sprintf("protocol chemo not yet verified"),
}
return nil, pl.SetLogError(event, chemoProtocol)
}
if now.Before(*chemoProtocol.StartDate) || now.After(*chemoProtocol.EndDate) {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "invalid-date-range",
Detail: "chemo cannot be performed because the current date is outside the allowed treatment window.",
}
return nil, pl.SetLogError(event, chemoProtocol)
}
if chemoProtocol.ChemoPlans == nil || len(*chemoProtocol.ChemoPlans) == 0 {
return nil, nil
}
// Return the first chemo plan
return &(*chemoProtocol.ChemoPlans)[0], nil
}
func getChemoAdm(patientId uint, event *pl.Event) (*ec.Chemo, error) {
pl.SetLogInfo(event, nil, "started", "getChemoProtocol")
data := ec.Chemo{}
var tx = dg.I
tx = tx.Model(&ec.Chemo{}).
Joins(`LEFT JOIN "Encounter" e ON e."Id" = "Chemo"."Encounter_Id"`).
Where(`e."Patient_Id" = ? AND "Chemo"."Class_Code" = ?`, patientId, ere.CCCAdm).
Order(`"CreatedAt" DESC`).
First(&data)
if err := tx.Error; err != nil {
return nil, err
}
pl.SetLogInfo(event, nil, "complete")
return &data, nil
}
@@ -59,10 +59,11 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En
} else {
tx = dg.I
}
tx = tx.Model(&e.Encounter{})
if input.AuthInfo.Doctor_Code != nil {
tx.Where("\"Responsible_Doctor_Code\" = ?", *input.AuthInfo.Doctor_Code) //
tx = tx.Where("\"Responsible_Doctor_Code\" = ?", *input.AuthInfo.Doctor_Code) //
}
if input.StartDate != nil && input.EndDate != nil {
@@ -75,7 +76,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En
if input.Patient_Identifier != nil {
tx = tx.Joins("JOIN \"Patient\" ON \"Patient\".\"Id\" = \"Encounter\".\"Patient_Id\"").
Joins("JOIN \"Person\" ON \"Person\".\"Id\" = \"Patient\".\"Person_Id\"").Where("\"Person\".\"Name\" ILIKE ? OR \"Patient\".\"Number\" = ?", "%"+*input.Patient_Identifier+"%", *input.Patient_Identifier)
Joins("JOIN \"Person\" ON \"Person\".\"Id\" = \"Patient\".\"Person_Id\"").
Where("\"Person\".\"Name\" ILIKE ? OR \"Patient\".\"Number\" = ?", "%"+*input.Patient_Identifier+"%", *input.Patient_Identifier)
}
// TODO: getuk lib need to be updated to support this
@@ -83,20 +85,23 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En
tx = tx.Where("\"Encounter\".\"Status_Code\" = ?", *input.Status_Code)
}
// if input.Specialist_Code != nil {
// tx = tx.Where("\"Encounter\".\"Specialist_Code\" = ?", *input.Specialist_Code)
// }
if input.Specialist_Code != nil {
tx = tx.Where("\"Encounter\".\"Specialist_Code\" = ?", *input.Specialist_Code)
}
if input.PaymentMethod_Code != nil {
tx = tx.Where("\"Encounter\".\"PaymentMethod_Code\" = ?", *input.PaymentMethod_Code)
}
tx = tx.Debug().
Scopes(gh.Filter(input.FilterDto)).
Scopes(gh.Preload(input.Includes)).
Count(&count).
Scopes(gh.Paginate(input, &pagination)).
Order("\"CreatedAt\" DESC")
if input.ChemoClass != nil {
tx = tx.Joins(`RIGHT JOIN "Chemo" "c" ON "c"."Encounter_Id" = "Encounter"."Id"`).
Where(`"c"."Class_Code" = ?`, *input.ChemoClass)
}
// count
if err := tx.Count(&count).Error; err != nil {
return nil, nil, plh.HandleListError(input, event, err)
}
// tx.Debug().Scopes(gh.Preload(input.Includes)).
// Scopes(gh.Filter(input.FilterDto)).
@@ -104,7 +109,11 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En
// Scopes(gh.Paginate(input, &pagination)).
// Order("\"CreatedAt\" DESC")
if err := tx.Find(&data).Error; err != nil {
if err := tx.
Scopes(gh.Preload(input.Includes)).
Scopes(gh.Paginate(input, &pagination)).
Order("\"CreatedAt\" DESC").
Find(&data).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, &meta, nil
}
@@ -47,7 +47,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pr
tx = dg.I
}
tx = tx.Debug().
tx = tx.
Model(&e.PrescriptionItem{}).
Scopes(gh.Preload(input.Includes)).
Scopes(gh.Filter(input.FilterDto)).
+35 -9
View File
@@ -2,19 +2,20 @@ package soapi
import (
"errors"
erc "simrs-vx/internal/domain/references/common"
esync "simrs-vx/internal/domain/sync-entities/log"
pl "simrs-vx/pkg/logger"
pu "simrs-vx/pkg/use-case-helper"
"strconv"
e "simrs-vx/internal/domain/main-entities/soapi"
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"
erc "simrs-vx/internal/domain/references/common"
e "simrs-vx/internal/domain/main-entities/soapi"
esync "simrs-vx/internal/domain/sync-entities/log"
ucp "simrs-vx/internal/use-case/main-use-case/chemo-plan"
)
const source = "soapi"
@@ -41,13 +42,26 @@ func Create(input e.CreateDto) (*d.Data, error) {
return nil, pl.SetLogError(&event, input)
}
err := dg.I.Transaction(func(tx *gorm.DB) error {
chemoPlan, err := validateIfEncounterIsChemo(*input.Encounter_Id, "c", &event)
if err != nil {
return nil, err
}
err = dg.I.Transaction(func(tx *gorm.DB) error {
if resData, err := CreateData(input, &event, tx); err != nil {
return err
} else {
data = *resData
}
// update chemoPlan
if chemoPlan != nil {
chemoPlan.Encounter_Id = input.Encounter_Id
if err = ucp.UpdateData(chemoPlan, "c", &event, tx); err != nil {
return err
}
}
// get detail for sync
soapiData, err := ReadDetailData(e.ReadDetailDto{
Id: data.Id,
@@ -238,6 +252,18 @@ func Delete(input e.DeleteDto) (*d.Data, error) {
return err
}
// update chemoPlan
chemoPlan, err := validateIfEncounterIsChemo(*data.Encounter_Id, "d", &event)
if err != nil {
return err
}
if chemoPlan != nil {
if err = ucp.UpdateData(chemoPlan, "d", &event, tx); err != nil {
return err
}
}
mwRunner.setMwType(pu.MWTPre)
// Run pre-middleware
if err = mwRunner.ExecuteIfSyncOn(func() error {
@@ -5,6 +5,17 @@ Any functions that are used internally by the use-case
package soapi
import (
"errors"
pl "simrs-vx/pkg/logger"
dg "github.com/karincake/apem/db-gorm-pg"
"gorm.io/gorm"
ere "simrs-vx/internal/domain/references/encounter"
ecpl "simrs-vx/internal/domain/main-entities/chemo-plan"
ecp "simrs-vx/internal/domain/main-entities/chemo-protocol"
ee "simrs-vx/internal/domain/main-entities/encounter"
e "simrs-vx/internal/domain/main-entities/soapi"
)
@@ -39,3 +50,77 @@ func setBulkData(input []e.CreateDto, encounterId uint) []e.Soapi {
return data
}
func validateIfEncounterIsChemo(encounterId uint, method string, event *pl.Event) (*ecpl.ChemoPlan, error) {
// get encounter
enc, err := getEncounter(encounterId, event)
if err != nil {
return nil, err
}
// Encounter must be Ambulatory and NOT Rehab
a := enc.Ambulatory
if a == nil || a.Class_Code == ere.ACCRehab {
return nil, nil
}
// get chemo protocol
chemo, err := getChemo(*enc.Patient_Id, enc.Id, event)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, pl.SetLogError(event, nil)
}
if chemo.ChemoPlans == nil || len(*chemo.ChemoPlans) == 0 {
return nil, nil
}
// Return the first chemo plan
return &(*chemo.ChemoPlans)[0], nil
}
func getEncounter(encounterId uint, event *pl.Event) (*ee.Encounter, error) {
pl.SetLogInfo(event, nil, "started", "getEncounter")
data := ee.Encounter{}
var tx = dg.I
err := tx.Model(&ee.Encounter{}).
Joins(`LEFT JOIN "Ambulatory" a ON a."Encounter_Id" = "Encounter"."Id"`).
Where(`"Encounter"."Id" = ?`, encounterId).
Where(`"Encounter"."Class_Code" = ?`, ere.ECAmbulatory).
Preload("Ambulatory").
First(&data).Error
if err != nil {
return nil, err
}
pl.SetLogInfo(event, nil, "complete")
return &data, nil
}
func getChemo(patientId, encounterId uint, event *pl.Event) (*ecp.ChemoProtocol, error) {
pl.SetLogInfo(event, nil, "started", "getChemo")
data := ecp.ChemoProtocol{}
var tx = dg.I
tx = tx.Model(&ecp.ChemoProtocol{}).
Joins(`LEFT JOIN "ChemoPlan" cp ON cp."Protocol_Id" = "ChemoProtocol"."Id"`).
Where(`"ChemoProtocol"."Patient_Id" = ?`, patientId).
Preload("ChemoPlans", func(db *gorm.DB) *gorm.DB {
return db.
Where(`"Encounter_Id" = ?`, encounterId)
}).
First(&data)
if err := tx.Error; err != nil {
return nil, err
}
pl.SetLogInfo(event, nil, "complete")
return &data, nil
}
@@ -31,7 +31,7 @@ func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esi
tx = dg.IS["simrs"]
}
if err := tx.Debug().Create(&data).Error; err != nil {
if err := tx.Create(&data).Error; err != nil {
return nil, plh.HandleCreateError(input, event, err)
}