feat (orders): add guard if parents are done, cant create child

This commit is contained in:
dpurbosakti
2025-09-22 13:00:23 +07:00
parent 6304d8f02a
commit 37da1ee418
18 changed files with 365 additions and 3 deletions
@@ -17,3 +17,7 @@ type McuOrderSubItem struct {
Result *string `json:"result"`
Status_Code erc.DataStatusCode `json:"status_code"`
}
func (d McuOrderSubItem) IsCompleted() bool {
return d.Status_Code == erc.DSCDone
}
@@ -120,7 +120,6 @@ func SetRoutes() http.Handler {
hc.RegCrud(r, "/v1/prescription-item", prescriptionitem.O)
hc.RegCrud(r, "/v1/device-order-item", deviceorderitem.O)
hc.RegCrud(r, "/v1/material-order-item", materialorderitem.O)
hc.RegCrud(r, "/v1/mcu-order-sub-item", mcuordersubitem.O)
hk.GroupRoutes("/v1/mcu-order", r, hk.MapHandlerFunc{
"GET /": mcuorder.O.GetList,
"GET /{id}": mcuorder.O.GetDetail,
@@ -136,8 +135,17 @@ func SetRoutes() http.Handler {
"POST /": mcuorderitem.O.Create,
"PATCH /{id}": mcuorderitem.O.Update,
"DELETE /{id}": mcuorderitem.O.Delete,
"PATCH /{id}/complete": mcuorderitem.O.Complete,
"PATCH /{id}/set-schedule": mcuorderitem.O.SetSchedule,
})
hk.GroupRoutes("/v1/mcu-order-sub-item", r, hk.MapHandlerFunc{
"GET /": mcuordersubitem.O.GetList,
"GET /{id}": mcuordersubitem.O.GetDetail,
"POST /": mcuordersubitem.O.Create,
"PATCH /{id}": mcuordersubitem.O.Update,
"DELETE /{id}": mcuordersubitem.O.Delete,
"PATCH /{id}/complete": mcuordersubitem.O.Complete,
})
hk.GroupRoutes("/v1/encounter", r, hk.MapHandlerFunc{
"GET /": encounter.O.GetList,
"GET /{id}": encounter.O.GetDetail,
@@ -70,6 +70,18 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) {
rw.DataResponse(w, res, err)
}
func (obj myBase) Complete(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.Complete(dto)
rw.DataResponse(w, res, err)
}
func (obj myBase) SetSchedule(w http.ResponseWriter, r *http.Request) {
id := rw.ValidateInt(w, "id", r.PathValue("id"))
if id <= 0 {
@@ -69,3 +69,15 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) {
res, err := u.Delete(dto)
rw.DataResponse(w, res, err)
}
func (obj myBase) Complete(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.Complete(dto)
rw.DataResponse(w, res, err)
}
@@ -6,6 +6,8 @@ import (
e "simrs-vx/internal/domain/main-entities/device-order"
ue "simrs-vx/internal/use-case/main-use-case/encounter"
erc "simrs-vx/internal/domain/references/common"
dg "github.com/karincake/apem/db-gorm-pg"
@@ -38,6 +40,11 @@ func Create(input e.CreateDto) (*d.Data, error) {
return err
}
// check if encounter is done
if ue.IsDone(*input.Encounter_Id, &event, tx) {
return errors.New("encounter is already done")
}
if resData, err := CreateData(input, &event, tx); err != nil {
return err
} else {
@@ -380,7 +380,9 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) {
}
if err := createMedication(data.Id, &event, tx); err != nil {
return err
if !pu.IsDataNotFoundError(err) {
return err
}
}
pl.SetLogInfo(&event, nil, "complete")
@@ -178,3 +178,27 @@ func UpdateDischargeData(input e.DischargeDto, data *e.Encounter, event *pl.Even
pl.SetLogInfo(event, nil, "complete")
return nil
}
func IsDone(encounter_id uint, event *pl.Event, dbx ...*gorm.DB) bool {
pl.SetLogInfo(event, nil, "started", "DBIsDone")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
var data e.Encounter
if err := tx.Where("\"Id\" = ?", encounter_id).First(&data).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-get-fail",
Detail: "Database get failed",
Raw: err,
}
return false
}
pl.SetLogInfo(event, nil, "complete")
return data.IsDone()
}
@@ -1,10 +1,13 @@
package materialorderitem
import (
"errors"
"strconv"
e "simrs-vx/internal/domain/main-entities/material-order-item"
umo "simrs-vx/internal/use-case/main-use-case/material-order"
dg "github.com/karincake/apem/db-gorm-pg"
d "github.com/karincake/dodol"
@@ -35,6 +38,11 @@ func Create(input e.CreateDto) (*d.Data, error) {
return err
}
// check if materialOrder is done
if umo.IsCompleted(*input.MaterialOrder_Id, &event, tx) {
return errors.New("materialOrder is already done")
}
if resData, err := CreateData(input, &event, tx); err != nil {
return err
} else {
@@ -6,6 +6,8 @@ import (
e "simrs-vx/internal/domain/main-entities/material-order"
ue "simrs-vx/internal/use-case/main-use-case/encounter"
erc "simrs-vx/internal/domain/references/common"
dg "github.com/karincake/apem/db-gorm-pg"
@@ -38,6 +40,11 @@ func Create(input e.CreateDto) (*d.Data, error) {
return err
}
// check if encounter is done
if ue.IsDone(*input.Encounter_Id, &event, tx) {
return errors.New("encounter is already done")
}
if resData, err := CreateData(input, &event, tx); err != nil {
return err
} else {
@@ -153,3 +153,27 @@ func DeleteData(data *e.MaterialOrder, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, nil, "complete")
return nil
}
func IsCompleted(materialOrder_id uint, event *pl.Event, dbx ...*gorm.DB) bool {
pl.SetLogInfo(event, nil, "started", "DBIsCompleted")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
var data e.MaterialOrder
if err := tx.Where("\"Id\" = ?", materialOrder_id).First(&data).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-get-fail",
Detail: "Database get failed",
Raw: err,
}
return false
}
pl.SetLogInfo(event, nil, "complete")
return data.IsCompleted()
}
@@ -6,6 +6,10 @@ import (
e "simrs-vx/internal/domain/main-entities/mcu-order-item"
umo "simrs-vx/internal/use-case/main-use-case/mcu-order"
erc "simrs-vx/internal/domain/references/common"
dg "github.com/karincake/apem/db-gorm-pg"
d "github.com/karincake/dodol"
@@ -36,6 +40,11 @@ func Create(input e.CreateDto) (*d.Data, error) {
return err
}
// check if mcuOrder is done
if umo.IsCompleted(*input.McuOrder_Id, &event, tx) {
return errors.New("mcuOrder is already done")
}
if resData, err := CreateData(input, &event, tx); err != nil {
return err
} else {
@@ -279,6 +288,63 @@ func Delete(input e.DeleteDto) (*d.Data, error) {
}
func Complete(input e.ReadDetailDto) (*d.Data, error) {
var data *e.McuOrderItem
var err error
event := pl.Event{
Feature: "Complete",
Source: source,
}
// Start log
pl.SetLogInfo(&event, input, "started", "complete")
err = dg.I.Transaction(func(tx *gorm.DB) error {
data, err = ReadDetailData(input, &event, tx)
if err != nil {
return err
}
if data.IsCompleted() {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-state-mismatch",
Detail: "mcuOrderItem is already completed",
Raw: errors.New("mcuOrderItem is already completed"),
}
return pl.SetLogError(&event, input)
}
data.Status_Code = erc.DSCDone
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
})
if err != nil {
return nil, err
}
return &d.Data{
Meta: d.IS{
"source": source,
"structure": "single-data",
"status": "fetched",
},
Data: data.ToResponse(),
}, nil
}
func SetSchedule(input e.SetScheduleDto) (*d.Data, error) {
rdDto := e.ReadDetailDto{Id: input.Id}
var data *e.McuOrderItem
@@ -153,3 +153,27 @@ func DeleteData(data *e.McuOrderItem, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, nil, "complete")
return nil
}
func IsCompleted(mcuOrderItem_id uint, event *pl.Event, dbx ...*gorm.DB) bool {
pl.SetLogInfo(event, nil, "started", "DBIsCompleted")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
var data e.McuOrderItem
if err := tx.Where("\"Id\" = ?", mcuOrderItem_id).First(&data).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-get-fail",
Detail: "Database get failed",
Raw: err,
}
return false
}
pl.SetLogInfo(event, nil, "complete")
return data.IsCompleted()
}
@@ -1,10 +1,15 @@
package mcuordersubitem
import (
"errors"
"strconv"
e "simrs-vx/internal/domain/main-entities/mcu-order-sub-item"
umoi "simrs-vx/internal/use-case/main-use-case/mcu-order-item"
erc "simrs-vx/internal/domain/references/common"
dg "github.com/karincake/apem/db-gorm-pg"
d "github.com/karincake/dodol"
@@ -35,6 +40,11 @@ func Create(input e.CreateDto) (*d.Data, error) {
return err
}
// check if mcuOrderItem is done
if umoi.IsCompleted(*input.McuOrderItem_Id, &event, tx) {
return errors.New("mcuOrderItem is already done")
}
if resData, err := CreateData(input, &event, tx); err != nil {
return err
} else {
@@ -277,3 +287,60 @@ func Delete(input e.DeleteDto) (*d.Data, error) {
}, nil
}
func Complete(input e.ReadDetailDto) (*d.Data, error) {
var data *e.McuOrderSubItem
var err error
event := pl.Event{
Feature: "Complete",
Source: source,
}
// Start log
pl.SetLogInfo(&event, input, "started", "complete")
err = dg.I.Transaction(func(tx *gorm.DB) error {
data, err = ReadDetailData(input, &event, tx)
if err != nil {
return err
}
if data.IsCompleted() {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-state-mismatch",
Detail: "mcuOrderSubItem is already completed",
Raw: errors.New("mcuOrderSubItem is already completed"),
}
return pl.SetLogError(&event, input)
}
data.Status_Code = erc.DSCDone
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
})
if err != nil {
return nil, err
}
return &d.Data{
Meta: d.IS{
"source": source,
"structure": "single-data",
"status": "fetched",
},
Data: data.ToResponse(),
}, nil
}
@@ -6,6 +6,8 @@ import (
e "simrs-vx/internal/domain/main-entities/mcu-order"
ue "simrs-vx/internal/use-case/main-use-case/encounter"
erc "simrs-vx/internal/domain/references/common"
dg "github.com/karincake/apem/db-gorm-pg"
@@ -38,6 +40,11 @@ func Create(input e.CreateDto) (*d.Data, error) {
return err
}
// check if encounter is done
if ue.IsDone(*input.Encounter_Id, &event, tx) {
return errors.New("encounter is already done")
}
if resData, err := CreateData(input, &event, tx); err != nil {
return err
} else {
@@ -153,3 +153,27 @@ func DeleteData(data *e.McuOrder, event *pl.Event, dbx ...*gorm.DB) error {
pl.SetLogInfo(event, nil, "complete")
return nil
}
func IsCompleted(mcuOrder_id uint, event *pl.Event, dbx ...*gorm.DB) bool {
pl.SetLogInfo(event, nil, "started", "DBIsCompleted")
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
var data e.McuOrder
if err := tx.Where("\"Id\" = ?", mcuOrder_id).First(&data).Error; err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-get-fail",
Detail: "Database get failed",
Raw: err,
}
return false
}
pl.SetLogInfo(event, nil, "complete")
return data.IsCompleted()
}
@@ -37,7 +37,7 @@ func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error {
itemCreate := ei.CreateDto{
Code: pu.AddPrefix("mcuSub-", input.Code),
Name: input.Name,
ItemGroup_Code: ero.ITGCMCU,
ItemGroup_Code: ero.ITGCMCUSub,
// Uom_Code: &input.Uom_Code,
// Infra_Id: input.Infra_Id,
}
@@ -277,3 +277,62 @@ func Delete(input e.DeleteDto) (*d.Data, error) {
}, nil
}
// func Approve(input e.ReadDetailDto) (*d.Data, error) {
// var data *e.Prescription
// var err error
// event := pl.Event{
// Feature: "Approve",
// Source: source,
// }
// // Start log
// pl.SetLogInfo(&event, input, "started", "approve")
// err = dg.I.Transaction(func(tx *gorm.DB) error {
// data, err = ReadDetailData(input, &event, tx)
// if err != nil {
// return err
// }
// if data.IsApproved() {
// event.Status = "failed"
// event.ErrInfo = pl.ErrorInfo{
// Code: "data-state-mismatch",
// Detail: "prescription is already approved",
// Raw: errors.New("prescription is already approved"),
// }
// return pl.SetLogError(&event, input)
// }
// data.Status_Code = erc.DSCApproved
// 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
// })
// if err != nil {
// return nil, err
// }
// return &d.Data{
// Meta: d.IS{
// "source": source,
// "structure": "single-data",
// "status": "approved",
// },
// Data: data.ToResponse(),
// }, nil
// }
+7
View File
@@ -103,6 +103,13 @@ func HandleMiddlewareError(event *pl.Event, mwType, mwName string, logData inter
return pl.SetLogError(event, logData)
}
func IsDataNotFoundError(err error) bool {
if err == nil {
return false
}
return strings.Contains(err.Error(), "code: data-notFound")
}
func AddPrefix(prefix string, str string) string {
return prefix + str
}