/* DESCRIPTION: Any functions that are used internally by the use-case */ package encounter import ( "errors" "fmt" "strings" "time" "gorm.io/gorm" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" edo "simrs-vx/internal/domain/main-entities/device-order" ed "simrs-vx/internal/domain/main-entities/doctor" emo "simrs-vx/internal/domain/main-entities/material-order" emco "simrs-vx/internal/domain/main-entities/mcu-order" em "simrs-vx/internal/domain/main-entities/medication" 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" ep "simrs-vx/internal/domain/main-entities/prescription" epi "simrs-vx/internal/domain/main-entities/prescription-item" eu "simrs-vx/internal/domain/main-entities/unit" // udo "simrs-vx/internal/use-case/main-use-case/device-order" es "simrs-vx/internal/domain/main-entities/soapi" um "simrs-vx/internal/use-case/main-use-case/medication" umei "simrs-vx/internal/use-case/main-use-case/medication-item" umi "simrs-vx/internal/use-case/main-use-case/medicine-mix" ummi "simrs-vx/internal/use-case/main-use-case/medicine-mix-item" up "simrs-vx/internal/use-case/main-use-case/prescription" upi "simrs-vx/internal/use-case/main-use-case/prescription-item" e "simrs-vx/internal/domain/main-entities/encounter" erc "simrs-vx/internal/domain/references/common" erg "simrs-vx/internal/domain/references/organization" ) func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) { var inputSrc *e.CreateDto if inputT, ok := any(input).(*e.CreateDto); ok { inputSrc = inputT } else { inputTemp := any(input).(*e.UpdateDto) inputSrc = &inputTemp.CreateDto } data.Patient_Id = inputSrc.Patient_Id data.RegisteredAt = inputSrc.RegisteredAt data.Class_Code = inputSrc.Class_Code data.Unit_Id = inputSrc.Unit_Id data.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 data.Status_Code = erc.DSCProcess } func setDataUpdate(src e.UpdateDto, dst *e.Encounter) { dst.Appointment_Doctor_Id = src.Appointment_Doctor_Id dst.Responsible_Doctor_Id = src.Responsible_Doctor_Id dst.Unit_Id = src.Unit_Id dst.Specialist_Id = src.Specialist_Id dst.Subspecialist_Id = src.Subspecialist_Id dst.VisitDate = src.VisitDate } func setDataDischarge(src e.DischargeDto, dst *e.Encounter) { dst.Discharge_Method_Code = src.DischargeMethod_Code dst.EarlyEducation = src.EarlyEducation dst.MedicalDischargeEducation = src.MedicalDischargeEducation dst.AdmDischargeEducation = src.AdmDischargeEducation dst.DischargeReason = src.DischargeReason dst.Status_Code = erc.DSCDone now := time.Now() dst.Discharge_Date = &now } func checkSoapiByDocExists(encounter_id uint, event *pl.Event, tx *gorm.DB) error { pl.SetLogInfo(event, nil, "started", "checkSoapiByDocExists") var soapies []es.Soapi err := tx. Preload("Employee"). Preload("Employee.User"). Where("\"Encounter_Id\" = ?", encounter_id).Find(&soapies).Error if err != nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-get-fail", Detail: "get soapi failed", Raw: err, } return pl.SetLogError(event, nil) } if len(soapies) == 0 { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-notFound", Detail: "no soapi found for encounter", Raw: errors.New("soapi not found"), } return pl.SetLogError(event, nil) } for _, s := range soapies { if s.Employee != nil && *s.Employee.Position_Code == erg.EPCDoc { return nil } } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-update-fail", Detail: "no soapi written by a doctor found", Raw: errors.New("all soapi employees are not doctors"), } return pl.SetLogError(event, nil) } func createMedication(encounter_id uint, event *pl.Event, tx *gorm.DB) error { pl.SetLogInfo(event, nil, "started", "createMedication") prescription, err := up.ReadDetailData(ep.ReadDetailDto{Encounter_Id: &encounter_id}, event, tx) if err != nil { return err } prescriptionItem, _, err := upi.ReadListData(epi.ReadListDto{FilterDto: epi.FilterDto{Prescription_Id: &prescription.Id}}, event, tx) if err != nil { return err } if len(prescriptionItem) == 0 { return nil } medicationCreate := em.CreateDto{ Encounter_Id: &encounter_id, IssuedAt: pu.GetTimeNow(), Status_Code: erc.DSCNew, } medication, err := um.CreateData(medicationCreate, event, tx) if err != nil { return err } for _, prescriptionItem := range prescriptionItem { if prescriptionItem.IsMix { medMix_id, err := createMedicineMixAndItem(*prescriptionItem.MedicineMix, event, tx) if err != nil { return err } prescriptionItem.MedicineMix_Id = medMix_id } err := createMedicationItem(medication.Id, prescriptionItem, event, tx) if err != nil { return err } } return nil } func createMedicineMixAndItem(input emi.MedicineMix, event *pl.Event, tx *gorm.DB) (*uint, error) { pl.SetLogInfo(event, nil, "started", "createMedicineMix") medicineMixCreate := emi.CreateDto{ Name: input.Name, Uom_Code: input.Uom_Code, } medicineMix, err := umi.CreateData(medicineMixCreate, event, tx) if err != nil { return nil, err } // recreate medicineMixItem with new medicineMix_id to keep medMixItem remain the same for prescriptionItem that is created for _, medicineMixItem := range input.MixItems { medicineMixItemCreate := emmi.CreateDto{ MedicineMix_Id: &medicineMix.Id, Medicine_Id: medicineMixItem.Medicine_Id, Dose: medicineMixItem.Dose, } _, err := ummi.CreateData(medicineMixItemCreate, event, tx) if err != nil { return nil, err } } return &medicineMix.Id, nil } func createMedicationItem(medication_id uint, input epi.PrescriptionItem, event *pl.Event, tx *gorm.DB) error { pl.SetLogInfo(event, nil, "started", "createMedicationItem") medicationItemCreate := emei.CreateDto{ Medication_Id: &medication_id, IsMix: input.IsMix, Medicine_Id: input.Medicine_Id, MedicineMix_Id: input.MedicineMix_Id, Usage: input.Usage, Interval: input.Interval, IntervalUnit_Code: input.IntervalUnit_Code, Quantity: input.Quantity, } _, err := umei.CreateData(medicationItemCreate, event, tx) if err != nil { return err } return nil } func checkNewOrdersExist(encounter_id uint, event *pl.Event, tx *gorm.DB) error { pl.SetLogInfo(event, nil, "started", "CheckNewOrdersExist") var errs []string if err := getDeviceOrders(encounter_id, event, tx); err != nil { errs = append(errs, err.Error()) } if err := getMaterialOrders(encounter_id, event, tx); err != nil { errs = append(errs, err.Error()) } if err := getMcuOrders(encounter_id, event, tx); err != nil { errs = append(errs, err.Error()) } if len(errs) > 0 { return fmt.Errorf("encounter has open orders: %s", strings.Join(errs, "; ")) } return nil } func getDeviceOrders(encounter_id uint, event *pl.Event, tx *gorm.DB) error { pl.SetLogInfo(event, nil, "started", "getDeviceOrders") var orders []edo.DeviceOrder err := tx.Where("\"Encounter_Id\" = ? AND \"Status_Code\" = ?", encounter_id, erc.DSCNew).Find(&orders).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-get-fail", Detail: "get device order failed", Raw: err, } return pl.SetLogError(event, nil) } if len(orders) > 0 { return fmt.Errorf("encounter has %d device orders", len(orders)) } return nil } func getMaterialOrders(encounter_id uint, event *pl.Event, tx *gorm.DB) error { pl.SetLogInfo(event, nil, "started", "getMaterialOrders") var orders []emo.MaterialOrder err := tx.Where("\"Encounter_Id\" = ? AND \"Status_Code\" = ?", encounter_id, erc.DSCNew).Find(&orders).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-get-fail", Detail: "get material order failed", Raw: err, } return pl.SetLogError(event, nil) } if len(orders) > 0 { return fmt.Errorf("encounter has %d material orders", len(orders)) } return nil } func getMcuOrders(encounter_id uint, event *pl.Event, tx *gorm.DB) error { pl.SetLogInfo(event, nil, "started", "getMcuOrders") var orders []emco.McuOrder err := tx.Where("\"Encounter_Id\" = ? AND \"Status_Code\" = ?", encounter_id, erc.DSCNew).Find(&orders).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-get-fail", Detail: "get mcu order failed", Raw: err, } return pl.SetLogError(event, nil) } if len(orders) > 0 { return fmt.Errorf("encounter has %d mcu orders", len(orders)) } return nil } func setDataUpdateStatus(src e.UpdateStatusDto, dst *e.Encounter) { dst.Status_Code = src.StatusCode } func getUnits(unitIds []uint16, event *pl.Event, tx *gorm.DB) ([]eu.Unit, error) { pl.SetLogInfo(event, nil, "started", "getUnits") var units []eu.Unit err := tx.Where("\"Id\" IN ?", unitIds).Find(&units).Error if err != nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-get-fail", Detail: "get units", Raw: err, } return nil, pl.SetLogError(event, nil) } return units, nil } func getDoctors(doctorIds []uint, event *pl.Event, tx *gorm.DB) ([]ed.Doctor, error) { pl.SetLogInfo(event, nil, "started", "getDoctors") var doctors []ed.Doctor err := tx.Where("\"Id\" IN ?", doctorIds).Find(&doctors).Error if err != nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-get-fail", Detail: "get doctors", Raw: err, } return nil, pl.SetLogError(event, nil) } return doctors, nil }