From 9e4357780b25257f32558400f6fed15cb07f4ea9 Mon Sep 17 00:00:00 2001 From: vanilia Date: Fri, 14 Nov 2025 09:52:50 +0700 Subject: [PATCH] add sync installation --- .../installation/handler.go | 50 +-- .../main-use-case/installation/case.go | 126 +++---- .../installation/middleware-runner.go | 19 +- .../main-use-case/installation/middleware.go | 6 + .../main-use-case/installation/tycovar.go | 22 +- .../simgos-sync-plugin/installation/plugin.go | 150 +++++--- .../simgos-sync-use-case/installation/case.go | 324 +++++++----------- .../simgos-sync-use-case/installation/lib.go | 186 +++++----- 8 files changed, 442 insertions(+), 441 deletions(-) diff --git a/internal/interface/simgos-sync-handler/installation/handler.go b/internal/interface/simgos-sync-handler/installation/handler.go index 6f9a708d..36424e71 100644 --- a/internal/interface/simgos-sync-handler/installation/handler.go +++ b/internal/interface/simgos-sync-handler/installation/handler.go @@ -2,6 +2,7 @@ package installation import ( "net/http" + "strconv" rw "github.com/karincake/risoles" // ua "github.com/karincake/tumpeng/auth/svc" @@ -34,28 +35,35 @@ func (obj myBase) CreateLog(w http.ResponseWriter, r *http.Request) { } func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { - //code := rw.ValidateString(w, "code", r.PathValue("code")) - //if code == "" { - // return - //} - // - //dto := e.UpdateDto{} - //if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { - // return - //} - //dto.Code = &code - //res, err := u.Update(dto) - //rw.DataResponse(w, res, err) + id := rw.ValidateString(w, "id", r.PathValue("id")) + if id == "" { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + val, _ := strconv.ParseUint(id, 10, 16) + valUint := uint16(val) + dto.Id = &valUint + + res, err := u.Update(dto) + rw.DataResponse(w, res, err) } func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { - //code := rw.ValidateString(w, "code", r.PathValue("code")) - //if code == "" { - // return - //} - // - //dto := e.DeleteDto{} - //dto.Code = &code - //res, err := u.Delete(dto) - //rw.DataResponse(w, res, err) + id := rw.ValidateString(w, "id", r.PathValue("id")) + if id == "" { + return + } + + dto := e.DeleteDto{} + val, _ := strconv.ParseUint(id, 10, 16) + valUint := uint16(val) + dto.Id = &valUint + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) } diff --git a/internal/use-case/main-use-case/installation/case.go b/internal/use-case/main-use-case/installation/case.go index d0a409c0..b80b6ca5 100644 --- a/internal/use-case/main-use-case/installation/case.go +++ b/internal/use-case/main-use-case/installation/case.go @@ -13,7 +13,6 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/installation" - egos "simrs-vx/internal/domain/simgos-entities/installation" esync "simrs-vx/internal/domain/sync-entities/log" ) @@ -21,7 +20,6 @@ const source = "installation" func Create(input e.CreateDto) (*d.Data, error) { data := e.Installation{} - sgData := egos.MInstalasi{} event := pl.Event{ Feature: "Create", @@ -37,44 +35,24 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } else { data = *resData + id := uint(data.Id) + input.Id = &id } mwRunner.setMwType(pu.MWTPre) // Run pre-middleware - if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &sgData); err != nil { + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - var errMsg string - inputLog := esync.SimxLogDto{ - Payload: input, - Method: erc.CCCreate, - } - - if err != nil { - // Run log-middleware - errMsg = err.Error() - inputLog.ErrMessage = &errMsg - inputLog.IsSuccess = false - - // create log failed - if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { - return nil, err - } - + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } - // create log success - inputLog.IsSuccess = true - if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { - return nil, err - } + pl.SetLogInfo(&event, nil, "complete") return &d.Data{ Meta: d.II{ @@ -87,7 +65,6 @@ func Create(input e.CreateDto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Installation var dataList []e.Installation var metaList *e.MetaDto var err error @@ -101,23 +78,11 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event) - 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 }) @@ -152,23 +117,11 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event) - 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 }) @@ -198,6 +151,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -205,32 +159,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); 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, @@ -254,6 +202,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -261,30 +210,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id 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 { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); 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, @@ -295,3 +240,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/installation/middleware-runner.go b/internal/use-case/main-use-case/installation/middleware-runner.go index acfaaa47..5a8e2ad0 100644 --- a/internal/use-case/main-use-case/installation/middleware-runner.go +++ b/internal/use-case/main-use-case/installation/middleware-runner.go @@ -7,7 +7,6 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/installation" - egos "simrs-vx/internal/domain/simgos-entities/installation" esync "simrs-vx/internal/domain/sync-entities/log" ) @@ -25,13 +24,13 @@ func newMiddlewareRunner(event *pl.Event) *middlewareRunner { } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *egos.MInstalasi) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -86,13 +85,13 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Installation) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []UpdateMw, input *e.UpdateDto) error { for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -101,13 +100,13 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Installation) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []DeleteMw, input *e.DeleteDto) error { for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/installation/middleware.go b/internal/use-case/main-use-case/installation/middleware.go index 222ec563..dd4b0b42 100644 --- a/internal/use-case/main-use-case/installation/middleware.go +++ b/internal/use-case/main-use-case/installation/middleware.go @@ -13,4 +13,10 @@ func init() { createSimxLogMw = append(createSimxLogMw, createLogMw{Name: "create-log", Func: plugin.CreateLog}, ) + + updatePreMw = append(updatePreMw, + updateMw{Name: "update-installation", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "delete-installation", Func: plugin.Delete}) } diff --git a/internal/use-case/main-use-case/installation/tycovar.go b/internal/use-case/main-use-case/installation/tycovar.go index e704b3a1..262bba8c 100644 --- a/internal/use-case/main-use-case/installation/tycovar.go +++ b/internal/use-case/main-use-case/installation/tycovar.go @@ -9,8 +9,6 @@ functionality. The purpose of this is to make the code more maintainable. package installation import ( - egos "simrs-vx/internal/domain/simgos-entities/installation" - "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/installation" @@ -19,7 +17,7 @@ import ( type createMw struct { Name string - Func func(input *e.CreateDto, data *egos.MInstalasi, tx *gorm.DB) error + Func func(input *e.CreateDto) error } type createLogMw struct { @@ -27,6 +25,16 @@ type createLogMw struct { Func func(input *elog.SimxLogDto) error } +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error +} + type readListMw struct { Name string Func func(input *e.ReadListDto, data *e.Installation, tx *gorm.DB) error @@ -37,8 +45,8 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware @@ -47,7 +55,7 @@ var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw diff --git a/internal/use-case/simgos-sync-plugin/installation/plugin.go b/internal/use-case/simgos-sync-plugin/installation/plugin.go index b566302b..06c9bebe 100644 --- a/internal/use-case/simgos-sync-plugin/installation/plugin.go +++ b/internal/use-case/simgos-sync-plugin/installation/plugin.go @@ -7,54 +7,14 @@ import ( "io" "net/http" - "gorm.io/gorm" - sync "simrs-vx/internal/infra/sync-cfg" e "simrs-vx/internal/domain/main-entities/installation" - egos "simrs-vx/internal/domain/simgos-entities/installation" elog "simrs-vx/internal/domain/sync-entities/log" ) -func Create(input *e.CreateDto, data *egos.MInstalasi, tx *gorm.DB) error { - var endpoint = fmt.Sprintf("%s%s/v1/installation", sync.O.Host, sync.O.Prefix) - - jsonData, err := json.Marshal(input) - if err != nil { - return fmt.Errorf("failed to encode JSON: %w", err) - } - - req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) - if err != nil { - return err - } - - req.Header.Set("Content-Type", "application/json") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return fmt.Errorf(resp.Status) - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - - if err := json.Unmarshal(body, &data); err != nil { - return fmt.Errorf("failed to parse response JSON: %w", err) - } - - return nil -} - -func CreateLog(input *elog.SimxLogDto) error { - var endpoint = fmt.Sprintf("%s%s/v1/installation/log", sync.O.Host, sync.O.Prefix) +func Create(input *e.CreateDto) error { + endpoint := getPrefixEndpoint() jsonData, err := json.Marshal(input) if err != nil { @@ -85,3 +45,109 @@ func CreateLog(input *elog.SimxLogDto) error { return nil } + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf(resp.Status) + } + + _, err = io.ReadAll(resp.Body) + if err != nil { + return err + } + + return nil +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("PATCH", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf(resp.Status) + } + + _, err = io.ReadAll(resp.Body) + if err != nil { + return err + } + + return nil +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("DELETE", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf(resp.Status) + } + + _, err = io.ReadAll(resp.Body) + if err != nil { + return err + } + + return nil +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/installation", sync.O.Host, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-use-case/installation/case.go b/internal/use-case/simgos-sync-use-case/installation/case.go index f38cca14..6c3a79bd 100644 --- a/internal/use-case/simgos-sync-use-case/installation/case.go +++ b/internal/use-case/simgos-sync-use-case/installation/case.go @@ -1,14 +1,14 @@ package installation import ( + "errors" + esimgos "simrs-vx/internal/domain/simgos-entities/installation" esync "simrs-vx/internal/domain/sync-entities/log" - "strconv" dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" pl "simrs-vx/pkg/logger" - pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" @@ -18,6 +18,11 @@ import ( const source = "installation" func Create(input e.CreateDto) (*d.Data, error) { + var ( + txSync = dg.I.Begin() + txSimgos = dg.IS["simrs"].Begin() + ) + event := pl.Event{ Feature: "Create", Source: source, @@ -26,10 +31,6 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") - // Define trx - txSync := dg.I.Begin() - txSimgos := dg.IS["simrs"].Begin() - // STEP 1: Insert to simgos sgData, err := CreateSimgosData(input, &event, txSimgos) if err != nil { @@ -37,7 +38,7 @@ func Create(input e.CreateDto) (*d.Data, error) { } // STEP 2: Insert to Link - if err = CreateInstallationLinkData(*input.Id, sgData.No_Instalasi, &event, txSync); err != nil { + if err = CreateLinkData(*input.Id, sgData.No_Instalasi, &event, txSync); err != nil { txSimgos.Rollback() return nil, err } @@ -65,7 +66,6 @@ func Create(input e.CreateDto) (*d.Data, error) { "structure": "single-data", "status": "created", }, - Data: sgData, }, nil } @@ -80,7 +80,7 @@ func CreateSimxLog(input esync.SimxLogDto) (*d.Data, error) { err := dg.I.Transaction(func(tx *gorm.DB) error { // InsertSimxLog - if err := CreateSimxLogData(input, &event, tx); err != nil { + if err := CreateLogData(input, &event, tx); err != nil { return err } @@ -93,6 +93,8 @@ func CreateSimxLog(input esync.SimxLogDto) (*d.Data, error) { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -102,212 +104,152 @@ func CreateSimxLog(input esync.SimxLogDto) (*d.Data, error) { }, nil } -func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Installation - var dataList []e.Installation - var metaList *e.MetaDto - var err error +func Update(input e.UpdateDto) (*d.Data, error) { + var ( + txSync = dg.I.Begin() + txSimgos = dg.IS["simrs"].Begin() + sgData *esimgos.MInstalasi + err error + ) event := pl.Event{ - Feature: "ReadList", + Feature: "Update", Source: source, } // Start log - pl.SetLogInfo(&event, input, "started", "readList") + pl.SetLogInfo(&event, input, "started", "update") - 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 + // STEP 1: Get Installation Link + syncLink, errGetLink := ReadDetailLinkData(*input.Id, &event) + if errGetLink != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + } + + if errGetLink != nil && errors.Is(errGetLink, gorm.ErrRecordNotFound) { + // STEP 2.1: Insert to simgos + sgData, err = CreateSimgosData(input.CreateDto, &event, txSimgos) + if err != nil { + return nil, err } - if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { - return err + // STEP 2.2: Insert to Link + simxId := uint(*input.Id) + if err = CreateLinkData(simxId, sgData.No_Instalasi, &event, txSync); err != nil { + txSimgos.Rollback() + return nil, err } - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { - return err + } else { + // Step 3.1: Update Simgos + err = UpdateSimgosData(input, syncLink, &event, txSimgos) + if err != nil { + return nil, err } + } - return nil - }) - - if err != nil { + // STEP 4: Commit two trx + if err = txSimgos.Commit().Error; err != nil { + txSimgos.Rollback() + txSync.Rollback() 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.Installation - var err error - - event := pl.Event{ - Feature: "ReadDetail", - Source: source, + if errGetLink != nil { + if err = txSync.Commit().Error; err != nil { + // STEP 5.1: Rollback Partial + go func() { + _ = DeleteSimgosData(sgData, &event) + }() + return nil, err + } } - // 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 - } + pl.SetLogInfo(&event, nil, "complete") return &d.Data{ Meta: d.IS{ "source": source, "structure": "single-data", - "status": "fetched", + "status": "updated", }, - Data: data.ToResponse(), }, nil } -//func Update(input e.UpdateDto) (*d.Data, error) { -// rdDto := e.ReadDetailDto{Code: input.Code} -// var data *e.Installation -// var err error -// -// event := pl.Event{ -// Feature: "Update", -// Source: source, -// } -// -// // Start log -// pl.SetLogInfo(&event, input, "started", "update") -// -// err = dg.I.Transaction(func(tx *gorm.DB) error { -// pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") -// if data, err = ReadDetailData(rdDto, &event, tx); err != nil { -// return err -// } -// -// mwRunner := newMiddlewareRunner(&event, tx) -// mwRunner.setMwType(pu.MWTPre) -// // Run pre-middleware -// if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { -// return err -// } -// -// if err := UpdateData(input, data, &event, tx); err != nil { -// return err -// } -// -// pl.SetLogInfo(&event, nil, "complete") -// -// mwRunner.setMwType(pu.MWTPost) -// // Run post-middleware -// if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { -// return err -// } -// -// return nil -// }) -// -// if err != nil { -// return nil, err -// } -// -// return &d.Data{ -// Meta: d.IS{ -// "source": source, -// "structure": "single-data", -// "status": "updated", -// }, -// Data: data.ToResponse(), -// }, nil -// -//} +func Delete(input e.DeleteDto) (*d.Data, error) { + var ( + txSync = dg.I.Begin() + txSimgos = dg.IS["simrs"].Begin() + sgData *esimgos.MInstalasi + err error + ) -//func Delete(input e.DeleteDto) (*d.Data, error) { -// rdDto := e.ReadDetailDto{Code: input.Code} -// var data *e.Installation -// 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 -// -//} + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Installation Link + syncLink, errGetLink := ReadDetailLinkData(*input.Id, &event) + if errGetLink != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + } + + if errGetLink == nil { + // STEP 2: Get Simgos + sgData, err = ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + if err != nil { + return nil, err + } + + // STEP 3: Delete M_Instalation Simgos + err = DeleteSimgosData(sgData, &event, txSimgos) + if err != nil { + return nil, err + } + + // STEP 4: Delete Installation Link + err = DeleteLinkData(syncLink, &event, txSync) + if err != nil { + txSimgos.Rollback() + return nil, err + } + + // STEP 4: Commit two trx + if err = txSimgos.Commit().Error; err != nil { + txSimgos.Rollback() + txSync.Rollback() + return nil, err + } + + if err = txSync.Commit().Error; err != nil { + // STEP 5: Rollback Partial + go func() { + inputRollback := e.UpdateDto{ + CreateDto: e.CreateDto{ + Name: sgData.Nama_Instalasi, + }, + } + _ = UpdateSimgosData(inputRollback, syncLink, &event) + }() + return nil, err + } + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/installation/lib.go b/internal/use-case/simgos-sync-use-case/installation/lib.go index b260776e..3e7ca854 100644 --- a/internal/use-case/simgos-sync-use-case/installation/lib.go +++ b/internal/use-case/simgos-sync-use-case/installation/lib.go @@ -1,18 +1,17 @@ package installation import ( - esync "simrs-vx/internal/domain/sync-entities/log" + esynclog "simrs-vx/internal/domain/sync-entities/log" plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" - pu "simrs-vx/pkg/use-case-helper" "time" dg "github.com/karincake/apem/db-gorm-pg" - gh "github.com/karincake/getuk" "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/installation" esimgos "simrs-vx/internal/domain/simgos-entities/installation" + esync "simrs-vx/internal/domain/sync-entities/installation" ) var now = time.Now() @@ -37,26 +36,76 @@ func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esi return &data, nil } -func CreateSimxLogData(input esync.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { - pl.SetLogInfo(event, nil, "started", "DBCreate") - data := setDataSimxLog(&input) +func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MInstalasi, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := esimgos.MInstalasi{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"no_instalasi\" = ?", simgosId). + First(&data).Error; err != nil { + return nil, err + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.InstallationLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + data := setDataSimgos(&input) + data.No_Instalasi = dataSimgos.Simgos_Id var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] } else { - tx = dg.I + tx = dg.IS["simrs"] } - if err := tx.Create(&data).Error; err != nil { - return plh.HandleCreateError(input, event, err) + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) } pl.SetLogInfo(event, nil, "complete") return nil } -func CreateInstallationLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) error { +func DeleteSimgosData(data *esimgos.MInstalasi, 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.IS["simrs"] + } + + data.St_Aktif = 0 + + if err := tx.Save(&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 CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, nil, "started", "DBCreate") data := setDataSimxLink(simxId, simgosId) @@ -75,101 +124,31 @@ func CreateInstallationLinkData(simxId, simgosId uint, event *pl.Event, dbx ...* return nil } -func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Installation, *e.MetaDto, error) { - pl.SetLogInfo(event, input, "started", "DBReadList") - data := []e.Installation{} - pagination := gh.Pagination{} - count := int64(0) - meta := e.MetaDto{} +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.InstallationLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.InstallationLink{} - var tx *gorm.DB - if len(dbx) > 0 { - tx = dbx[0] - } else { - tx = dg.I - } - - tx = tx. - Model(&e.Installation{}). - Scopes(gh.Preload(input.Includes)). - Scopes(gh.Filter(input.FilterDto)). - Count(&count). - Scopes(gh.Paginate(input, &pagination)). - Scopes(gh.Sort(input.Sort)) - - if err := tx.Find(&data).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, &meta, nil - } - return nil, nil, plh.HandleListError(input, event, err) - } - - meta.Count = int(count) - meta.PageNumber = pagination.PageNumber - meta.PageSize = pagination.PageSize - - pl.SetLogInfo(event, nil, "complete") - return data, &meta, nil -} - -func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Installation, error) { - pl.SetLogInfo(event, input, "started", "DBReadDetail") - data := e.Installation{} - - var tx *gorm.DB - if len(dbx) > 0 { - tx = dbx[0] - } else { - tx = dg.I - } - - if input.Code != nil { - tx = tx.Where("\"Code\" = ?", *input.Code) - } - if input.Id != nil { - tx = tx.Where("\"Id\" = ?", *input.Id) - } + var tx = dg.I if err := tx. - Scopes(gh.Preload(input.Includes)). + Where("\"Simx_Id\" = ?", simxId). First(&data).Error; err != nil { - if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { - return nil, processedErr - } + return nil, err } pl.SetLogInfo(event, nil, "complete") return &data, nil } -//func UpdateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) error { -// pl.SetLogInfo(event, input, "started", "DBUpdate") -// setData(&input, data) -// -// var tx *gorm.DB -// if len(dbx) > 0 { -// tx = dbx[0] -// } else { -// tx = dg.I -// } -// -// if err := tx.Save(&data).Error; err != nil { -// event.Status = "failed" -// event.ErrInfo = pl.ErrorInfo{ -// Code: "data-update-fail", -// Detail: "Database update failed", -// Raw: err, -// } -// return pl.SetLogError(event, input) -// } -// -// pl.SetLogInfo(event, nil, "complete") -// return nil -//} - -func DeleteSimgosData(data *esimgos.MInstalasi, event *pl.Event) error { +func DeleteLinkData(data *esync.InstallationLink, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, data, "started", "DBDelete") - var tx = dg.IS["simrs"] + + 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" @@ -184,3 +163,22 @@ func DeleteSimgosData(data *esimgos.MInstalasi, event *pl.Event) error { pl.SetLogInfo(event, nil, "complete") return nil } + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&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 plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +}