Merge branch 'dev' of https://github.com/dikstub-rssa/simrs-be into feat/sync-setting-vanili

This commit is contained in:
vanilia
2025-11-28 12:23:34 +07:00
48 changed files with 1418 additions and 419 deletions

No files matched your search

@@ -87,6 +87,9 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e
if input.Id != nil {
tx = tx.Where("\"Id\" = ?", input.Id)
}
if input.Code != nil {
tx = tx.Where("\"Code\" = ?", input.Code)
}
if err := tx.First(&data).Error; err != nil {
if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil {
return nil, processedErr
@@ -37,7 +37,7 @@ func Create(input e.CreateDto) (*d.Data, error) {
}
// validate encounter_id
_, err := ue.ReadDetail(ee.ReadDetailDto{Id: uint16(*input.Encounter_Id)})
_, err := ue.ReadDetail(ee.ReadDetailDto{Id: *input.Encounter_Id})
if err != nil {
return err
}
+219 -154
View File
@@ -19,19 +19,15 @@ import (
erg "simrs-vx/internal/domain/references/organization"
ev "simrs-vx/internal/domain/bpjs-entities/vclaim-reference"
eaeh "simrs-vx/internal/domain/main-entities/adm-employee-hist"
edc "simrs-vx/internal/domain/main-entities/death-cause"
e "simrs-vx/internal/domain/main-entities/encounter"
eir "simrs-vx/internal/domain/main-entities/internal-reference"
erdh "simrs-vx/internal/domain/main-entities/responsible-doctor-hist"
es "simrs-vx/internal/domain/main-entities/soapi"
esync "simrs-vx/internal/domain/sync-entities/log"
uv "simrs-vx/internal/use-case/bpjs-use-case/vclaim-reference"
uaeh "simrs-vx/internal/use-case/main-use-case/adm-employee-hist"
udc "simrs-vx/internal/use-case/main-use-case/death-cause"
uir "simrs-vx/internal/use-case/main-use-case/internal-reference"
urdh "simrs-vx/internal/use-case/main-use-case/responsible-doctor-hist"
us "simrs-vx/internal/use-case/main-use-case/soapi"
)
@@ -118,7 +114,6 @@ func Create(input e.CreateDto) (*d.Data, error) {
// insert vclaimReference
if vr := input.VclaimReference; vr != nil {
t, _ := time.Parse("2006-01-02", vr.TglRujukan)
_, err = uv.CreateData(ev.CreateDto{
Encounter_Id: &data.Id,
Date: &t,
@@ -127,17 +122,11 @@ func Create(input e.CreateDto) (*d.Data, error) {
Number: &vr.NoSep}, &event, tx)
}
// insert adm_employee_hist (employee with role reg for create)
if _, err = uaeh.CreateData(eaeh.CreateDto{
Encounter_Id: &data.Id,
Employee_Id: data.Adm_Employee_Id,
StartedAt: &now}, &event, tx); err != nil {
return err
}
dataEncounter, err := ReadDetailData(e.ReadDetailDto{
Id: uint16(data.Id),
Includes: "Adm_Employee.User,Patient.Person.Relatives,Patient.Person.VclaimMember,VclaimReference"},
Id: data.Id,
Includes: "Adm_Employee.User,Patient.Person.Relatives," +
"Patient.Person.VclaimMember,VclaimReference," +
"Patient.Person.Contacts,Patient.Person.Addresses"},
&event, tx)
if err != nil {
return err
@@ -311,7 +300,7 @@ func Update(input e.UpdateDto) (*d.Data, error) {
}
dataEncounter, err := ReadDetailData(e.ReadDetailDto{
Id: uint16(data.Id),
Id: data.Id,
Includes: "Adm_Employee.User,Patient.Person.Relatives,Patient.Person.VclaimMember"},
&event, tx)
if err != nil {
@@ -429,7 +418,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) {
}
func CheckOut(input e.DischargeDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Ambulatory,Rehab"}
rdDto := e.ReadDetailDto{Id: input.Id, Includes: "Ambulatory,Rehab,InternalReferences"}
var data *e.Encounter
var err error
@@ -441,7 +430,7 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) {
// Start log
pl.SetLogInfo(&event, input, "started", "checkOut")
roleAllowed := []string{string(erg.EPCNur), string(erg.EPCDoc)}
roleAllowed := []string{string(erg.EPCNur)}
err = validateAuth(input.AuthInfo, roleAllowed, "checkOut-encounter", &event)
if err != nil {
return nil, err
@@ -466,7 +455,7 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) {
}
if data.Ambulatory != nil && (data.Ambulatory.Class_Code == ere.ACCReg || data.Ambulatory.Class_Code == ere.ACCRehab) {
// validate if soapi exist
// Validate SOAPI completeness: abort checkout if any required SOAPI is missing.
if err = getSoapiByTypeCode(data, &event, "check-out"); err != nil {
return err
}
@@ -478,12 +467,13 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) {
}
}
} else {
// chemo TBC
// TODO: chemo TBC (to be confirm)
if err := checkSoapiByDocExists(data.Id, &event, tx); err != nil {
return err
}
}
// update encounter
if err := updateDischargeData(input, data, &event, tx); err != nil {
return err
}
@@ -498,16 +488,6 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) {
}
}
// update finishedAt in latest responsible_doctor_hist
if err = updateLatestResponsibleDoctorHist(e.CheckinDto{Id: input.Id, FinishedAt: &now}, &event, tx); err != nil {
return err
}
// update finishedAt in latest adm_employee_hist
if err = updateLatestAdmEmployeeHist(e.CheckinDto{Id: input.Id, FinishedAt: &now}, &event, tx); err != nil {
return err
}
// insert data death-cause
if *input.Discharge_Method_Code == ere.DMCDeath {
if _, err = udc.CreateData(edc.CreateDto{Encounter_Id: &input.Id, Value: input.DeathCause}, &event, tx); err != nil {
@@ -515,10 +495,23 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) {
}
}
dataEncounter, err := ReadDetailData(e.ReadDetailDto{
Id: uint16(data.Id),
Includes: "DeathCause"},
&event, tx)
// perform additional validation when discharge_method_code is "consul-poly" or "consul-executive"
if *data.Discharge_Method_Code == ere.DMCConsulPoly || *data.Discharge_Method_Code == ere.DMCConsulExecutive {
for _, v := range *data.InternalReferences {
if *v.Status_Code == erc.DACNew {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-state-mismatch",
Detail: "checkout is not allowed because the internal-reference status is 'new'",
Raw: errors.New("internal-referral status not done yet"),
}
return pl.SetLogError(&event, input)
}
}
}
// read the newest data encounter for sync
dataEncounter, err := ReadDetailData(e.ReadDetailDto{Id: data.Id, Includes: "DeathCause"}, &event, tx)
if err != nil {
return err
}
@@ -560,6 +553,14 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) {
// Start log
pl.SetLogInfo(&event, input, "started", "update")
// TODO: Only "supervisi pendaftaran" could cancel encounter
roleAllowed := []string{string(erg.EPCReg), string(erg.EPCNur), string(erg.EPCDoc)}
err = validateAuth(input.AuthInfo, roleAllowed, "update-status-encounter", &event)
if err != nil {
return nil, err
}
mwRunner := newMiddlewareRunner(&event)
err = dg.I.Transaction(func(tx *gorm.DB) error {
@@ -581,34 +582,6 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) {
if input.StatusCode == erc.DSCCancel {
// TODO: Prevent cancellation if the billing has been verified
// TODO: Only "supervisi pendaftaran" could cancel encounter
roleAllowedToCancel := []string{
string(erg.EPCReg),
string(erg.EPCNur),
string(erg.EPCDoc),
}
// check if user has employee position
if !input.AuthInfo.HasEmployeePosition() {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "auth-forbidden",
Detail: "user has no employee position",
Raw: errors.New("authentication failed"),
}
return pl.SetLogError(&event, input)
}
if input.AuthInfo.Employee_Position_Code != nil && !pu.Contains(roleAllowedToCancel, *input.AuthInfo.Employee_Position_Code) {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "auth-forbidden",
Detail: "user position is not allowed, only user with registration, nurse, or doctor position is allowed to cancel encounter",
Raw: errors.New("authentication failed"),
}
return pl.SetLogError(&event, input)
}
// Prevent cancellation if soapi exist
dataSoapi, _, err := us.ReadListData(es.ReadListDto{
FilterDto: es.FilterDto{Encounter_Id: &data.Id}}, &event, tx)
@@ -627,11 +600,13 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) {
}
}
if err := UpdateStatusData(input, data, &event, tx); err != nil {
if err := UpdateStatusData(input, &event, tx); err != nil {
return err
}
if input.StatusCode == erc.DSCCancel {
if input.StatusCode == erc.DSCProcess || input.StatusCode == erc.DSCCancel {
data.Status_Code = input.StatusCode
mwRunner.setMwType(pu.MWTPre)
// Run pre-middleware
if err := mwRunner.RunUpdateStatusMiddleware(updatestatusEncounter, data); err != nil {
@@ -642,10 +617,12 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) {
return nil
})
if err != nil {
if err = runLogMiddleware(err, input, mwRunner); err != nil {
return nil, err
}
pl.SetLogInfo(&event, nil, "complete")
return &d.Data{
Meta: d.IS{
"source": source,
@@ -658,7 +635,7 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) {
}
func CheckIn(input e.CheckinDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Rehab,Ambulatory"}
rdDto := e.ReadDetailDto{Id: input.Id, Includes: "Rehab,Ambulatory"}
var data *e.Encounter
var err error
@@ -675,10 +652,10 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) {
if err != nil {
return nil, err
}
input.Adm_Employee_Id = input.AuthInfo.Employee_Id
input.Responsible_Nurse_Code = input.AuthInfo.Nurse_Code
// validate foreign key
if err := validateForeignKey(input); err != nil {
if err := validateForeignKey(input, &event); err != nil {
return nil, err
}
@@ -705,7 +682,7 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) {
return pl.SetLogError(&event, input)
}
// validate if soapi exist
// prevent repeated check-in. If SOAPI already exists, block the check-in process.
if data.Ambulatory != nil && (data.Ambulatory.Class_Code == ere.ACCReg || data.Ambulatory.Class_Code == ere.ACCRehab) {
err = getSoapiByTypeCode(data, &event, "check-in")
if err != nil {
@@ -713,39 +690,13 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) {
}
}
// Upsert responsible_doctor_hist if responsible_doctor_code has changed
if data.Responsible_Doctor_Code == nil || *input.Responsible_Doctor_Code != *data.Responsible_Doctor_Code {
// upsert responsibleDoctorHist
if err = upsertResponsibleDoctorHist(erdh.CreateDto{
Encounter_Id: &data.Id,
Doctor_Code: input.Responsible_Doctor_Code,
StartedAt: input.StartedAt,
}, &event, tx); err != nil {
return err
}
}
// Upsert adm_employee_hist if adm_employee_id has changed
if *input.Adm_Employee_Id != *data.Adm_Employee_Id {
// upsert admEmployeeHist
if err = upsertAdmEmployeeHist(eaeh.CreateDto{
Encounter_Id: &data.Id,
Employee_Id: input.Adm_Employee_Id,
StartedAt: input.StartedAt,
}, &event, tx); err != nil {
return err
}
}
// update encounter data
if err := updateCheckInData(input, data, &event, tx); err != nil {
return err
}
dataEncounter, err := ReadDetailData(e.ReadDetailDto{
Id: uint16(data.Id),
Includes: "Adm_Employee.User"},
&event, tx)
// read the newest data encounter for sync
dataEncounter, err := ReadDetailData(e.ReadDetailDto{Id: data.Id, Includes: "Responsible_Nurse.Employee.User"}, &event, tx)
if err != nil {
return err
}
@@ -776,7 +727,7 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) {
}
func RequestSwitchUnit(input e.SwitchUnitDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Responsible_Doctor"}
rdDto := e.ReadDetailDto{Id: input.Id, Includes: "Responsible_Nurse.Employee.User,Responsible_Doctor.Employee"}
var data *e.Encounter
var err error
@@ -809,23 +760,33 @@ func RequestSwitchUnit(input e.SwitchUnitDto) (*d.Data, error) {
return nil, err
}
roleAllowed := []string{string(erg.EPCNur)}
err = validateAuth(input.AuthInfo, roleAllowed, "request-switch-poly", &event)
if err != nil {
return nil, err
}
input.Src_Nurse_Code = input.AuthInfo.Nurse_Code
mwRunner := newMiddlewareRunner(&event)
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
}
input.Src_Doctor_Code = data.Responsible_Doctor_Code
//if data.IsDone() {
// event.Status = "failed"
// event.ErrInfo = pl.ErrorInfo{
// Code: "data-state-mismatch",
// Detail: "encounter is done",
// Raw: errors.New("encounter is done"),
// }
// return pl.SetLogError(&event, input)
//}
if data.IsDone() {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-state-mismatch",
Detail: "encounter is done",
Raw: errors.New("encounter is done"),
}
return pl.SetLogError(&event, input)
}
// verify Soapi exist for current responsible doctor
// Poly-Switch-Requests can only be processed if the previous responsible doctor has completed their SOAPI.
dataSoapi, err := getSoapiByResponsibleDoctor(*data, &event)
if err != nil {
return err
@@ -839,21 +800,36 @@ func RequestSwitchUnit(input e.SwitchUnitDto) (*d.Data, error) {
return pl.SetLogError(&event, input)
}
// bulk internal references
if err := uir.CreateBulkData(*input.InternalReferences, input.Id, &event, tx); err != nil {
// update encounter discharge_method_code
if err = UpdateDischargeMethod(input, &event, tx); err != nil {
return err
}
// TODO: update status encounter, finishedAt
// bulk internal references
if err := uir.CreateBulkData(&input, &event, tx); err != nil {
return err
}
pl.SetLogInfo(&event, nil, "complete")
// read the newest data encounter for sync
dataEncounter, err := ReadDetailData(e.ReadDetailDto{Id: data.Id, Includes: "InternalReferences,Responsible_Nurse.Employee.User"}, &event, tx)
if err != nil {
return err
}
mwRunner.setMwType(pu.MWTPre)
// Run pre-middleware
if err := mwRunner.RunRequestSwitchUnitMiddleware(requestSwitchEncounter, dataEncounter); err != nil {
return err
}
return nil
})
if err != nil {
if err = runLogMiddleware(err, input, mwRunner); err != nil {
return nil, err
}
pl.SetLogInfo(&event, nil, "complete")
return &d.Data{
Meta: d.IS{
"source": source,
@@ -864,10 +840,12 @@ func RequestSwitchUnit(input e.SwitchUnitDto) (*d.Data, error) {
}, nil
}
func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Responsible_Doctor"}
var data *e.Encounter
var err error
func ApproveSwitchUnit(input e.ApproveCancelUnitDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: input.Id, Includes: "Responsible_Doctor.Employee"}
var (
data *e.Encounter
err error
)
event := pl.Event{
Feature: "ApproveSwitchUnit",
@@ -877,13 +855,31 @@ func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) {
// Start log
pl.SetLogInfo(&event, input, "started", "approveSwitchUnit")
roleAllowed := []string{string(erg.EPCNur)}
err = validateAuth(input.AuthInfo, roleAllowed, "request-switch-poly", &event)
if err != nil {
return nil, err
}
mwRunner := newMiddlewareRunner(&event)
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
}
// get internal reference
if data.IsDone() {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-state-mismatch",
Detail: "encounter is done",
Raw: errors.New("encounter is done"),
}
return pl.SetLogError(&event, input)
}
// get internalReference based on internalReferences_Id
irData, err := uir.ReadDetailData(eir.ReadDetailDto{
Id: input.InternalReferences_Id, Includes: "Doctor"}, &event, tx)
if err != nil {
@@ -900,17 +896,7 @@ func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) {
return pl.SetLogError(&event, input)
}
//if data.IsDone() {
// event.Status = "failed"
// event.ErrInfo = pl.ErrorInfo{
// Code: "data-state-mismatch",
// Detail: "encounter is done",
// Raw: errors.New("encounter is done"),
// }
// return pl.SetLogError(&event, input)
//}
// verify Soapi exist for current responsible doctor
// Approve-Switch-Requests can only be processed if the previous responsible doctor has completed their SOAPI.
dataSoapi, err := getSoapiByResponsibleDoctor(*data, &event)
if err != nil {
return err
@@ -924,51 +910,130 @@ func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) {
return pl.SetLogError(&event, input)
}
// Set doctor_code; nil indicates no change.
if input.Dst_Doctor_Code == nil {
input.Dst_Doctor_Code = irData.Doctor_Code
}
// update internal reference
if err = uir.UpdateData(eir.UpdateDto{
Id: input.InternalReferences_Id,
CreateDto: eir.CreateDto{
Encounter_Id: &input.Id,
Doctor_Code: irData.Doctor_Code,
Unit_Code: irData.Unit_Code,
Status_Code: erc.DACApproved,
}}, irData, &event, tx); err != nil {
Status_Code: erc.DACApproved,
Doctor_Code: input.Dst_Doctor_Code,
Nurse_Code: input.Nurse_Code}}, irData, &event, tx); err != nil {
return err
}
// update encounter
if err = updateEncounterApproveSwitchUnit(*irData, &event, tx); err != nil {
if err = updateEncounterApproveSwitchUnit(input, &event, tx); err != nil {
return err
}
// update latest responsible doctor hist
if err = updateLatestResponsibleDoctorHist(e.CheckinDto{Id: input.Id, FinishedAt: &now}, &event, tx); err != nil {
mwRunner.setMwType(pu.MWTPre)
// Run pre-middleware
if err := mwRunner.RunApproveSwitchUnitMiddleware(approveSwitchEncounter, &input); err != nil {
return err
}
// create responsible doctor based on internal reference data
if _, err = urdh.CreateData(erdh.CreateDto{
Encounter_Id: &input.Id,
Doctor_Code: irData.Doctor_Code,
StartedAt: &now,
}, &event, tx); err != nil {
return err
}
// update data response
data.Responsible_Doctor_Code = irData.Doctor_Code
data.Unit_Code = irData.Unit_Code
data.Specialist_Code = irData.Doctor.Specialist_Code
data.Subspecialist_Code = irData.Doctor.Subspecialist_Code
pl.SetLogInfo(&event, nil, "complete")
return nil
})
if err = runLogMiddleware(err, input, mwRunner); err != nil {
return nil, err
}
pl.SetLogInfo(&event, nil, "complete")
return &d.Data{
Meta: d.IS{
"source": source,
"structure": "single-data",
"status": "updated",
},
Data: data.ToResponse(),
}, nil
}
func CancelSwitchUnit(input e.ApproveCancelUnitDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: input.Id}
var (
data *e.Encounter
err error
)
event := pl.Event{
Feature: "CancelSwitchUnit",
Source: source,
}
// Start log
pl.SetLogInfo(&event, input, "started", "cancelSwitchUnit")
roleAllowed := []string{string(erg.EPCNur)}
err = validateAuth(input.AuthInfo, roleAllowed, "request-switch-poly", &event)
if err != nil {
return nil, err
}
mwRunner := newMiddlewareRunner(&event)
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.IsDone() {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-state-mismatch",
Detail: "encounter is done",
Raw: errors.New("encounter is done"),
}
return pl.SetLogError(&event, input)
}
// get internalReference based on internalReferences_Id
irData, err := uir.ReadDetailData(eir.ReadDetailDto{
Id: input.InternalReferences_Id}, &event, tx)
if err != nil {
return err
}
if *irData.Status_Code != erc.DACNew {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-state-mismatch",
Detail: "internal references is approve",
Raw: errors.New("internal references is approve"),
}
return pl.SetLogError(&event, input)
}
// update internal reference
if err = uir.UpdateData(eir.UpdateDto{
Id: input.InternalReferences_Id,
CreateDto: eir.CreateDto{
Status_Code: erc.DACCanceled,
Nurse_Code: input.Nurse_Code}}, irData, &event, tx); err != nil {
return err
}
mwRunner.setMwType(pu.MWTPre)
// Run pre-middleware
if err := mwRunner.RunCancelSwitchUnitMiddleware(cancelSwitchEncounter, &input); err != nil {
return err
}
return nil
})
if err = runLogMiddleware(err, input, mwRunner); err != nil {
return nil, err
}
pl.SetLogInfo(&event, nil, "complete")
return &d.Data{
Meta: d.IS{
"source": source,
@@ -7,6 +7,7 @@ package encounter
import (
"errors"
"fmt"
un "simrs-vx/internal/use-case/main-use-case/nurse"
"strings"
"time"
@@ -29,7 +30,6 @@ import (
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"
eem "simrs-vx/internal/domain/main-entities/employee"
e "simrs-vx/internal/domain/main-entities/encounter"
ei "simrs-vx/internal/domain/main-entities/inpatient"
emo "simrs-vx/internal/domain/main-entities/material-order"
@@ -38,6 +38,7 @@ import (
emei "simrs-vx/internal/domain/main-entities/medication-item"
emi "simrs-vx/internal/domain/main-entities/medicine-mix"
emmi "simrs-vx/internal/domain/main-entities/medicine-mix-item"
en "simrs-vx/internal/domain/main-entities/nurse"
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"
@@ -51,12 +52,12 @@ import (
uc "simrs-vx/internal/use-case/main-use-case/chemo"
ud "simrs-vx/internal/use-case/main-use-case/doctor"
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"
um "simrs-vx/internal/use-case/main-use-case/medication"
umei "simrs-vx/internal/use-case/main-use-case/medication-item"
umi "simrs-vx/internal/use-case/main-use-case/medicine-mix"
ummi "simrs-vx/internal/use-case/main-use-case/medicine-mix-item"
_ "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"
@@ -68,6 +69,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) {
var inputSrc *e.CreateDto
if inputT, ok := any(input).(*e.CreateDto); ok {
inputSrc = inputT
data.Status_Code = erc.DSCNew
} else {
inputTemp := any(input).(*e.UpdateDto)
inputSrc = &inputTemp.CreateDto
@@ -90,7 +92,6 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) {
data.Responsible_Doctor_Code = inputSrc.Responsible_Doctor_Code
data.RefSource_Name = inputSrc.RefSource_Name
data.Appointment_Id = inputSrc.Appointment_Id
data.Status_Code = erc.DSCProcess
data.RefType_Code = &inputSrc.RefTypeCode
data.NewStatus = inputSrc.NewStatus
}
@@ -117,17 +118,24 @@ func setDataDischarge(src e.DischargeDto, dst *e.Encounter) {
dst.FinishedAt = &now
}
func setDataUpdateStatus(src e.UpdateStatusDto, dst *e.Encounter) {
dst.Status_Code = src.StatusCode
}
func setDataCheckIn(src e.CheckinDto, dst *e.Encounter) {
if src.Adm_Employee_Id != nil {
dst.Adm_Employee_Id = src.Adm_Employee_Id
}
dst.Responsible_Nurse_Code = src.Responsible_Nurse_Code
dst.Responsible_Doctor_Code = src.Responsible_Doctor_Code
dst.StartedAt = src.StartedAt
dst.Status_Code = erc.DSCProcess
}
func setDischargeMethodCode(code ere.PolySwitchCode) *ere.DischargeMethodCode {
var dcm ere.DischargeMethodCode
switch code {
case ere.PSCConsulPoly:
dcm = ere.DMCConsulPoly
case ere.PSCConsulExecutive:
dcm = ere.DMCConsulExecutive
}
return &dcm
}
func checkSoapiByDocExists(encounter_id uint, event *pl.Event, tx *gorm.DB) error {
@@ -556,6 +564,7 @@ func getSoapiByResponsibleDoctor(enc e.Encounter, event *pl.Event) (data []es.So
Code: "no responsible-doctor found",
Detail: "Encounter does not have responsible-doctor",
}
return nil, pl.SetLogError(event, enc)
}
err = dg.I.
@@ -904,17 +913,17 @@ func updateRehabStatus(input er.UpdateDto, event *pl.Event, dbx ...*gorm.DB) err
return nil
}
func validateForeignKey(input e.CheckinDto) error {
func validateForeignKey(input e.CheckinDto, event *pl.Event) error {
// validate employee_Id
if input.Adm_Employee_Id != nil {
if _, err := uem.ReadDetail(eem.ReadDetailDto{Id: uint16(*input.Adm_Employee_Id)}); err != nil {
if input.Responsible_Nurse_Code != nil {
if _, err := un.ReadDetailData(en.ReadDetailDto{Code: input.Responsible_Nurse_Code}, event); err != nil {
return err
}
}
// validate doctor_Code
if input.Responsible_Doctor_Code != nil {
if _, err := ud.ReadDetail(ed.ReadDetailDto{Code: input.Responsible_Doctor_Code}); err != nil {
if _, err := ud.ReadDetailData(ed.ReadDetailDto{Code: input.Responsible_Doctor_Code}, event); err != nil {
return err
}
}
@@ -3,7 +3,6 @@ package encounter
import (
// std
"errors"
eir "simrs-vx/internal/domain/main-entities/internal-reference"
// external
dg "github.com/karincake/apem/db-gorm-pg"
gh "github.com/karincake/getuk"
@@ -205,9 +204,8 @@ func IsDone(encounter_id uint, event *pl.Event, dbx ...*gorm.DB) bool {
return data.IsDone()
}
func UpdateStatusData(input e.UpdateStatusDto, data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, data, "started", "DBUpdate")
setDataUpdateStatus(input, data)
func UpdateStatusData(input e.UpdateStatusDto, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, input, "started", "DBUpdateStatus")
var tx *gorm.DB
if len(dbx) > 0 {
@@ -216,22 +214,49 @@ func UpdateStatusData(input e.UpdateStatusDto, data *e.Encounter, event *pl.Even
tx = dg.I
}
if err := tx.Save(&data).Error; err != nil {
if err := tx.Model(&e.Encounter{}).
Where("\"Id\" = ?", input.Id).
Update("Status_Code", input.StatusCode).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-update-fail",
Detail: "Database update failed",
Code: "update-fail",
Detail: "Failed to update status code",
Raw: err,
}
return pl.SetLogError(event, input)
}
return nil
}
func UpdateDischargeMethod(input e.SwitchUnitDto, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, input, "started", "DBUpdateDischargeMethod")
dischargeCode := setDischargeMethodCode(*input.PolySwitchCode)
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
if err := tx.Model(&e.Encounter{}).
Where("\"Id\" = ?", input.Id).
Update("Discharge_Method_Code", dischargeCode).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "update-fail",
Detail: "Failed to update discharge method code",
Raw: err,
}
return pl.SetLogError(event, input)
}
pl.SetLogInfo(event, nil, "complete")
return nil
}
func updateCheckInData(input e.CheckinDto, data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, data, "started", "DBUpdate")
pl.SetLogInfo(event, data, "started", "DBUpdateCheckin")
setDataCheckIn(input, data)
var tx *gorm.DB
@@ -318,7 +343,7 @@ func verifyAllocatedVisitCount(i e.CreateDto, event *pl.Event) (e.Encounter, boo
return recentEncounterAdm, valid, nil
}
func updateEncounterApproveSwitchUnit(input eir.InternalReference, event *pl.Event, dbx ...*gorm.DB) (err error) {
func updateEncounterApproveSwitchUnit(input e.ApproveCancelUnitDto, event *pl.Event, dbx ...*gorm.DB) (err error) {
pl.SetLogInfo(event, nil, "started", "DBCreate")
var tx *gorm.DB
@@ -329,10 +354,10 @@ func updateEncounterApproveSwitchUnit(input eir.InternalReference, event *pl.Eve
}
if err := tx.Model(&e.Encounter{}).
Where("\"Id\" = ?", input.Encounter_Id).
Where("\"Id\" = ?", input.Id).
Updates(map[string]interface{}{
"Responsible_Doctor_Code": input.Doctor_Code,
"Unit_Code": input.Unit_Code,
"Responsible_Doctor_Code": input.Dst_Doctor_Code,
"Responsible_Nurse_Code": input.Nurse_Code,
}).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
@@ -27,7 +27,6 @@ func newMiddlewareRunner(event *pl.Event) *middlewareRunner {
}
}
// ExecuteCreateMiddleware executes create middleware
func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.Encounter) error {
if !me.SyncOn {
return nil
@@ -47,7 +46,6 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e
return nil
}
// ExecuteCreateMiddleware executes create middleware
func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error {
if !me.SyncOn {
return nil
@@ -199,6 +197,60 @@ func (me *middlewareRunner) RunUpdateStatusMiddleware(middlewares []updateStatus
return nil
}
func (me *middlewareRunner) RunRequestSwitchUnitMiddleware(middleware requestSwitchUnitMw, input *e.Encounter) error {
if !me.SyncOn {
return nil
}
logData := pu.GetLogData(input, nil)
pl.SetLogInfo(me.Event, logData, "started", middleware.Name)
if err := middleware.Func(input); 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) RunApproveSwitchUnitMiddleware(middleware approveSwitchUnitMw, input *e.ApproveCancelUnitDto) error {
if !me.SyncOn {
return nil
}
logData := pu.GetLogData(input, nil)
pl.SetLogInfo(me.Event, logData, "started", middleware.Name)
if err := middleware.Func(input); 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) RunCancelSwitchUnitMiddleware(middleware cancelSwitchUnitMw, input *e.ApproveCancelUnitDto) error {
if !me.SyncOn {
return nil
}
logData := pu.GetLogData(input, nil)
pl.SetLogInfo(me.Event, logData, "started", middleware.Name)
if err := middleware.Func(input); 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
}
@@ -21,5 +21,9 @@ func init() {
checkoutEncounter = checkoutMw{Name: "sync-checkout-encounter", Func: plugin.Checkout}
updatestatusEncounter = append(updatestatusEncounter,
updateStatusMw{Name: "sync-update-status-encounter", Func: plugin.Cancel})
updateStatusMw{Name: "sync-update-status-encounter", Func: plugin.UpdateStatus})
requestSwitchEncounter = requestSwitchUnitMw{Name: "sync-request-switch-unit-encounter", Func: plugin.RequestSwitchUnit}
approveSwitchEncounter = approveSwitchUnitMw{Name: "sync-approve-switch-unit-encounter", Func: plugin.ApproveSwitchUnit}
cancelSwitchEncounter = cancelSwitchUnitMw{Name: "sync-cancel-switch-unit-encounter", Func: plugin.CancelSwitchUnit}
}
@@ -59,6 +59,21 @@ type updateStatusMw struct {
Func func(input *e.Encounter) error
}
type requestSwitchUnitMw struct {
Name string
Func func(input *e.Encounter) error
}
type approveSwitchUnitMw struct {
Name string
Func func(input *e.ApproveCancelUnitDto) error
}
type cancelSwitchUnitMw struct {
Name string
Func func(input *e.ApproveCancelUnitDto) error
}
type UpdateMw = updateMw
type DeleteMw = deleteMw
@@ -76,3 +91,6 @@ var deletePostMw []readDetailMw
var checkinEncounterMw checkinMw
var checkoutEncounter checkoutMw
var updatestatusEncounter []updateStatusMw
var requestSwitchEncounter requestSwitchUnitMw
var approveSwitchEncounter approveSwitchUnitMw
var cancelSwitchEncounter cancelSwitchUnitMw
@@ -5,35 +5,41 @@ Any functions that are used internally by the use-case
package internal_reference
import (
e "simrs-vx/internal/domain/main-entities/encounter"
ir "simrs-vx/internal/domain/main-entities/internal-reference"
erc "simrs-vx/internal/domain/references/common"
)
func setData[T *ir.CreateDto | *ir.UpdateDto](input T, data *ir.InternalReference) {
var inputSrc *ir.CreateDto
if inputT, ok := any(input).(*ir.CreateDto); ok {
inputSrc = inputT
} else {
inputTemp := any(input).(*ir.UpdateDto)
inputSrc = &inputTemp.CreateDto
}
func setDataCreate(input *ir.CreateDto, data *ir.InternalReference) {
data.Encounter_Id = input.Encounter_Id
data.Unit_Code = input.Unit_Code
data.Encounter_Id = inputSrc.Encounter_Id
data.Unit_Code = inputSrc.Unit_Code
data.Doctor_Code = inputSrc.Doctor_Code
data.Status_Code = &inputSrc.Status_Code
data.Doctor_Code = input.Doctor_Code
data.SrcDoctor_Code = input.SrcDoctor_Code
data.Nurse_Code = input.Nurse_Code
data.SrcNurse_Code = input.SrcNurse_Code
data.Status_Code = &input.Status_Code
}
func setBulkData(input []ir.CreateDto, encounterId uint) []ir.InternalReference {
func setDataUpdate(input *ir.UpdateDto, data *ir.InternalReference) {
data.Doctor_Code = input.Doctor_Code
data.Nurse_Code = input.Nurse_Code
data.Status_Code = &input.Status_Code
}
func setBulkData(input *e.SwitchUnitDto) []ir.InternalReference {
var data []ir.InternalReference
for _, v := range input {
for _, v := range *input.InternalReferences {
statusCode := erc.DACNew
data = append(data, ir.InternalReference{
Encounter_Id: &encounterId,
Unit_Code: v.Unit_Code,
Doctor_Code: v.Doctor_Code,
Status_Code: &statusCode,
Encounter_Id: &input.Id,
Unit_Code: v.Unit_Code,
Doctor_Code: v.Doctor_Code,
Status_Code: &statusCode,
SrcDoctor_Code: input.Src_Doctor_Code,
SrcNurse_Code: input.Src_Nurse_Code,
})
}
@@ -2,6 +2,7 @@ package internal_reference
import (
"errors"
e "simrs-vx/internal/domain/main-entities/encounter"
eir "simrs-vx/internal/domain/main-entities/internal-reference"
plh "simrs-vx/pkg/lib-helper"
pl "simrs-vx/pkg/logger"
@@ -16,7 +17,7 @@ func CreateData(input eir.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*eir.Int
pl.SetLogInfo(event, nil, "started", "DBCreate")
data := eir.InternalReference{}
setData(&input, &data)
setDataCreate(&input, &data)
var tx *gorm.DB
if len(dbx) > 0 {
@@ -97,7 +98,7 @@ func ReadDetailData(input eir.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (
func UpdateData(input eir.UpdateDto, data *eir.InternalReference, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, data, "started", "DBUpdate")
setData(&input, data)
setDataUpdate(&input, data)
var tx *gorm.DB
if len(dbx) > 0 {
@@ -143,10 +144,10 @@ func DeleteData(data *eir.InternalReference, event *pl.Event, dbx ...*gorm.DB) e
return nil
}
func CreateBulkData(input []eir.CreateDto, encounterId uint, event *pl.Event, dbx ...*gorm.DB) error {
func CreateBulkData(input *e.SwitchUnitDto, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, nil, "started", "DBCreate")
data := setBulkData(input, encounterId)
data := setBulkData(input)
var tx *gorm.DB
if len(dbx) > 0 {
@@ -359,7 +359,7 @@ func Verify(input e.VerifyDto) (*d.Data, error) {
func validateForeignKey(input e.CreateDto) error {
// validate encounter
if input.Encounter_Id != nil {
if _, err := ue.ReadDetail(ee.ReadDetailDto{Id: uint16(*input.Encounter_Id)}); err != nil {
if _, err := ue.ReadDetail(ee.ReadDetailDto{Id: *input.Encounter_Id}); err != nil {
return err
}
}
+15 -1
View File
@@ -1,6 +1,7 @@
package unit
import (
"errors"
e "simrs-vx/internal/domain/main-entities/unit"
erc "simrs-vx/internal/domain/references/common"
esync "simrs-vx/internal/domain/sync-entities/log"
@@ -27,9 +28,22 @@ func Create(input e.CreateDto) (*d.Data, error) {
// Start log
pl.SetLogInfo(&event, input, "started", "create")
// validate unit_code
_, err := strconv.Atoi(input.Code)
if err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "invalid_code_format",
Detail: "unit_code must be a valid integer",
Raw: errors.New("invalid unit_code format"),
}
return nil, pl.SetLogError(&event, input)
}
mwRunner := newMiddlewareRunner(&event)
err := dg.I.Transaction(func(tx *gorm.DB) error {
err = dg.I.Transaction(func(tx *gorm.DB) error {
if resData, err := CreateData(input, &event, tx); err != nil {
return err
} else {