From 0c5aa0becf90a4032a61176ccf460a297ed8bc85 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 18 Aug 2025 13:02:14 +0700 Subject: [PATCH 01/40] feat (user): use case done --- internal/domain/main-entities/user/dto.go | 6 +- .../_use-case-template/crud/tycovar.go | 4 +- internal/use-case/main-use-case/user/case.go | 166 +++++++++++++++++- .../use-case/main-use-case/user/helper.go | 9 +- internal/use-case/main-use-case/user/lib.go | 5 +- .../use-case/main-use-case/user/tycovar.go | 4 +- 6 files changed, 181 insertions(+), 13 deletions(-) diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index b1335f1d..e47c8aec 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -32,7 +32,7 @@ type Deletedto struct { } type MetaDto struct { - PageNumber int `json:"page_number"` - PageSize int `json:"page_size"` - Count int64 `json:"count"` + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` } diff --git a/internal/use-case/_use-case-template/crud/tycovar.go b/internal/use-case/_use-case-template/crud/tycovar.go index 0a5c27fd..a53e4298 100644 --- a/internal/use-case/_use-case-template/crud/tycovar.go +++ b/internal/use-case/_use-case-template/crud/tycovar.go @@ -26,7 +26,7 @@ var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var udpatePreMw []readDetailMw -var udpatePostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw var deletePreMw []readDetailMw var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index 779b344c..54cd1d55 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -3,6 +3,7 @@ package user import ( "fmt" e "simrs-vx/internal/domain/main-entities/user" + "strconv" dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" @@ -17,7 +18,7 @@ const source = "user" func Create(input e.CreateDto) (*d.Data, error) { data := e.User{} - setData(input, &data) + setCreate(input, &data) event := pl.Event{ Feature: "Create", @@ -104,3 +105,166 @@ func Create(input e.CreateDto) (*d.Data, error) { Data: data, }, nil } + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.User + var dataList []e.User + var metaList *e.MetaDto + var err error + err = dg.I.Transaction(func(tx *gorm.DB) error { + for i := range readListPreMw { + if err := readListPreMw[i](&input, data, tx); err != nil { + return nil + } + } + + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + return err + } + + for i := range readListPostMw { + if err := readListPostMw[i](&input, data, tx); err != nil { + return nil + } + } + + 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), + }, + Data: dataList, + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.User + var err error + err = dg.I.Transaction(func(tx *gorm.DB) error { + for i := range readDetailPreMw { + if err := readDetailPreMw[i](&input, data, tx); err != nil { + return nil + } + } + data, err := ReadDetailData(input, tx) + if err != nil { + return err + } + for i := range readDetailPostMw { + if err := readDetailPostMw[i](&input, data, tx); err != nil { + return nil + } + } + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data, + }, nil +} + +func Update(input e.Updatedto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.User + var err error + err = dg.I.Transaction(func(tx *gorm.DB) error { + data, err = ReadDetailData(rdDto, tx) + if err != nil { + return nil + } + + err = setUpdate(input, data) + if err != nil { + return err + } + for i := range updatePreMw { + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + return nil + } + } + if err := UpdateData(*data, tx); err != nil { + return nil + } + for i := range updatePostMw { + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + return nil + } + } + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data, + }, nil + +} + +func Delete(input e.Deletedto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.User + var err error + err = dg.I.Transaction(func(tx *gorm.DB) error { + data, err = ReadDetailData(rdDto, tx) + if err != nil { + return nil + } + for i := range deletePreMw { + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + return nil + } + } + if err := DeleteData(data, tx); err != nil { + return nil + } + for i := range deletePostMw { + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + return nil + } + } + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data, + }, nil + +} diff --git a/internal/use-case/main-use-case/user/helper.go b/internal/use-case/main-use-case/user/helper.go index e16c080c..adcf0925 100644 --- a/internal/use-case/main-use-case/user/helper.go +++ b/internal/use-case/main-use-case/user/helper.go @@ -10,7 +10,7 @@ import ( p "simrs-vx/pkg/password" ) -func setData(src e.CreateDto, dst *e.User) error { +func setCreate(src e.CreateDto, dst *e.User) error { pass, err := p.Hash(src.Password) if err != nil { return err @@ -22,3 +22,10 @@ func setData(src e.CreateDto, dst *e.User) error { return nil } + +func setUpdate(src e.Updatedto, dst *e.User) error { + dst.Name = src.CreateDto.Name + dst.Status_Code = src.CreateDto.Status_Code + + return nil +} diff --git a/internal/use-case/main-use-case/user/lib.go b/internal/use-case/main-use-case/user/lib.go index 27bbf221..344c3bf9 100644 --- a/internal/use-case/main-use-case/user/lib.go +++ b/internal/use-case/main-use-case/user/lib.go @@ -52,7 +52,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.User, *e.MetaDto, e return nil, nil, err } - meta.Count = count + meta.Count = int(count) meta.PageNumber = pagination.PageNumber meta.PageSize = pagination.PageSize return data, &meta, nil @@ -69,9 +69,6 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.User, error) { } if err := tx.First(&data, input.Id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } return nil, err } diff --git a/internal/use-case/main-use-case/user/tycovar.go b/internal/use-case/main-use-case/user/tycovar.go index 6169fba5..e8d564df 100644 --- a/internal/use-case/main-use-case/user/tycovar.go +++ b/internal/use-case/main-use-case/user/tycovar.go @@ -26,7 +26,7 @@ var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var udpatePreMw []readDetailMw -var udpatePostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw var deletePreMw []readDetailMw var deletePostMw []readDetailMw From f80cba1cf511815d61e1dbd2c27f157acaf12d56 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 19 Aug 2025 14:26:19 +0700 Subject: [PATCH 02/40] feat (user): adjust for auth, hide pass --- cmd/main-api/config.yml-example | 9 ++- cmd/migration/migrations/20250819053416.sql | 15 ++++ cmd/migration/migrations/atlas.sum | 2 + go.mod | 6 ++ go.sum | 10 +++ internal/domain/base-entities/core/entity.go | 6 +- internal/domain/main-entities/user/dto.go | 45 +++++++++++- internal/domain/main-entities/user/entity.go | 14 ++-- internal/domain/references/common/common.go | 6 +- .../interface/main-handler/main-handler.go | 13 +++- .../interface/main-handler/user/handler.go | 71 +++++++++++++++++++ .../main-use-case/authentication/helper.go | 21 ++++++ .../main-use-case/authentication/tycovar.go | 20 ++++++ internal/use-case/main-use-case/user/case.go | 22 +++--- .../use-case/main-use-case/user/helper.go | 6 +- internal/use-case/main-use-case/user/lib.go | 2 +- .../handler-crud-helper.go | 42 +++++++++++ pkg/handler-crud-helper/types.go | 11 +++ pkg/logger/logger.go | 13 ++++ .../handler-logger/handler-logger.go | 6 +- 20 files changed, 305 insertions(+), 35 deletions(-) create mode 100644 cmd/migration/migrations/20250819053416.sql create mode 100644 cmd/migration/migrations/atlas.sum create mode 100644 internal/interface/main-handler/user/handler.go create mode 100644 internal/use-case/main-use-case/authentication/helper.go create mode 100644 internal/use-case/main-use-case/authentication/tycovar.go create mode 100644 pkg/handler-crud-helper/handler-crud-helper.go create mode 100644 pkg/handler-crud-helper/types.go diff --git a/cmd/main-api/config.yml-example b/cmd/main-api/config.yml-example index dfe3cb7e..aaf986f0 100644 --- a/cmd/main-api/config.yml-example +++ b/cmd/main-api/config.yml-example @@ -47,7 +47,12 @@ corsCfg: allowedMethod: satuSehatCfg: - host: localhsot:8200 + host: localhost:8200 bpjsCfg: - host: localhsot:8200 + host: localhost:8200 + +corsCfg: + allowedOrigins: + - http://example.com + allowedMethod: \ No newline at end of file diff --git a/cmd/migration/migrations/20250819053416.sql b/cmd/migration/migrations/20250819053416.sql new file mode 100644 index 00000000..fa94170a --- /dev/null +++ b/cmd/migration/migrations/20250819053416.sql @@ -0,0 +1,15 @@ +-- Create "User" table +CREATE TABLE "public"."User" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Name" character varying(25) NOT NULL, + "Password" character varying(255) NOT NULL, + "Status_Code" character varying(10) NOT NULL, + "FailedLoginCount" smallint NULL, + "LoginAttemptCount" bigint NULL, + "LastSuccessLogin" timestamptz NULL, + "LastAllowdLogin" timestamptz NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum new file mode 100644 index 00000000..d8fcc6bb --- /dev/null +++ b/cmd/migration/migrations/atlas.sum @@ -0,0 +1,2 @@ +h1:TslQ6d3/z4H6DQJvWAGwP3IVSAr/qYOosLEmorZhYx0= +20250819053416.sql h1:kYIqQm8dEYH+feZEHrCekuEvwKl3h1W4zlIpPAWn3W8= diff --git a/go.mod b/go.mod index f80d3909..daf9b4ff 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,15 @@ toolchain go1.24.6 require ( ariga.io/atlas-provider-gorm v0.5.6 + github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/google/uuid v1.6.0 github.com/karincake/apem v0.0.16-h github.com/karincake/dodol v0.0.1 github.com/karincake/getuk v0.1.0 + github.com/karincake/hongkue v0.0.4 github.com/karincake/lepet v0.0.1 + github.com/karincake/risoles v0.0.3 + github.com/karincake/semprit v0.0.3 golang.org/x/crypto v0.41.0 gorm.io/driver/postgres v1.5.11 gorm.io/gorm v1.25.12 @@ -28,6 +33,7 @@ require ( github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/karincake/serabi v0.0.14 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-sqlite3 v1.14.28 // indirect diff --git a/go.sum b/go.sum index 36a81d0f..8982eb2b 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= @@ -73,8 +75,16 @@ github.com/karincake/dodol v0.0.1 h1:jUXmJh1r0Ei4fmHPZ6IUkoplW/V9d27L63JEl6zudL0 github.com/karincake/dodol v0.0.1/go.mod h1:2f1NcvkvY0J3GMUkwILNDYVvRUpz0W3lpPp/Ha/Ld24= github.com/karincake/getuk v0.1.0 h1:jcIsASrr0UDE528GN7Ua6n9UFyRgUypsWh8Or8wzCO0= github.com/karincake/getuk v0.1.0/go.mod h1:NVnvxSGAkQ/xuq99FzWACvY5efyKPLFla1cKB8czm7c= +github.com/karincake/hongkue v0.0.4 h1:oWthq6cDg5DvDm1Z3e7mCLOATQf+oAdtHxN9OPnCfA8= +github.com/karincake/hongkue v0.0.4/go.mod h1:YVi5Lyh3DE+GRHx2OSODOr7FwvLi8U4idvcPHO7yeag= github.com/karincake/lepet v0.0.1 h1:eq/cwn5BBg0jWZ1c/MmvhFIBma0zBpVs2LwkfDOncy4= github.com/karincake/lepet v0.0.1/go.mod h1:U84w7olXO3BPJw2Hu6MBonFmJmPKaFjtyAj1HTu3z1A= +github.com/karincake/risoles v0.0.3 h1:7VBShf2yC6NqD0PotQcb0i8Xe6mJeTRrHnE0qzKf7NU= +github.com/karincake/risoles v0.0.3/go.mod h1:u4YS+rPp92ODTbGC4RUx4DxKoThnmPjBl1CNdnmKD/c= +github.com/karincake/semprit v0.0.3 h1:znleGRu73xrHk6a70+jRQgVh9VF3TAhttQz6vfgNdyM= +github.com/karincake/semprit v0.0.3/go.mod h1:nLtNmWlHkxMKG0IMzqnnfkn1L/RVYGXVW3LchfYQMu8= +github.com/karincake/serabi v0.0.14 h1:yK3nBLRXdoUNSUDIfbZqIQxnZ6U6Ij5QEO8d5QzZzsw= +github.com/karincake/serabi v0.0.14/go.mod h1:GcnPBWb+UotDxvb/a2CKwourCEyVIL4P9+YxVmZ5zgk= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= diff --git a/internal/domain/base-entities/core/entity.go b/internal/domain/base-entities/core/entity.go index fc8ab1f9..dcd47c1b 100644 --- a/internal/domain/base-entities/core/entity.go +++ b/internal/domain/base-entities/core/entity.go @@ -7,9 +7,9 @@ import ( ) type Base struct { - CreatedAt time.Time `json:"createdAt" gorm:"type:timestamptz"` - UpdatedAt string `json:"updatedAt" gorm:"type:timestamptz"` - DeteledAt gorm.DeletedAt `json:"deletedAt,omitempty"` + CreatedAt time.Time `json:"createdAt" gorm:"column:CreatedAt;type:timestamptz"` + UpdatedAt time.Time `json:"updatedAt" gorm:"column:UpdatedAt;type:timestamptz"` + DeletedAt gorm.DeletedAt `json:"deletedAt,omitempty" gorm:"column:DeletedAt"` } type Main struct { diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index e47c8aec..ab2bd7d2 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -1,6 +1,10 @@ package user -import erc "simrs-vx/internal/domain/references/common" +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + "time" +) type CreateDto struct { Name string `json:"name"` @@ -22,12 +26,12 @@ type ReadDetailDto struct { Name string `json:"name"` } -type Updatedto struct { +type UpdateDto struct { Id uint `json:"id"` CreateDto } -type Deletedto struct { +type DeleteDto struct { Id uint `json:"id"` } @@ -36,3 +40,38 @@ type MetaDto struct { PageSize int `json:"page_size"` Count int `json:"count"` } + +type LoginDto struct { + Name string `json:"name" validate:"required"` + Password string `json:"password" validate:"required"` + Duration uint32 `json:"duration"` // in minutes +} + +type ResponseDto struct { + ecore.Main + Name string `json:"name"` + Status_Code erc.StatusCode `json:"status_code"` + FailedLoginCount uint8 `json:"failedLoginCount"` + LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"` + LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` +} + +func (u User) ToResponse() ResponseDto { + resp := ResponseDto{ + Name: u.Name, + Status_Code: u.Status_Code, + FailedLoginCount: u.FailedLoginCount, + LastSuccessLogin: u.LastSuccessLogin, + LastAllowdLogin: u.LastAllowdLogin, + } + resp.Main = u.Main + return resp +} + +func ToResponseList(users []User) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/user/entity.go b/internal/domain/main-entities/user/entity.go index 078c0577..f69e03ca 100644 --- a/internal/domain/main-entities/user/entity.go +++ b/internal/domain/main-entities/user/entity.go @@ -3,12 +3,16 @@ package user import ( ecore "simrs-vx/internal/domain/base-entities/core" erc "simrs-vx/internal/domain/references/common" + "time" ) type User struct { - ecore.Main // adjust this according to the needs - Name string `json:"name" gorm:"not null;size:25"` - Password string `json:"password" gorm:"not null;size:255"` - Status_Code erc.StatusCode `json:"status_code" gorm:"not null;size:10"` - FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` + ecore.Main // adjust this according to the needs + Name string `json:"name" gorm:"not null;size:25"` + Password string `json:"password" gorm:"not null;size:255"` + Status_Code erc.StatusCode `json:"status_code" gorm:"not null;size:10"` + FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` + LoginAttemptCount int `json:"-"` + LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"` + LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` } diff --git a/internal/domain/references/common/common.go b/internal/domain/references/common/common.go index 3382267a..a31d7644 100644 --- a/internal/domain/references/common/common.go +++ b/internal/domain/references/common/common.go @@ -35,6 +35,8 @@ const ( ) const ( - SCActive StatusCode = "active" - SCInactive StatusCode = "inactive" + SCNew StatusCode = "new" + SCActive StatusCode = "active" + SCBlocked StatusCode = "blocked" + SCSuspended StatusCode = "suspended" ) diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index ef390c43..f023d4b8 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -3,6 +3,10 @@ package handler import ( "net/http" + /******************** main / transaction ********************/ + auth "simrs-vx/internal/interface/main-handler/authentication" + user "simrs-vx/internal/interface/main-handler/user" + /******************** external ********************/ a "github.com/karincake/apem" @@ -11,6 +15,8 @@ import ( ssdb "simrs-vx/internal/infra/ss-db" /******************** pkg ********************/ + cmw "simrs-vx/pkg/cors-manager-mw" + hc "simrs-vx/pkg/handler-crud-helper" handlerlogger "simrs-vx/pkg/middleware/handler-logger" ///// Internal @@ -28,6 +34,11 @@ func SetRoutes() http.Handler { /******************** Main ********************/ r.HandleFunc("/", home.Home) + r.HandleFunc("POST /v1/authentication/login", auth.Login) + r.HandleFunc("POST /v1/authentication/logout", auth.Logout) + + hc.RegCrud(r, "/v1/user", user.O) + ///// - return handlerlogger.SetLog(r) + return cmw.SetCors(handlerlogger.SetLog(r)) } diff --git a/internal/interface/main-handler/user/handler.go b/internal/interface/main-handler/user/handler.go new file mode 100644 index 00000000..99ea784b --- /dev/null +++ b/internal/interface/main-handler/user/handler.go @@ -0,0 +1,71 @@ +package user + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/user" + u "simrs-vx/internal/use-case/main-use-case/user" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(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.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/main-use-case/authentication/helper.go b/internal/use-case/main-use-case/authentication/helper.go new file mode 100644 index 00000000..2a9a9c92 --- /dev/null +++ b/internal/use-case/main-use-case/authentication/helper.go @@ -0,0 +1,21 @@ +package authentication + +import ( + dg "github.com/karincake/apem/db-gorm-mysql" +) + +// just return the error code +func GetAndCheck(input, condition any) (eCode string) { + result := dg.I.Where(condition).Find(input) + if result.Error != nil { + return "fetch-fail" + } else if result.RowsAffected == 0 { + return "auth-login-incorrect" + } + + return "" +} + +func GetDocName(id uint) string { + return "authentication" +} diff --git a/internal/use-case/main-use-case/authentication/tycovar.go b/internal/use-case/main-use-case/authentication/tycovar.go new file mode 100644 index 00000000..d4d5b5ea --- /dev/null +++ b/internal/use-case/main-use-case/authentication/tycovar.go @@ -0,0 +1,20 @@ +package authentication + +type TokenType string + +const AccessToken = "Access" +const RefreshToken = "Refresh" + +type AuthInfo struct { + Uuid string + User_Id int + User_Name string + // User_Email string + // User_Ref_Id int + // User_Position_Code string +} + +type AuthCfg struct { + AtSecretKey string `yaml:"atSecretKey"` + RtSecretKey string `yaml:"rtSecretKey"` +} diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index 54cd1d55..bba503db 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -98,11 +98,11 @@ func Create(input e.CreateDto) (*d.Data, error) { return &d.Data{ Meta: d.II{ - "source": source, - "type": "list", - "status": "created", + "source": source, + "structure": "single-data", + "status": "created", }, - Data: data, + Data: data.ToResponse(), }, nil } @@ -145,7 +145,7 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { "page_size": strconv.Itoa(metaList.PageSize), "record_totalCount": strconv.Itoa(metaList.Count), }, - Data: dataList, + Data: e.ToResponseList(dataList), }, nil } @@ -158,7 +158,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { return nil } } - data, err := ReadDetailData(input, tx) + data, err = ReadDetailData(input, tx) if err != nil { return err } @@ -180,11 +180,11 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: data, + Data: data.ToResponse(), }, nil } -func Update(input e.Updatedto) (*d.Data, error) { +func Update(input e.UpdateDto) (*d.Data, error) { rdDto := e.ReadDetailDto{Id: input.Id} var data *e.User var err error @@ -224,12 +224,12 @@ func Update(input e.Updatedto) (*d.Data, error) { "structure": "single-data", "status": "updated", }, - Data: data, + Data: data.ToResponse(), }, nil } -func Delete(input e.Deletedto) (*d.Data, error) { +func Delete(input e.DeleteDto) (*d.Data, error) { rdDto := e.ReadDetailDto{Id: input.Id} var data *e.User var err error @@ -264,7 +264,7 @@ func Delete(input e.Deletedto) (*d.Data, error) { "structure": "single-data", "status": "deleted", }, - Data: data, + Data: data.ToResponse(), }, nil } diff --git a/internal/use-case/main-use-case/user/helper.go b/internal/use-case/main-use-case/user/helper.go index adcf0925..1d334fb7 100644 --- a/internal/use-case/main-use-case/user/helper.go +++ b/internal/use-case/main-use-case/user/helper.go @@ -23,9 +23,9 @@ func setCreate(src e.CreateDto, dst *e.User) error { return nil } -func setUpdate(src e.Updatedto, dst *e.User) error { - dst.Name = src.CreateDto.Name - dst.Status_Code = src.CreateDto.Status_Code +func setUpdate(src e.UpdateDto, dst *e.User) error { + dst.Name = src.Name + dst.Status_Code = src.Status_Code return nil } diff --git a/internal/use-case/main-use-case/user/lib.go b/internal/use-case/main-use-case/user/lib.go index 344c3bf9..30f6213d 100644 --- a/internal/use-case/main-use-case/user/lib.go +++ b/internal/use-case/main-use-case/user/lib.go @@ -45,7 +45,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.User, *e.MetaDto, e Scopes(gh.Paginate(input, &pagination)). Order("CreatedAt DESC") - if err := tx.Find(&data).Error; err != nil { + if err := tx.Debug().Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, &meta, nil } diff --git a/pkg/handler-crud-helper/handler-crud-helper.go b/pkg/handler-crud-helper/handler-crud-helper.go new file mode 100644 index 00000000..d7da62f4 --- /dev/null +++ b/pkg/handler-crud-helper/handler-crud-helper.go @@ -0,0 +1,42 @@ +package handlercrudhelper + +import ( + "net/http" + "reflect" + + hk "github.com/karincake/hongkue" +) + +func RegCrud(r *http.ServeMux, path string, mwAndRouter ...any) { + sLength := len(mwAndRouter) + + mwCandidates := mwAndRouter[:sLength-1] + mwList := []hk.HandlerMw{} + for i := range mwCandidates { + // have to do it manually, since casting directly results unexpected result + myType := reflect.TypeOf(mwCandidates[i]) + if myType.String() != "func(http.Handler) http.Handler" { + panic("non middleware included as middleware") + } + mwList = append(mwList, mwCandidates[i].(func(http.Handler) http.Handler)) + + // if g, okHandler := mwCandidates[i].(func(http.Handler) http.Handler); !okHandler { + // panic("non middleware included") + // } else { + // mwList = append(mwList, g) + // } + } + + c, ok := mwAndRouter[sLength-1].(CrudBase) + if !ok { + panic("non CrudBase used in the last paramter") + } + + hk.GroupRoutes(path, r, mwList, hk.MapHandlerFunc{ + "POST /": c.Create, + "GET /": c.GetList, + "GET /{id}": c.GetDetail, + "PATCH /{id}": c.Update, + "DELETE /{id}": c.Delete, + }) +} diff --git a/pkg/handler-crud-helper/types.go b/pkg/handler-crud-helper/types.go new file mode 100644 index 00000000..e85f22fc --- /dev/null +++ b/pkg/handler-crud-helper/types.go @@ -0,0 +1,11 @@ +package handlercrudhelper + +import "net/http" + +type CrudBase interface { + Create(w http.ResponseWriter, r *http.Request) + GetList(w http.ResponseWriter, r *http.Request) + GetDetail(w http.ResponseWriter, r *http.Request) + Update(w http.ResponseWriter, r *http.Request) + Delete(w http.ResponseWriter, r *http.Request) +} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 2a9047ca..f65f35b4 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -3,6 +3,7 @@ package logger import ( "encoding/json" + "fmt" lz "github.com/karincake/apem/logger-zerolog" d "github.com/karincake/dodol" @@ -64,3 +65,15 @@ func SetLogError(e Event, data any) error { } return d.FieldError{Code: e.ErrInfo.Code, Message: msg} } + +func GenMessage(errCode string, errDetail ...string) string { + errMsg := "" + if len(errDetail) == 0 || errDetail[0] == "" { + errMsg = l.I.Msg(errCode) + } else if len(errDetail) == 1 && errDetail[0] != "" { // manual + errMsg = fmt.Sprintf(l.I.Msg(errCode), errDetail[0]) + } else if len(errDetail) == 2 && errDetail[0] != "" && errDetail[1] != "" { // manual + errMsg = fmt.Sprintf(l.I.Msg(errCode), errDetail[0], errDetail[1]) + } + return errMsg +} diff --git a/pkg/middleware/handler-logger/handler-logger.go b/pkg/middleware/handler-logger/handler-logger.go index ed6b77c6..42d1d0da 100644 --- a/pkg/middleware/handler-logger/handler-logger.go +++ b/pkg/middleware/handler-logger/handler-logger.go @@ -6,12 +6,10 @@ import ( "net/http" "time" - l "github.com/karincake/apem/loggera" + lz "github.com/karincake/apem/logger-zerolog" lo "github.com/karincake/apem/loggero" ) -var Logger l.LoggerItf - type wrappedWriter struct { http.ResponseWriter statusCode int @@ -31,7 +29,7 @@ func SetLog(next http.Handler) http.Handler { } next.ServeHTTP(wrapped, r) - Logger.Info(). + lz.O.Info(). String("scope", "request"). Int("status", wrapped.statusCode). String("method", r.Method). From 911cf6d1fbeca5f699a8f4d5499ad9fb86f95119 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 19 Aug 2025 14:26:34 +0700 Subject: [PATCH 03/40] add auth --- .../authentication/authentication.go | 58 +++++ .../main-use-case/authentication/case.go | 218 ++++++++++++++++++ 2 files changed, 276 insertions(+) create mode 100644 internal/interface/main-handler/authentication/authentication.go create mode 100644 internal/use-case/main-use-case/authentication/case.go diff --git a/internal/interface/main-handler/authentication/authentication.go b/internal/interface/main-handler/authentication/authentication.go new file mode 100644 index 00000000..2b3cf437 --- /dev/null +++ b/internal/interface/main-handler/authentication/authentication.go @@ -0,0 +1,58 @@ +package authentication + +import ( + "context" + "net/http" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" + + m "simrs-vx/internal/domain/main-entities/user" + s "simrs-vx/internal/use-case/main-use-case/authentication" +) + +type authKey string + +const akInfo authKey = "authInfo" + +type Key struct{} + +// var Position m.Position + +func Login(w http.ResponseWriter, r *http.Request) { + var input m.LoginDto + if !(rw.ValidateStructByIOR(w, r.Body, &input)) { + return + } + + // input.Position = Position + res, err := s.GenToken(input) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.II{"errors": err}, nil) + } else { + rw.DataResponse(w, res, err) + } +} + +func Logout(w http.ResponseWriter, r *http.Request) { + authInfoContext := context.Context.Value(r.Context(), akInfo) + if authInfoContext == nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "logout skiped. the request is done wihtout authorization."}, nil) + return + } + authInfo := context.Context.Value(r.Context(), akInfo).(*s.AuthInfo) + s.RevokeToken(authInfo.Uuid) + rw.WriteJSON(w, http.StatusOK, d.IS{"message": "logged out"}, nil) +} + +func GuardMW(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + accessDetail, err := s.ExtractToken(r, s.AccessToken) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, err.(d.FieldError), nil) + return + } + ctx := context.WithValue(r.Context(), Key{}, accessDetail) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} diff --git a/internal/use-case/main-use-case/authentication/case.go b/internal/use-case/main-use-case/authentication/case.go new file mode 100644 index 00000000..0a4383e1 --- /dev/null +++ b/internal/use-case/main-use-case/authentication/case.go @@ -0,0 +1,218 @@ +package authentication + +import ( + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "github.com/golang-jwt/jwt" + "github.com/google/uuid" + dg "github.com/karincake/apem/db-gorm-mysql" + d "github.com/karincake/dodol" + l "github.com/karincake/lepet" + + a "github.com/karincake/apem" + ms "github.com/karincake/apem/ms-redis" + + el "simrs-vx/pkg/logger" + p "simrs-vx/pkg/password" + + mu "simrs-vx/internal/domain/main-entities/user" + erc "simrs-vx/internal/domain/references/common" +) + +var authCfg AuthCfg + +func init() { + a.RegisterExtCall(GetConfig) +} + +// Generates token and store in redis at one place +// just return the error code +func GenToken(input mu.LoginDto) (*d.Data, error) { + // Get User + user := &mu.User{Name: input.Name} + // if input.Position_Code != "" { + // user.Position_Code = input.Position_Code + // } + if errCode := GetAndCheck(user, user); errCode != "" { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: errCode, Message: el.GenMessage(errCode)}} + } + + if user.LoginAttemptCount > 5 { + if user.LastSuccessLogin != nil { + now := time.Now() + lastAllowdLogin := user.LastAllowdLogin + if lastAllowdLogin.After(now.Add(-time.Hour * 1)) { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-tooMany", Message: el.GenMessage("auth-login-tooMany")}} + } else { + tn := time.Now() + user.LastAllowdLogin = &tn + user.LoginAttemptCount = 0 + dg.I.Save(&user) + } + } else { + tn := time.Now() + user.LastAllowdLogin = &tn + dg.I.Save(&user) + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-tooMany", Message: el.GenMessage("auth-login-tooMany")}} + } + } + + if !p.Check(input.Password, user.Password) { + user.LoginAttemptCount++ + dg.I.Save(&user) + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-incorrect", Message: el.GenMessage("auth-login-incorrect")}} + } else if user.Status_Code == erc.SCBlocked { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-blocked", Message: el.GenMessage("auth-login-blocked")}} + } else if user.Status_Code == erc.SCNew { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-unverified", Message: el.GenMessage("auth-login-unverified")}} + } + + // Access token prep + id, err := uuid.NewRandom() + if err != nil { + panic(fmt.Sprintf(l.I.Msg("uuid-gen-fail"), err)) + } + if input.Duration == 0 { + input.Duration = 24 * 60 + } + duration := time.Minute * time.Duration(input.Duration) + aUuid := id.String() + atExpires := time.Now().Add(duration).Unix() + atSecretKey := authCfg.AtSecretKey + + // extra + // if input.Position_Code == "doc" { + + // } + + // Creating Access Token + atClaims := jwt.MapClaims{} + atClaims["user_id"] = user.Id + atClaims["user_name"] = user.Name + // atClaims["user_email"] = user.Email + // atClaims["user_position_code"] = user.Position_Code + // atClaims["user_ref_id"] = user.Ref_Id + atClaims["exp"] = atExpires + atClaims["uuid"] = aUuid + at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims) + ats, err := at.SignedString([]byte(atSecretKey)) + if err != nil { + return nil, d.FieldErrors{"user": d.FieldError{Code: "token-sign-err", Message: el.GenMessage("token-sign-err")}} + } + + // Save to redis + now := time.Now() + atx := time.Unix(atExpires, 0) //converting Unix to UTC(to Time object) + err = ms.I.Set(aUuid, strconv.Itoa(int(user.Id)), atx.Sub(now)).Err() + if err != nil { + panic(fmt.Sprintf(l.I.Msg("redis-store-fail"), err.Error())) + } + + tn := time.Now() + user.LoginAttemptCount = 0 + user.LastSuccessLogin = &tn + user.LastAllowdLogin = &tn + dg.I.Save(&user) + + // Current data + return &d.Data{ + Meta: d.IS{ + "source": "authentication", + "structure": "single-data", + "status": "verified", + }, + Data: d.II{ + "user_id": strconv.Itoa(int(user.Id)), + "user_name": user.Name, + // "user_email": user.Email, + // "user_position_code": user.Position_Code, + // "user_ref_id": user.Ref_Id, + "accessToken": ats, + }, + }, nil +} + +func RevokeToken(uuid string) { + ms.I.Del(uuid) +} + +func VerifyToken(r *http.Request, tokenType TokenType) (data *jwt.Token, errCode, errDetail string) { + auth := r.Header.Get("Authorization") + if auth == "" { + return nil, "auth-missingHeader", "" + } + authArr := strings.Split(auth, " ") + if len(authArr) == 2 { + auth = authArr[1] + } + + token, err := jwt.Parse(auth, func(token *jwt.Token) (any, error) { + //Make sure that the token method conform to "SigningMethodHMAC" + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf(l.I.Msg("token-sign-unexcpeted"), token.Header["alg"]) + } + if tokenType == AccessToken { + return []byte(authCfg.AtSecretKey), nil + } else { + return []byte(authCfg.RtSecretKey), nil + } + }) + if err != nil { + return nil, "token-parse-fail", err.Error() + } + return token, "", "" +} + +func ExtractToken(r *http.Request, tokenType TokenType) (data *AuthInfo, err error) { + token, errCode, errDetail := VerifyToken(r, tokenType) + if errCode != "" { + return nil, d.FieldError{Code: errCode, Message: el.GenMessage(errCode, errDetail)} + } + claims, ok := token.Claims.(jwt.MapClaims) + if ok && token.Valid { + accessUuid, ok := claims["uuid"].(string) + if !ok { + return nil, d.FieldError{Code: "token-invalid", Message: el.GenMessage("token-invalid", "uuid not available")} + } + user_id, myErr := strconv.ParseInt(fmt.Sprintf("%.f", claims["user_id"]), 10, 64) + if myErr != nil { + return nil, d.FieldError{Code: "token-invalid", Message: el.GenMessage("token-invalid", "uuid is not available")} + } + accessUuidRedis := ms.I.Get(accessUuid) + if accessUuidRedis.String() == "" { + return nil, d.FieldError{Code: "token-unidentified", Message: el.GenMessage("token-unidentified")} + } + user_name := fmt.Sprintf("%v", claims["user_name"]) + // user_email := "" + // if v, exist := claims["user_email"]; exist && v != nil { + // user_email = v.(string) + // } + // ref_id := 0 + // if v, exist := claims["user_ref_id"]; exist && v != nil { + // tmp := v.(float64) + // ref_id = int(tmp) + // } + // position_code := "" + // if v, exist := claims["user_position_code"]; exist && v != nil { + // position_code = v.(string) + // } + data = &AuthInfo{ + Uuid: accessUuid, + User_Id: int(user_id), + User_Name: user_name, + // User_Email: user_email, + // User_Ref_Id: ref_id, + // User_Position_Code: position_code, + } + return + } + return nil, d.FieldError{Code: "token", Message: "token-invalid"} +} + +func GetConfig() { + a.ParseCfg(&authCfg) +} From a448f43b676908f1750d72ac0562a141354fa67b Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 19 Aug 2025 14:26:39 +0700 Subject: [PATCH 04/40] add cors --- pkg/cors-manager-mw/cors-manager-mw.go | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 pkg/cors-manager-mw/cors-manager-mw.go diff --git a/pkg/cors-manager-mw/cors-manager-mw.go b/pkg/cors-manager-mw/cors-manager-mw.go new file mode 100644 index 00000000..8ff70d8e --- /dev/null +++ b/pkg/cors-manager-mw/cors-manager-mw.go @@ -0,0 +1,31 @@ +package corsmanagermw + +import ( + "net/http" + + a "github.com/karincake/apem" +) + +type CorsCfg struct { + AllowedOrigins []string `yaml:"allowedOrigins"` + AllowedMethod string `yaml:"allowedMethod"` +} + +var cfg CorsCfg + +func SetCors(next http.Handler) http.Handler { + a.ParseSingleCfg(&cfg) + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", cfg.AllowedMethod) + w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") + + if r.Method == "OPTIONS" { + w.WriteHeader(http.StatusOK) + return + } + + next.ServeHTTP(w, r) + }) +} From 4a6c6e28bc7f27047295420aa98f8f5e809af014 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 19 Aug 2025 15:21:06 +0700 Subject: [PATCH 05/40] feat (auth): rework logout --- .../main-handler/authentication/authentication.go | 10 +++++----- internal/interface/main-handler/main-handler.go | 6 +++++- internal/use-case/main-use-case/authentication/case.go | 2 +- .../use-case/main-use-case/authentication/helper.go | 4 ++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/internal/interface/main-handler/authentication/authentication.go b/internal/interface/main-handler/authentication/authentication.go index 2b3cf437..37b84346 100644 --- a/internal/interface/main-handler/authentication/authentication.go +++ b/internal/interface/main-handler/authentication/authentication.go @@ -15,7 +15,7 @@ type authKey string const akInfo authKey = "authInfo" -type Key struct{} +type AuthKey struct{} // var Position m.Position @@ -35,12 +35,12 @@ func Login(w http.ResponseWriter, r *http.Request) { } func Logout(w http.ResponseWriter, r *http.Request) { - authInfoContext := context.Context.Value(r.Context(), akInfo) - if authInfoContext == nil { + ctxVal := r.Context().Value(AuthKey{}) + if ctxVal == nil { rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "logout skiped. the request is done wihtout authorization."}, nil) return } - authInfo := context.Context.Value(r.Context(), akInfo).(*s.AuthInfo) + authInfo := ctxVal.(*s.AuthInfo) s.RevokeToken(authInfo.Uuid) rw.WriteJSON(w, http.StatusOK, d.IS{"message": "logged out"}, nil) } @@ -52,7 +52,7 @@ func GuardMW(next http.Handler) http.Handler { rw.WriteJSON(w, http.StatusUnauthorized, err.(d.FieldError), nil) return } - ctx := context.WithValue(r.Context(), Key{}, accessDetail) + ctx := context.WithValue(r.Context(), AuthKey{}, accessDetail) next.ServeHTTP(w, r.WithContext(ctx)) }) } diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index f023d4b8..8d0efe0f 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -9,6 +9,7 @@ import ( /******************** external ********************/ a "github.com/karincake/apem" + hk "github.com/karincake/hongkue" /******************** infra ********************/ gs "simrs-vx/internal/infra/gorm-setting" @@ -17,6 +18,7 @@ import ( /******************** pkg ********************/ cmw "simrs-vx/pkg/cors-manager-mw" hc "simrs-vx/pkg/handler-crud-helper" + lh "simrs-vx/pkg/lang-helper" handlerlogger "simrs-vx/pkg/middleware/handler-logger" ///// Internal @@ -28,6 +30,7 @@ func SetRoutes() http.Handler { ///// a.RegisterExtCall(gs.Adjust) a.RegisterExtCall(ssdb.Init) + a.RegisterExtCall(lh.Populate) r := http.NewServeMux() @@ -35,7 +38,8 @@ func SetRoutes() http.Handler { r.HandleFunc("/", home.Home) r.HandleFunc("POST /v1/authentication/login", auth.Login) - r.HandleFunc("POST /v1/authentication/logout", auth.Logout) + // r.HandleFunc("POST /v1/authentication/logout", auth.Logout) + hk.Route("POST /v1/authentication/logout", r, auth.GuardMW, auth.Logout) hc.RegCrud(r, "/v1/user", user.O) diff --git a/internal/use-case/main-use-case/authentication/case.go b/internal/use-case/main-use-case/authentication/case.go index 0a4383e1..069958c7 100644 --- a/internal/use-case/main-use-case/authentication/case.go +++ b/internal/use-case/main-use-case/authentication/case.go @@ -9,7 +9,7 @@ import ( "github.com/golang-jwt/jwt" "github.com/google/uuid" - dg "github.com/karincake/apem/db-gorm-mysql" + dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" l "github.com/karincake/lepet" diff --git a/internal/use-case/main-use-case/authentication/helper.go b/internal/use-case/main-use-case/authentication/helper.go index 2a9a9c92..de618b5c 100644 --- a/internal/use-case/main-use-case/authentication/helper.go +++ b/internal/use-case/main-use-case/authentication/helper.go @@ -1,12 +1,12 @@ package authentication import ( - dg "github.com/karincake/apem/db-gorm-mysql" + dg "github.com/karincake/apem/db-gorm-pg" ) // just return the error code func GetAndCheck(input, condition any) (eCode string) { - result := dg.I.Where(condition).Find(input) + result := dg.I.Where(condition).Find(&input) if result.Error != nil { return "fetch-fail" } else if result.RowsAffected == 0 { From d476a314221fce1b68c7e6c9eeaaf0f57bcd86d9 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 19 Aug 2025 15:52:52 +0700 Subject: [PATCH 06/40] missing inactive status code --- internal/domain/references/common/common.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/domain/references/common/common.go b/internal/domain/references/common/common.go index a31d7644..7f6fed2b 100644 --- a/internal/domain/references/common/common.go +++ b/internal/domain/references/common/common.go @@ -37,6 +37,7 @@ const ( const ( SCNew StatusCode = "new" SCActive StatusCode = "active" + SCInactive StatusCode = "inactive" SCBlocked StatusCode = "blocked" SCSuspended StatusCode = "suspended" ) From 0a680d523b08ca5541ed0d5874b59f071651136c Mon Sep 17 00:00:00 2001 From: Dwi Atmoko Purbo Sakti <82804339+dpurbosakti@users.noreply.github.com> Date: Wed, 20 Aug 2025 08:56:01 +0700 Subject: [PATCH 07/40] Delete cmd/migration/atlas.hcl --- cmd/migration/atlas.hcl | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 cmd/migration/atlas.hcl diff --git a/cmd/migration/atlas.hcl b/cmd/migration/atlas.hcl deleted file mode 100644 index 3372fb2d..00000000 --- a/cmd/migration/atlas.hcl +++ /dev/null @@ -1,22 +0,0 @@ -data "external_schema" "gorm" { - program = [ - "go", - "run", - "-mod=mod", - ".", - ] -} - -env "gorm" { - src = data.external_schema.gorm.url - dev = "postgres://moko:password@localhost:5432/simrs_vx3?sslmode=disable" - migration { - dir = "file://migrations" - } - url = "postgres://moko:password@localhost:5432/simrs_vx1?sslmode=disable" - format { - migrate { - diff = "{{ sql . \" \" }}" - } - } -} \ No newline at end of file From b20380b1f64388c1182a4803e5db9feaeb5eceb5 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 20 Aug 2025 09:36:13 +0700 Subject: [PATCH 08/40] feat (user): add logger on crud --- internal/use-case/main-use-case/user/case.go | 279 ++++++++++++++++--- internal/use-case/main-use-case/user/lib.go | 2 +- pkg/logger/logger.go | 15 +- 3 files changed, 251 insertions(+), 45 deletions(-) diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index bba503db..0086fa32 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -26,17 +26,13 @@ func Create(input e.CreateDto) (*d.Data, error) { } // Start log - event.Action = "Create" - event.Status = "started" - pl.SetLogInfo(event, input) + pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { for i := range createPreMw { mwName := fmt.Sprintf("createPreMw[%d]", i) - event.Action = mwName - event.Status = "started" - pl.SetLogInfo(event, data) + pl.SetLogInfo(&event, data, "started", mwName) if err := createPreMw[i](&input, &data, tx); err != nil { event.Status = "failed" @@ -48,13 +44,10 @@ func Create(input e.CreateDto) (*d.Data, error) { return pl.SetLogError(event, data) } - event.Status = "completed" - pl.SetLogInfo(event, nil) + pl.SetLogInfo(&event, nil, "complete") } - event.Action = "DBCreate" - event.Status = "started" - pl.SetLogInfo(event, data) + pl.SetLogInfo(&event, data, "started", "DBCreate") _, err := CreateData(&data, tx) if err != nil { event.Status = "failed" @@ -66,15 +59,12 @@ func Create(input e.CreateDto) (*d.Data, error) { return pl.SetLogError(event, data) } - event.Status = "completed" - pl.SetLogInfo(event, nil) + pl.SetLogInfo(&event, nil, "complete") for i := range createPostMw { mwName := fmt.Sprintf("createPostMw[%d]", i) - event.Action = mwName - event.Status = "started" - pl.SetLogInfo(event, input) + pl.SetLogInfo(&event, input, "started", mwName) if err := createPostMw[i](&input, &data, tx); err != nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ @@ -86,8 +76,7 @@ func Create(input e.CreateDto) (*d.Data, error) { } } - event.Status = "completed" - pl.SetLogInfo(event, nil) + pl.SetLogInfo(&event, nil, "complete") return nil }) @@ -111,22 +100,64 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { var dataList []e.User 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 { for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := readListPreMw[i](&input, data, tx); err != nil { - return nil + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) } + + pl.SetLogInfo(&event, nil, "complete") } + pl.SetLogInfo(&event, input, "started", "DBReadList") dataList, metaList, err = ReadListData(input, tx) if err != nil { - return err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) } + pl.SetLogInfo(&event, nil, "complete") + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := readListPostMw[i](&input, data, tx); err != nil { - return nil + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) } + + pl.SetLogInfo(&event, nil, "complete") } return nil @@ -152,21 +183,66 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { var data *e.User 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 { for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := readDetailPreMw[i](&input, data, tx); err != nil { - return nil + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) } + + pl.SetLogInfo(&event, nil, "complete") } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) if err != nil { - return err - } - for i := range readDetailPostMw { - if err := readDetailPostMw[i](&input, data, tx); err != nil { - return nil + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, } + return pl.SetLogError(event, input) } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + return nil }) @@ -188,29 +264,93 @@ func Update(input e.UpdateDto) (*d.Data, error) { rdDto := e.ReadDetailDto{Id: input.Id} var data *e.User 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") data, err = ReadDetailData(rdDto, tx) if err != nil { - return nil + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) } + pl.SetLogInfo(&event, nil, "complete") + + pl.SetLogInfo(&event, input, "started", "setUpdate") err = setUpdate(input, data) if err != nil { - return err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "set-update-fail", + Detail: "Set update data failed", + Raw: err, + } + return pl.SetLogError(event, input) } + + pl.SetLogInfo(&event, nil, "complete") + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + if err := updatePreMw[i](&rdDto, data, tx); err != nil { - return nil + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) } + + pl.SetLogInfo(&event, nil, "complete") } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") if err := UpdateData(*data, tx); err != nil { - return nil - } - for i := range updatePostMw { - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - return 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") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + return nil }) @@ -233,24 +373,79 @@ func Delete(input e.DeleteDto) (*d.Data, error) { rdDto := e.ReadDetailDto{Id: input.Id} var data *e.User 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") data, err = ReadDetailData(rdDto, tx) if err != nil { - return nil + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) } + + pl.SetLogInfo(&event, nil, "complete") + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + if err := deletePreMw[i](&rdDto, data, tx); err != nil { - return nil + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) } + + pl.SetLogInfo(&event, nil, "complete") } + + pl.SetLogInfo(&event, data, "started", "DBDelete") if err := DeleteData(data, tx); err != nil { - return nil - } - for i := range deletePostMw { - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - return 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") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + return nil }) diff --git a/internal/use-case/main-use-case/user/lib.go b/internal/use-case/main-use-case/user/lib.go index 30f6213d..c767bdf1 100644 --- a/internal/use-case/main-use-case/user/lib.go +++ b/internal/use-case/main-use-case/user/lib.go @@ -43,7 +43,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.User, *e.MetaDto, e Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). - Order("CreatedAt DESC") + Order("\"CreatedAt\" DESC") if err := tx.Debug().Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index f65f35b4..73f884bd 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -27,13 +27,24 @@ type ErrorInfo struct { Raw error } -func SetLogInfo(e Event, data any) { +// SetLogInfo updates the event and logs it. +// The first argument is the event, the second is the data. +// Variadic arguments: +// - first (optional): status +// - second (optional): action +func SetLogInfo(e *Event, data any, args ...string) { dataString, _ := json.Marshal(data) + if len(args) > 0 { + e.Status = args[0] + } + if len(args) > 1 { + e.Action = args[1] + } lz.O.Info(). String("source", e.Source). String("feature", e.Feature). String("action", e.Action). - String("status", "started"). + String("status", e.Status). String("input", string(dataString)). Send() } From a8f9dcf73814bf014f555da68f1ace111f58c398 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 20 Aug 2025 13:07:56 +0700 Subject: [PATCH 09/40] feat (crud): add division, division-position --- ...{20250819053416.sql => 20250820052409.sql} | 11 + cmd/migration/migrations/20250820055632.sql | 12 + cmd/migration/migrations/atlas.sum | 5 +- .../main-entities/division-position/dto.go | 68 +++ .../main-entities/division-position/entity.go | 14 + internal/domain/main-entities/division/dto.go | 68 +++ .../domain/main-entities/division/entity.go | 12 + .../domain/references/encounter/encounter.go | 44 ++ .../references/examination/examination.go | 44 -- .../main-handler/division-position/handler.go | 71 +++ .../main-handler/division/handler.go | 71 +++ .../interface/main-handler/main-handler.go | 6 + internal/interface/migration/migration.go | 4 + .../main-use-case/division-position/case.go | 452 ++++++++++++++++++ .../main-use-case/division-position/helper.go | 23 + .../main-use-case/division-position/lib.go | 98 ++++ .../division-position/tycovar.go | 32 ++ .../use-case/main-use-case/division/case.go | 452 ++++++++++++++++++ .../use-case/main-use-case/division/helper.go | 23 + .../use-case/main-use-case/division/lib.go | 98 ++++ .../main-use-case/division/tycovar.go | 32 ++ 21 files changed, 1594 insertions(+), 46 deletions(-) rename cmd/migration/migrations/{20250819053416.sql => 20250820052409.sql} (61%) create mode 100644 cmd/migration/migrations/20250820055632.sql create mode 100644 internal/domain/main-entities/division-position/dto.go create mode 100644 internal/domain/main-entities/division-position/entity.go create mode 100644 internal/domain/main-entities/division/dto.go create mode 100644 internal/domain/main-entities/division/entity.go create mode 100644 internal/domain/references/encounter/encounter.go delete mode 100644 internal/domain/references/examination/examination.go create mode 100644 internal/interface/main-handler/division-position/handler.go create mode 100644 internal/interface/main-handler/division/handler.go create mode 100644 internal/use-case/main-use-case/division-position/case.go create mode 100644 internal/use-case/main-use-case/division-position/helper.go create mode 100644 internal/use-case/main-use-case/division-position/lib.go create mode 100644 internal/use-case/main-use-case/division-position/tycovar.go create mode 100644 internal/use-case/main-use-case/division/case.go create mode 100644 internal/use-case/main-use-case/division/helper.go create mode 100644 internal/use-case/main-use-case/division/lib.go create mode 100644 internal/use-case/main-use-case/division/tycovar.go diff --git a/cmd/migration/migrations/20250819053416.sql b/cmd/migration/migrations/20250820052409.sql similarity index 61% rename from cmd/migration/migrations/20250819053416.sql rename to cmd/migration/migrations/20250820052409.sql index fa94170a..b3df477e 100644 --- a/cmd/migration/migrations/20250819053416.sql +++ b/cmd/migration/migrations/20250820052409.sql @@ -1,3 +1,14 @@ +-- Create "Division" table +CREATE TABLE "public"."Division" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "Parent_Id" smallint NULL, + PRIMARY KEY ("Id") +); -- Create "User" table CREATE TABLE "public"."User" ( "Id" bigserial NOT NULL, diff --git a/cmd/migration/migrations/20250820055632.sql b/cmd/migration/migrations/20250820055632.sql new file mode 100644 index 00000000..9e9369be --- /dev/null +++ b/cmd/migration/migrations/20250820055632.sql @@ -0,0 +1,12 @@ +-- Create "DivisionPosition" table +CREATE TABLE "public"."DivisionPosition" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Division_Id" integer NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_DivisionPosition_Division" FOREIGN KEY ("Division_Id") REFERENCES "public"."Division" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index d8fcc6bb..d9bda753 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,2 +1,3 @@ -h1:TslQ6d3/z4H6DQJvWAGwP3IVSAr/qYOosLEmorZhYx0= -20250819053416.sql h1:kYIqQm8dEYH+feZEHrCekuEvwKl3h1W4zlIpPAWn3W8= +h1:RD9Yp8yQFfSKnSkmgYm47Q47Dn3FmZvYDCeNIiVKU1w= +20250820052409.sql h1:W2zifi3eF+hG0fHvIrY15dH82WO/4QPGdZOEUkgKlAg= +20250820055632.sql h1:sPoDUmT4aZV4qiaq63ssIcoevr3N2WAjRcU1c+Kz6kc= diff --git a/internal/domain/main-entities/division-position/dto.go b/internal/domain/main-entities/division-position/dto.go new file mode 100644 index 00000000..3847d332 --- /dev/null +++ b/internal/domain/main-entities/division-position/dto.go @@ -0,0 +1,68 @@ +package divisionposition + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Division_Id *uint16 `json:"division_id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Division_Id *uint16 `json:"division_id"` + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Division_Id *uint16 `json:"division_id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Division_Id *uint16 `json:"division_id"` + Code string `json:"code"` + Name string `json:"name"` +} + +func (d DivisionPosition) ToResponse() ResponseDto { + resp := ResponseDto{ + Division_Id: d.Division_Id, + Code: d.Code, + Name: d.Name, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(users []DivisionPosition) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/division-position/entity.go b/internal/domain/main-entities/division-position/entity.go new file mode 100644 index 00000000..88311e96 --- /dev/null +++ b/internal/domain/main-entities/division-position/entity.go @@ -0,0 +1,14 @@ +package divisionposition + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/division" +) + +type DivisionPosition struct { + ecore.SmallMain // adjust this according to the needs + Division_Id *uint16 `json:"division_id"` + Division *ed.Division `json:"division" gorm:"foreignKey:Division_Id"` + Code string `json:"code" gorm:"size:10"` + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/domain/main-entities/division/dto.go b/internal/domain/main-entities/division/dto.go new file mode 100644 index 00000000..3d369cdf --- /dev/null +++ b/internal/domain/main-entities/division/dto.go @@ -0,0 +1,68 @@ +package division + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + Parent_Id *int16 `json:"parent_id"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + Parent_Id *int16 `json:"parent_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Parent_Id *int16 `json:"parent_id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + Parent_Id *int16 `json:"parent_id"` +} + +func (d Division) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + Parent_Id: d.Parent_Id, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(users []Division) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/division/entity.go b/internal/domain/main-entities/division/entity.go new file mode 100644 index 00000000..55918a8d --- /dev/null +++ b/internal/domain/main-entities/division/entity.go @@ -0,0 +1,12 @@ +package division + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type Division struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"size:10"` + Name string `json:"name" gorm:"size:50"` + Parent_Id *int16 `json:"parent_id"` +} diff --git a/internal/domain/references/encounter/encounter.go b/internal/domain/references/encounter/encounter.go new file mode 100644 index 00000000..9ffa168d --- /dev/null +++ b/internal/domain/references/encounter/encounter.go @@ -0,0 +1,44 @@ +package encounter + +type ( + EncounterStatus string + EncounterClass string + EmergencyClass string + InpatientClass string +) + +const ( + EncounterStatusNew EncounterStatus = "new" + EncounterStatusNurse EncounterStatus = "nurse assessment" + EncounterStatusDoctor EncounterStatus = "doctor assessment" + EncounterStatusDone EncounterStatus = "done" + EncounterStatusCancel EncounterStatus = "canceled" +) +const ( + IGD EmergencyClass = "igd" + Ponek EmergencyClass = "ponek" +) +const ( + ECAmbulatory EncounterClass = "ambulatory" + ECInpatient EncounterClass = "inpatient" + ECEmergency EncounterClass = "emergency" + ECRadiology EncounterClass = "radiology" +) + +func (ec EncounterClass) Code() string { + switch ec { + case ECAmbulatory: + return "AMB" + case ECInpatient: + return "IMP" + case ECEmergency: + return "EMER" + default: + return "UNKNOWN" + } +} + +const ( + ICU InpatientClass = "ICU" + NonICU InpatientClass = "non ICU" +) diff --git a/internal/domain/references/examination/examination.go b/internal/domain/references/examination/examination.go deleted file mode 100644 index 4ca227db..00000000 --- a/internal/domain/references/examination/examination.go +++ /dev/null @@ -1,44 +0,0 @@ -package examination - -type ( - ExaminationStatus string - ExaminationClass string - EmergencyClass string - InpatientClass string -) - -const ( - ExaminationStatusNew ExaminationStatus = "new" - ExaminationStatusNurse ExaminationStatus = "nurse assessment" - ExaminationStatusDoctor ExaminationStatus = "doctor assessment" - ExaminationStatusDone ExaminationStatus = "done" - ExaminationStatusCancel ExaminationStatus = "canceled" -) -const ( - IGD EmergencyClass = "igd" - Ponek EmergencyClass = "ponek" -) -const ( - ECAmbulatory ExaminationClass = "ambulatory" - ECInpatient ExaminationClass = "inpatient" - ECEmergency ExaminationClass = "emergency" - ECRadiology ExaminationClass = "radiology" -) - -func (ec ExaminationClass) Code() string { - switch ec { - case ECAmbulatory: - return "AMB" - case ECInpatient: - return "IMP" - case ECEmergency: - return "EMER" - default: - return "UNKNOWN" - } -} - -const ( - ICU InpatientClass = "ICU" - NonICU InpatientClass = "non ICU" -) diff --git a/internal/interface/main-handler/division-position/handler.go b/internal/interface/main-handler/division-position/handler.go new file mode 100644 index 00000000..180b96ea --- /dev/null +++ b/internal/interface/main-handler/division-position/handler.go @@ -0,0 +1,71 @@ +package divisionposition + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/division-position" + u "simrs-vx/internal/use-case/main-use-case/division-position" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/division/handler.go b/internal/interface/main-handler/division/handler.go new file mode 100644 index 00000000..94940f55 --- /dev/null +++ b/internal/interface/main-handler/division/handler.go @@ -0,0 +1,71 @@ +package division + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/division" + u "simrs-vx/internal/use-case/main-use-case/division" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 8d0efe0f..22f8453b 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -21,6 +21,10 @@ import ( lh "simrs-vx/pkg/lang-helper" handlerlogger "simrs-vx/pkg/middleware/handler-logger" + /******************** sources ********************/ + division "simrs-vx/internal/interface/main-handler/division" + divisionposition "simrs-vx/internal/interface/main-handler/division-position" + ///// Internal "simrs-vx/internal/interface/main-handler/home" ) @@ -42,6 +46,8 @@ func SetRoutes() http.Handler { hk.Route("POST /v1/authentication/logout", r, auth.GuardMW, auth.Logout) hc.RegCrud(r, "/v1/user", user.O) + hc.RegCrud(r, "/v1/division", division.O) + hc.RegCrud(r, "/v1/division-position", divisionposition.O) ///// return cmw.SetCors(handlerlogger.SetLog(r)) diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 8a22efb0..8396c8a6 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -5,6 +5,8 @@ import ( "io" "os" "os/exec" + ed "simrs-vx/internal/domain/main-entities/division" + edp "simrs-vx/internal/domain/main-entities/division-position" eu "simrs-vx/internal/domain/main-entities/user" "ariga.io/atlas-provider-gorm/gormschema" @@ -41,6 +43,8 @@ func Loader() { func GetEntities() []any { return []any{ &eu.User{}, + &ed.Division{}, + &edp.DivisionPosition{}, } } diff --git a/internal/use-case/main-use-case/division-position/case.go b/internal/use-case/main-use-case/division-position/case.go new file mode 100644 index 00000000..46d5d80f --- /dev/null +++ b/internal/use-case/main-use-case/division-position/case.go @@ -0,0 +1,452 @@ +package divisionposition + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/division-position" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +const source = "division-position" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.DivisionPosition{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.DivisionPosition + var dataList []e.DivisionPosition + 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 { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + 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": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.DivisionPosition + 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 { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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 Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.DivisionPosition + 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") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); 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") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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.DivisionPosition + 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") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); 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") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/division-position/helper.go b/internal/use-case/main-use-case/division-position/helper.go new file mode 100644 index 00000000..f353a9ea --- /dev/null +++ b/internal/use-case/main-use-case/division-position/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package divisionposition + +import ( + e "simrs-vx/internal/domain/main-entities/division-position" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.DivisionPosition) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Division_Id = inputSrc.Division_Id + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/division-position/lib.go b/internal/use-case/main-use-case/division-position/lib.go new file mode 100644 index 00000000..60648199 --- /dev/null +++ b/internal/use-case/main-use-case/division-position/lib.go @@ -0,0 +1,98 @@ +package divisionposition + +import ( + e "simrs-vx/internal/domain/main-entities/division-position" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.DivisionPosition, dbx ...*gorm.DB) (*e.DivisionPosition, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.DivisionPosition, *e.MetaDto, error) { + data := []e.DivisionPosition{} + 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.DivisionPosition{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.DivisionPosition, error) { + data := e.DivisionPosition{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.DivisionPosition, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.DivisionPosition, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/division-position/tycovar.go b/internal/use-case/main-use-case/division-position/tycovar.go new file mode 100644 index 00000000..0684de01 --- /dev/null +++ b/internal/use-case/main-use-case/division-position/tycovar.go @@ -0,0 +1,32 @@ +/* +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 divisionposition + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/division-position" +) + +type createMw func(input *e.CreateDto, data *e.DivisionPosition, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.DivisionPosition, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.DivisionPosition, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.DivisionPosition, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.DivisionPosition, tx *gorm.DB) error + +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 diff --git a/internal/use-case/main-use-case/division/case.go b/internal/use-case/main-use-case/division/case.go new file mode 100644 index 00000000..9b0aa8b5 --- /dev/null +++ b/internal/use-case/main-use-case/division/case.go @@ -0,0 +1,452 @@ +package division + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/division" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +const source = "division" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Division{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Division + var dataList []e.Division + 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 { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + 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": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Division + 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 { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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 Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Division + 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") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); 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") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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.Division + 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") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); 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") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/division/helper.go b/internal/use-case/main-use-case/division/helper.go new file mode 100644 index 00000000..c0341ee0 --- /dev/null +++ b/internal/use-case/main-use-case/division/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package division + +import ( + e "simrs-vx/internal/domain/main-entities/division" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Division) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Parent_Id = inputSrc.Parent_Id +} diff --git a/internal/use-case/main-use-case/division/lib.go b/internal/use-case/main-use-case/division/lib.go new file mode 100644 index 00000000..1b13bcf5 --- /dev/null +++ b/internal/use-case/main-use-case/division/lib.go @@ -0,0 +1,98 @@ +package division + +import ( + e "simrs-vx/internal/domain/main-entities/division" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.Division, dbx ...*gorm.DB) (*e.Division, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Division, *e.MetaDto, error) { + data := []e.Division{} + 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.Division{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Division, error) { + data := e.Division{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.Division, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.Division, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/division/tycovar.go b/internal/use-case/main-use-case/division/tycovar.go new file mode 100644 index 00000000..ba4154f2 --- /dev/null +++ b/internal/use-case/main-use-case/division/tycovar.go @@ -0,0 +1,32 @@ +/* +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 division + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/division" +) + +type createMw func(input *e.CreateDto, data *e.Division, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.Division, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error + +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 From 14cba148226e77d14c6e777eb17dcd8683c466dd Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 20 Aug 2025 13:08:55 +0700 Subject: [PATCH 10/40] add encounter outpatient class --- internal/domain/references/encounter/encounter.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/domain/references/encounter/encounter.go b/internal/domain/references/encounter/encounter.go index 9ffa168d..b7e4c1d8 100644 --- a/internal/domain/references/encounter/encounter.go +++ b/internal/domain/references/encounter/encounter.go @@ -20,6 +20,7 @@ const ( ) const ( ECAmbulatory EncounterClass = "ambulatory" + ECOutpatient EncounterClass = "outpatient" ECInpatient EncounterClass = "inpatient" ECEmergency EncounterClass = "emergency" ECRadiology EncounterClass = "radiology" From 4c25bdf8dbd53e533c23794c5df377d8e48fd2a6 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 20 Aug 2025 13:40:25 +0700 Subject: [PATCH 11/40] feat (crud): add installation, unit --- cmd/migration/migrations/20250820061823.sql | 11 + cmd/migration/migrations/20250820062943.sql | 12 + cmd/migration/migrations/atlas.sum | 4 +- .../domain/main-entities/installation/dto.go | 69 +++ .../main-entities/installation/entity.go | 13 + internal/domain/main-entities/unit/dto.go | 68 +++ internal/domain/main-entities/unit/entity.go | 14 + .../domain/references/encounter/encounter.go | 2 +- .../main-handler/installation/handler.go | 71 +++ .../interface/main-handler/main-handler.go | 6 + .../interface/main-handler/unit/handler.go | 71 +++ internal/interface/migration/migration.go | 4 + .../main-use-case/division-position/case.go | 11 +- .../use-case/main-use-case/division/case.go | 11 +- .../main-use-case/installation/case.go | 459 +++++++++++++++++ .../main-use-case/installation/helper.go | 23 + .../main-use-case/installation/lib.go | 98 ++++ .../main-use-case/installation/tycovar.go | 32 ++ internal/use-case/main-use-case/unit/case.go | 460 ++++++++++++++++++ .../use-case/main-use-case/unit/helper.go | 23 + internal/use-case/main-use-case/unit/lib.go | 98 ++++ .../use-case/main-use-case/unit/tycovar.go | 32 ++ internal/use-case/main-use-case/user/case.go | 11 +- 23 files changed, 1595 insertions(+), 8 deletions(-) create mode 100644 cmd/migration/migrations/20250820061823.sql create mode 100644 cmd/migration/migrations/20250820062943.sql create mode 100644 internal/domain/main-entities/installation/dto.go create mode 100644 internal/domain/main-entities/installation/entity.go create mode 100644 internal/domain/main-entities/unit/dto.go create mode 100644 internal/domain/main-entities/unit/entity.go create mode 100644 internal/interface/main-handler/installation/handler.go create mode 100644 internal/interface/main-handler/unit/handler.go create mode 100644 internal/use-case/main-use-case/installation/case.go create mode 100644 internal/use-case/main-use-case/installation/helper.go create mode 100644 internal/use-case/main-use-case/installation/lib.go create mode 100644 internal/use-case/main-use-case/installation/tycovar.go create mode 100644 internal/use-case/main-use-case/unit/case.go create mode 100644 internal/use-case/main-use-case/unit/helper.go create mode 100644 internal/use-case/main-use-case/unit/lib.go create mode 100644 internal/use-case/main-use-case/unit/tycovar.go diff --git a/cmd/migration/migrations/20250820061823.sql b/cmd/migration/migrations/20250820061823.sql new file mode 100644 index 00000000..cd50b42b --- /dev/null +++ b/cmd/migration/migrations/20250820061823.sql @@ -0,0 +1,11 @@ +-- Create "Installation" table +CREATE TABLE "public"."Installation" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "EncounterClass_Code" character varying(10) NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/migration/migrations/20250820062943.sql b/cmd/migration/migrations/20250820062943.sql new file mode 100644 index 00000000..36a3046b --- /dev/null +++ b/cmd/migration/migrations/20250820062943.sql @@ -0,0 +1,12 @@ +-- Create "Unit" table +CREATE TABLE "public"."Unit" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Installation_Id" integer NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Unit_Installation" FOREIGN KEY ("Installation_Id") REFERENCES "public"."Installation" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index d9bda753..a6638e1e 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,3 +1,5 @@ -h1:RD9Yp8yQFfSKnSkmgYm47Q47Dn3FmZvYDCeNIiVKU1w= +h1:sflrLy3WNiI1HdFXmrmyufKJOFz2lUT1ElPaNRU+uCo= 20250820052409.sql h1:W2zifi3eF+hG0fHvIrY15dH82WO/4QPGdZOEUkgKlAg= 20250820055632.sql h1:sPoDUmT4aZV4qiaq63ssIcoevr3N2WAjRcU1c+Kz6kc= +20250820061823.sql h1:mj37CorTCwngLSo5PRKGC3Wy4I4IapmNXaJGgGxU6y4= +20250820062943.sql h1:Cr8vZGsdJ8Bh+ZKGVAmEh+4rnsjgt5eIy3lExpE4etc= diff --git a/internal/domain/main-entities/installation/dto.go b/internal/domain/main-entities/installation/dto.go new file mode 100644 index 00000000..e4f806b1 --- /dev/null +++ b/internal/domain/main-entities/installation/dto.go @@ -0,0 +1,69 @@ +package installation + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ere "simrs-vx/internal/domain/references/encounter" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` +} + +func (i Installation) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: i.Code, + Name: i.Name, + EncounterClass_Code: i.EncounterClass_Code, + } + resp.SmallMain = i.SmallMain + return resp +} + +func ToResponseList(users []Installation) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/installation/entity.go b/internal/domain/main-entities/installation/entity.go new file mode 100644 index 00000000..84159810 --- /dev/null +++ b/internal/domain/main-entities/installation/entity.go @@ -0,0 +1,13 @@ +package installation + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ere "simrs-vx/internal/domain/references/encounter" +) + +type Installation struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"size:10"` + Name string `json:"name" gorm:"size:50"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code" gorm:"size:10"` +} diff --git a/internal/domain/main-entities/unit/dto.go b/internal/domain/main-entities/unit/dto.go new file mode 100644 index 00000000..0a5e8b51 --- /dev/null +++ b/internal/domain/main-entities/unit/dto.go @@ -0,0 +1,68 @@ +package unit + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Installation_Id *uint16 `json:"installation_id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Installation_Id *uint16 `json:"installation_id"` + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Installation_Id *uint16 `json:"installation_id"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Installation_Id *uint16 `json:"installation_id"` + Code string `json:"code"` + Name string `json:"name"` +} + +func (u Unit) ToResponse() ResponseDto { + resp := ResponseDto{ + Installation_Id: u.Installation_Id, + Code: u.Code, + Name: u.Name, + } + resp.SmallMain = u.SmallMain + return resp +} + +func ToResponseList(users []Unit) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/unit/entity.go b/internal/domain/main-entities/unit/entity.go new file mode 100644 index 00000000..3953692f --- /dev/null +++ b/internal/domain/main-entities/unit/entity.go @@ -0,0 +1,14 @@ +package unit + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/installation" +) + +type Unit struct { + ecore.SmallMain // adjust this according to the needs + Installation_Id *uint16 `json:"installation_id"` + Installation *ei.Installation `json:"installation" gorm:"foreignKey:Installation_Id"` + Code string `json:"code" gorm:"size:10"` + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/domain/references/encounter/encounter.go b/internal/domain/references/encounter/encounter.go index b7e4c1d8..941b0cae 100644 --- a/internal/domain/references/encounter/encounter.go +++ b/internal/domain/references/encounter/encounter.go @@ -28,7 +28,7 @@ const ( func (ec EncounterClass) Code() string { switch ec { - case ECAmbulatory: + case ECAmbulatory, ECOutpatient: return "AMB" case ECInpatient: return "IMP" diff --git a/internal/interface/main-handler/installation/handler.go b/internal/interface/main-handler/installation/handler.go new file mode 100644 index 00000000..dd5903f8 --- /dev/null +++ b/internal/interface/main-handler/installation/handler.go @@ -0,0 +1,71 @@ +package installation + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/installation" + u "simrs-vx/internal/use-case/main-use-case/installation" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 22f8453b..6659b264 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -24,6 +24,8 @@ import ( /******************** sources ********************/ division "simrs-vx/internal/interface/main-handler/division" divisionposition "simrs-vx/internal/interface/main-handler/division-position" + installation "simrs-vx/internal/interface/main-handler/installation" + unit "simrs-vx/internal/interface/main-handler/unit" ///// Internal "simrs-vx/internal/interface/main-handler/home" @@ -46,8 +48,12 @@ func SetRoutes() http.Handler { hk.Route("POST /v1/authentication/logout", r, auth.GuardMW, auth.Logout) hc.RegCrud(r, "/v1/user", user.O) + + /******************** sources ********************/ hc.RegCrud(r, "/v1/division", division.O) hc.RegCrud(r, "/v1/division-position", divisionposition.O) + hc.RegCrud(r, "/v1/installation", installation.O) + hc.RegCrud(r, "/v1/unit", unit.O) ///// return cmw.SetCors(handlerlogger.SetLog(r)) diff --git a/internal/interface/main-handler/unit/handler.go b/internal/interface/main-handler/unit/handler.go new file mode 100644 index 00000000..0abc9a21 --- /dev/null +++ b/internal/interface/main-handler/unit/handler.go @@ -0,0 +1,71 @@ +package unit + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/unit" + u "simrs-vx/internal/use-case/main-use-case/unit" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 8396c8a6..723d097e 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -7,6 +7,8 @@ import ( "os/exec" ed "simrs-vx/internal/domain/main-entities/division" edp "simrs-vx/internal/domain/main-entities/division-position" + ei "simrs-vx/internal/domain/main-entities/installation" + eun "simrs-vx/internal/domain/main-entities/unit" eu "simrs-vx/internal/domain/main-entities/user" "ariga.io/atlas-provider-gorm/gormschema" @@ -45,6 +47,8 @@ func GetEntities() []any { &eu.User{}, &ed.Division{}, &edp.DivisionPosition{}, + &ei.Installation{}, + &eun.Unit{}, } } diff --git a/internal/use-case/main-use-case/division-position/case.go b/internal/use-case/main-use-case/division-position/case.go index 46d5d80f..2749ca1b 100644 --- a/internal/use-case/main-use-case/division-position/case.go +++ b/internal/use-case/main-use-case/division-position/case.go @@ -1,6 +1,7 @@ package divisionposition import ( + "errors" "fmt" e "simrs-vx/internal/domain/main-entities/division-position" "strconv" @@ -213,14 +214,20 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-read-detail-fail", Detail: "Database read detail failed", Raw: err, } - return pl.SetLogError(event, input) } pl.SetLogInfo(&event, nil, "complete") diff --git a/internal/use-case/main-use-case/division/case.go b/internal/use-case/main-use-case/division/case.go index 9b0aa8b5..dfd9d985 100644 --- a/internal/use-case/main-use-case/division/case.go +++ b/internal/use-case/main-use-case/division/case.go @@ -1,6 +1,7 @@ package division import ( + "errors" "fmt" e "simrs-vx/internal/domain/main-entities/division" "strconv" @@ -213,14 +214,20 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-read-detail-fail", Detail: "Database read detail failed", Raw: err, } - return pl.SetLogError(event, input) } pl.SetLogInfo(&event, nil, "complete") diff --git a/internal/use-case/main-use-case/installation/case.go b/internal/use-case/main-use-case/installation/case.go new file mode 100644 index 00000000..9a2689ec --- /dev/null +++ b/internal/use-case/main-use-case/installation/case.go @@ -0,0 +1,459 @@ +package installation + +import ( + "errors" + "fmt" + e "simrs-vx/internal/domain/main-entities/installation" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +const source = "installation" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Installation{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Installation + var dataList []e.Installation + 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 { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + 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": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + 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, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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 Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + 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") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); 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") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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.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") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); 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") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/installation/helper.go b/internal/use-case/main-use-case/installation/helper.go new file mode 100644 index 00000000..3ad22892 --- /dev/null +++ b/internal/use-case/main-use-case/installation/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package installation + +import ( + e "simrs-vx/internal/domain/main-entities/installation" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Installation) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.EncounterClass_Code = inputSrc.EncounterClass_Code +} diff --git a/internal/use-case/main-use-case/installation/lib.go b/internal/use-case/main-use-case/installation/lib.go new file mode 100644 index 00000000..30129aa3 --- /dev/null +++ b/internal/use-case/main-use-case/installation/lib.go @@ -0,0 +1,98 @@ +package installation + +import ( + e "simrs-vx/internal/domain/main-entities/installation" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.Installation, dbx ...*gorm.DB) (*e.Installation, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Installation, *e.MetaDto, error) { + data := []e.Installation{} + 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.Installation{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Installation, error) { + data := e.Installation{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.Installation, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.Installation, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/installation/tycovar.go b/internal/use-case/main-use-case/installation/tycovar.go new file mode 100644 index 00000000..072372e0 --- /dev/null +++ b/internal/use-case/main-use-case/installation/tycovar.go @@ -0,0 +1,32 @@ +/* +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 installation + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/installation" +) + +type createMw func(input *e.CreateDto, data *e.Installation, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.Installation, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error + +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 diff --git a/internal/use-case/main-use-case/unit/case.go b/internal/use-case/main-use-case/unit/case.go new file mode 100644 index 00000000..37082abf --- /dev/null +++ b/internal/use-case/main-use-case/unit/case.go @@ -0,0 +1,460 @@ +package unit + +import ( + "errors" + "fmt" + e "simrs-vx/internal/domain/main-entities/unit" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +const source = "unit" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Unit{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Unit + var dataList []e.Unit + 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 { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + 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": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Unit + 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 { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + } + return pl.SetLogError(event, input) + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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 Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Unit + 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") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); 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") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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.Unit + 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") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); 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") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/unit/helper.go b/internal/use-case/main-use-case/unit/helper.go new file mode 100644 index 00000000..f7729ec9 --- /dev/null +++ b/internal/use-case/main-use-case/unit/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package unit + +import ( + e "simrs-vx/internal/domain/main-entities/unit" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Unit) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Installation_Id = inputSrc.Installation_Id + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/unit/lib.go b/internal/use-case/main-use-case/unit/lib.go new file mode 100644 index 00000000..a185ebb9 --- /dev/null +++ b/internal/use-case/main-use-case/unit/lib.go @@ -0,0 +1,98 @@ +package unit + +import ( + e "simrs-vx/internal/domain/main-entities/unit" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.Unit, dbx ...*gorm.DB) (*e.Unit, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Unit, *e.MetaDto, error) { + data := []e.Unit{} + 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.Unit{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Unit, error) { + data := e.Unit{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.Unit, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.Unit, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/unit/tycovar.go b/internal/use-case/main-use-case/unit/tycovar.go new file mode 100644 index 00000000..410328d3 --- /dev/null +++ b/internal/use-case/main-use-case/unit/tycovar.go @@ -0,0 +1,32 @@ +/* +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 unit + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/unit" +) + +type createMw func(input *e.CreateDto, data *e.Unit, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.Unit, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error + +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 diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index 0086fa32..fbcb65f3 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -1,6 +1,7 @@ package user import ( + "errors" "fmt" e "simrs-vx/internal/domain/main-entities/user" "strconv" @@ -213,14 +214,20 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-read-detail-fail", Detail: "Database read detail failed", Raw: err, } - return pl.SetLogError(event, input) } pl.SetLogInfo(&event, nil, "complete") From a2184894968205350d26663a01d96d4dda57de26 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 20 Aug 2025 13:53:14 +0700 Subject: [PATCH 12/40] feat (unit, division-position): add preload --- .../main-entities/division-position/dto.go | 11 +++- internal/domain/main-entities/province/dto.go | 61 +++++++++++++++++++ .../domain/main-entities/province/entity.go | 6 ++ internal/domain/main-entities/unit/dto.go | 9 ++- .../main-use-case/division-position/lib.go | 1 + internal/use-case/main-use-case/unit/lib.go | 1 + 6 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 internal/domain/main-entities/province/dto.go create mode 100644 internal/domain/main-entities/province/entity.go diff --git a/internal/domain/main-entities/division-position/dto.go b/internal/domain/main-entities/division-position/dto.go index 3847d332..fd9446fc 100644 --- a/internal/domain/main-entities/division-position/dto.go +++ b/internal/domain/main-entities/division-position/dto.go @@ -2,6 +2,7 @@ package divisionposition import ( ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/division" ) type CreateDto struct { @@ -44,9 +45,10 @@ type MetaDto struct { type ResponseDto struct { ecore.SmallMain - Division_Id *uint16 `json:"division_id"` - Code string `json:"code"` - Name string `json:"name"` + Division_Id *uint16 `json:"division_id"` + Division *ed.Division `json:"division,omitempty"` + Code string `json:"code"` + Name string `json:"name"` } func (d DivisionPosition) ToResponse() ResponseDto { @@ -56,6 +58,9 @@ func (d DivisionPosition) ToResponse() ResponseDto { Name: d.Name, } resp.SmallMain = d.SmallMain + if d.Division != nil { + resp.Division = d.Division + } return resp } diff --git a/internal/domain/main-entities/province/dto.go b/internal/domain/main-entities/province/dto.go new file mode 100644 index 00000000..5fb9aae3 --- /dev/null +++ b/internal/domain/main-entities/province/dto.go @@ -0,0 +1,61 @@ +package province + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + CreateDto +} + +type DeleteDto struct { + Code string `json:"code"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + Parent_Id *int16 `json:"parent_id"` +} + +func (d Province) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + return resp +} + +func ToResponseList(users []Province) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/province/entity.go b/internal/domain/main-entities/province/entity.go new file mode 100644 index 00000000..dbe76750 --- /dev/null +++ b/internal/domain/main-entities/province/entity.go @@ -0,0 +1,6 @@ +package province + +type Province struct { + Code string `json:"code" gorm:"size:2"` + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/domain/main-entities/unit/dto.go b/internal/domain/main-entities/unit/dto.go index 0a5e8b51..5b0c3aef 100644 --- a/internal/domain/main-entities/unit/dto.go +++ b/internal/domain/main-entities/unit/dto.go @@ -2,6 +2,7 @@ package unit import ( ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/installation" ) type CreateDto struct { @@ -45,8 +46,9 @@ type MetaDto struct { type ResponseDto struct { ecore.SmallMain Installation_Id *uint16 `json:"installation_id"` - Code string `json:"code"` - Name string `json:"name"` + Installation *ei.Installation + Code string `json:"code"` + Name string `json:"name"` } func (u Unit) ToResponse() ResponseDto { @@ -56,6 +58,9 @@ func (u Unit) ToResponse() ResponseDto { Name: u.Name, } resp.SmallMain = u.SmallMain + if u.Installation != nil { + resp.Installation = u.Installation + } return resp } diff --git a/internal/use-case/main-use-case/division-position/lib.go b/internal/use-case/main-use-case/division-position/lib.go index 60648199..7b4058a6 100644 --- a/internal/use-case/main-use-case/division-position/lib.go +++ b/internal/use-case/main-use-case/division-position/lib.go @@ -40,6 +40,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.DivisionPosition, * Model(&e.DivisionPosition{}). // Joins("Patient"). // if needed // Preload("Patient"). // if needed + Preload("Division"). // if needed Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). diff --git a/internal/use-case/main-use-case/unit/lib.go b/internal/use-case/main-use-case/unit/lib.go index a185ebb9..ee4ddf1e 100644 --- a/internal/use-case/main-use-case/unit/lib.go +++ b/internal/use-case/main-use-case/unit/lib.go @@ -40,6 +40,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Unit, *e.MetaDto, e Model(&e.Unit{}). // Joins("Patient"). // if needed // Preload("Patient"). // if needed + Preload("Installation"). // if needed Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). From 5c716eb269cc6de7eced04ad5a6ed9cbb78b59bc Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 20 Aug 2025 16:51:24 +0700 Subject: [PATCH 13/40] refactor use case --- cmd/migration/migrations/20250820052409.sql | 26 -- cmd/migration/migrations/20250820055632.sql | 12 - cmd/migration/migrations/20250820061823.sql | 11 - cmd/migration/migrations/20250820062943.sql | 12 - cmd/migration/migrations/20250820083721.sql | 103 ++++ cmd/migration/migrations/atlas.sum | 7 +- internal/domain/main-entities/district/dto.go | 62 +++ .../domain/main-entities/district/entity.go | 11 + .../main-entities/division-position/entity.go | 2 +- .../domain/main-entities/division/entity.go | 2 +- .../main-entities/installation/entity.go | 2 +- internal/domain/main-entities/province/dto.go | 20 +- .../domain/main-entities/province/entity.go | 8 +- internal/domain/main-entities/regency/dto.go | 62 +++ .../domain/main-entities/regency/entity.go | 11 + internal/domain/main-entities/unit/entity.go | 2 +- internal/domain/main-entities/village/dto.go | 59 +++ .../domain/main-entities/village/entity.go | 8 + .../main-handler/district/handler.go | 71 +++ .../interface/main-handler/main-handler.go | 10 + .../main-handler/province/handler.go | 71 +++ .../interface/main-handler/regency/handler.go | 71 +++ .../interface/main-handler/village/handler.go | 71 +++ internal/interface/migration/migration.go | 28 +- .../use-case/main-use-case/district/case.go | 430 +++++++++++++++++ .../use-case/main-use-case/district/helper.go | 23 + .../use-case/main-use-case/district/lib.go | 97 ++++ .../main-use-case/district/tycovar.go | 32 ++ .../main-use-case/division-position/case.go | 46 +- .../use-case/main-use-case/division/case.go | 44 +- .../main-use-case/installation/case.go | 44 +- .../use-case/main-use-case/province/case.go | 431 +++++++++++++++++ .../use-case/main-use-case/province/helper.go | 22 + .../use-case/main-use-case/province/lib.go | 97 ++++ .../main-use-case/province/tycovar.go | 32 ++ .../use-case/main-use-case/regency/case.go | 431 +++++++++++++++++ .../use-case/main-use-case/regency/helper.go | 29 ++ .../use-case/main-use-case/regency/lib.go | 97 ++++ .../use-case/main-use-case/regency/tycovar.go | 32 ++ internal/use-case/main-use-case/unit/case.go | 45 +- internal/use-case/main-use-case/user/case.go | 46 +- .../use-case/main-use-case/village/case.go | 439 ++++++++++++++++++ .../use-case/main-use-case/village/helper.go | 22 + .../use-case/main-use-case/village/lib.go | 97 ++++ .../use-case/main-use-case/village/tycovar.go | 32 ++ pkg/use-case-helper/use-case-helper.go | 48 ++ 46 files changed, 3080 insertions(+), 278 deletions(-) delete mode 100644 cmd/migration/migrations/20250820052409.sql delete mode 100644 cmd/migration/migrations/20250820055632.sql delete mode 100644 cmd/migration/migrations/20250820061823.sql delete mode 100644 cmd/migration/migrations/20250820062943.sql create mode 100644 cmd/migration/migrations/20250820083721.sql create mode 100644 internal/domain/main-entities/district/dto.go create mode 100644 internal/domain/main-entities/district/entity.go create mode 100644 internal/domain/main-entities/regency/dto.go create mode 100644 internal/domain/main-entities/regency/entity.go create mode 100644 internal/domain/main-entities/village/dto.go create mode 100644 internal/domain/main-entities/village/entity.go create mode 100644 internal/interface/main-handler/district/handler.go create mode 100644 internal/interface/main-handler/province/handler.go create mode 100644 internal/interface/main-handler/regency/handler.go create mode 100644 internal/interface/main-handler/village/handler.go create mode 100644 internal/use-case/main-use-case/district/case.go create mode 100644 internal/use-case/main-use-case/district/helper.go create mode 100644 internal/use-case/main-use-case/district/lib.go create mode 100644 internal/use-case/main-use-case/district/tycovar.go create mode 100644 internal/use-case/main-use-case/province/case.go create mode 100644 internal/use-case/main-use-case/province/helper.go create mode 100644 internal/use-case/main-use-case/province/lib.go create mode 100644 internal/use-case/main-use-case/province/tycovar.go create mode 100644 internal/use-case/main-use-case/regency/case.go create mode 100644 internal/use-case/main-use-case/regency/helper.go create mode 100644 internal/use-case/main-use-case/regency/lib.go create mode 100644 internal/use-case/main-use-case/regency/tycovar.go create mode 100644 internal/use-case/main-use-case/village/case.go create mode 100644 internal/use-case/main-use-case/village/helper.go create mode 100644 internal/use-case/main-use-case/village/lib.go create mode 100644 internal/use-case/main-use-case/village/tycovar.go create mode 100644 pkg/use-case-helper/use-case-helper.go diff --git a/cmd/migration/migrations/20250820052409.sql b/cmd/migration/migrations/20250820052409.sql deleted file mode 100644 index b3df477e..00000000 --- a/cmd/migration/migrations/20250820052409.sql +++ /dev/null @@ -1,26 +0,0 @@ --- Create "Division" table -CREATE TABLE "public"."Division" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - "Parent_Id" smallint NULL, - PRIMARY KEY ("Id") -); --- Create "User" table -CREATE TABLE "public"."User" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Name" character varying(25) NOT NULL, - "Password" character varying(255) NOT NULL, - "Status_Code" character varying(10) NOT NULL, - "FailedLoginCount" smallint NULL, - "LoginAttemptCount" bigint NULL, - "LastSuccessLogin" timestamptz NULL, - "LastAllowdLogin" timestamptz NULL, - PRIMARY KEY ("Id") -); diff --git a/cmd/migration/migrations/20250820055632.sql b/cmd/migration/migrations/20250820055632.sql deleted file mode 100644 index 9e9369be..00000000 --- a/cmd/migration/migrations/20250820055632.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Create "DivisionPosition" table -CREATE TABLE "public"."DivisionPosition" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Division_Id" integer NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_DivisionPosition_Division" FOREIGN KEY ("Division_Id") REFERENCES "public"."Division" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); diff --git a/cmd/migration/migrations/20250820061823.sql b/cmd/migration/migrations/20250820061823.sql deleted file mode 100644 index cd50b42b..00000000 --- a/cmd/migration/migrations/20250820061823.sql +++ /dev/null @@ -1,11 +0,0 @@ --- Create "Installation" table -CREATE TABLE "public"."Installation" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - "EncounterClass_Code" character varying(10) NULL, - PRIMARY KEY ("Id") -); diff --git a/cmd/migration/migrations/20250820062943.sql b/cmd/migration/migrations/20250820062943.sql deleted file mode 100644 index 36a3046b..00000000 --- a/cmd/migration/migrations/20250820062943.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Create "Unit" table -CREATE TABLE "public"."Unit" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Installation_Id" integer NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_Unit_Installation" FOREIGN KEY ("Installation_Id") REFERENCES "public"."Installation" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); diff --git a/cmd/migration/migrations/20250820083721.sql b/cmd/migration/migrations/20250820083721.sql new file mode 100644 index 00000000..cee52edc --- /dev/null +++ b/cmd/migration/migrations/20250820083721.sql @@ -0,0 +1,103 @@ +-- Create "Province" table +CREATE TABLE "public"."Province" ( + "Id" smallserial NOT NULL, + "Code" character varying(2) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Province_Code" UNIQUE ("Code") +); +-- Create "User" table +CREATE TABLE "public"."User" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Name" character varying(25) NOT NULL, + "Password" character varying(255) NOT NULL, + "Status_Code" character varying(10) NOT NULL, + "FailedLoginCount" smallint NULL, + "LoginAttemptCount" bigint NULL, + "LastSuccessLogin" timestamptz NULL, + "LastAllowdLogin" timestamptz NULL, + PRIMARY KEY ("Id") +); +-- Create "Regency" table +CREATE TABLE "public"."Regency" ( + "Id" serial NOT NULL, + "Province_Code" character varying(2) NULL, + "Code" character varying(4) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Regency_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Province_Regencies" FOREIGN KEY ("Province_Code") REFERENCES "public"."Province" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "District" table +CREATE TABLE "public"."District" ( + "Id" bigserial NOT NULL, + "Regency_Code" character varying(4) NULL, + "Code" character varying(6) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_District_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Regency_Districts" FOREIGN KEY ("Regency_Code") REFERENCES "public"."Regency" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Division" table +CREATE TABLE "public"."Division" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "Parent_Id" smallint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Division_Code" UNIQUE ("Code") +); +-- Create "DivisionPosition" table +CREATE TABLE "public"."DivisionPosition" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Division_Id" integer NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_DivisionPosition_Code" UNIQUE ("Code"), + CONSTRAINT "fk_DivisionPosition_Division" FOREIGN KEY ("Division_Id") REFERENCES "public"."Division" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Installation" table +CREATE TABLE "public"."Installation" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "EncounterClass_Code" character varying(10) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Installation_Code" UNIQUE ("Code") +); +-- Create "Unit" table +CREATE TABLE "public"."Unit" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Installation_Id" integer NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Unit_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Unit_Installation" FOREIGN KEY ("Installation_Id") REFERENCES "public"."Installation" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Village" table +CREATE TABLE "public"."Village" ( + "Id" bigserial NOT NULL, + "District_Code" character varying(6) NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Village_Code" UNIQUE ("Code"), + CONSTRAINT "fk_District_Villages" FOREIGN KEY ("District_Code") REFERENCES "public"."District" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index a6638e1e..b94d1d8d 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,5 +1,2 @@ -h1:sflrLy3WNiI1HdFXmrmyufKJOFz2lUT1ElPaNRU+uCo= -20250820052409.sql h1:W2zifi3eF+hG0fHvIrY15dH82WO/4QPGdZOEUkgKlAg= -20250820055632.sql h1:sPoDUmT4aZV4qiaq63ssIcoevr3N2WAjRcU1c+Kz6kc= -20250820061823.sql h1:mj37CorTCwngLSo5PRKGC3Wy4I4IapmNXaJGgGxU6y4= -20250820062943.sql h1:Cr8vZGsdJ8Bh+ZKGVAmEh+4rnsjgt5eIy3lExpE4etc= +h1:BeM3qkN2alMJypXIeFt15SbwthvdFivDIoB6gVZayPM= +20250820083721.sql h1:I3MicNCsXGQJLAWD6axmyvjKZHEObHbF5WKfhQf1ijQ= diff --git a/internal/domain/main-entities/district/dto.go b/internal/domain/main-entities/district/dto.go new file mode 100644 index 00000000..156d97b3 --- /dev/null +++ b/internal/domain/main-entities/district/dto.go @@ -0,0 +1,62 @@ +package district + +import ev "simrs-vx/internal/domain/main-entities/village" + +type CreateDto struct { + Regency_Code string `json:"regency_code" validate:"numeric;maxLength=4"` + Code string `json:"code" validate:"numeric;maxLength=6"` + Name string `json:"name" validate:"alphaSpace;maxLength=50"` +} + +type ReadListDto struct { + Regency_Code string `json:"regency_code"` + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint32 `json:"id"` + Regency_Code string `json:"regency_code"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint32 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint32 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + Id uint32 `json:"id"` + Regency_Code string `json:"regency_code"` + Code string `json:"code"` + Name string `json:"name"` + Villages []*ev.Village `json:"villages,omitempty"` +} + +func (d District) ToResponse() ResponseDto { + resp := ResponseDto(d) + return resp +} + +func ToResponseList(users []District) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/district/entity.go b/internal/domain/main-entities/district/entity.go new file mode 100644 index 00000000..a3ad27e7 --- /dev/null +++ b/internal/domain/main-entities/district/entity.go @@ -0,0 +1,11 @@ +package district + +import ev "simrs-vx/internal/domain/main-entities/village" + +type District struct { + Id uint32 `json:"id" gorm:"primaryKey"` + Regency_Code string `json:"regency_code" gorm:"size:4"` + Code string `json:"code" gorm:"unique;size:6"` // NOTE: THE PROPER SIZE IS 6 + Name string `json:"name" gorm:"size:50"` + Villages []*ev.Village `json:"villages,omitempty" gorm:"foreignKey:District_Code;references:Code"` +} diff --git a/internal/domain/main-entities/division-position/entity.go b/internal/domain/main-entities/division-position/entity.go index 88311e96..6ff32055 100644 --- a/internal/domain/main-entities/division-position/entity.go +++ b/internal/domain/main-entities/division-position/entity.go @@ -9,6 +9,6 @@ type DivisionPosition struct { ecore.SmallMain // adjust this according to the needs Division_Id *uint16 `json:"division_id"` Division *ed.Division `json:"division" gorm:"foreignKey:Division_Id"` - Code string `json:"code" gorm:"size:10"` + Code string `json:"code" gorm:"unique;size:10"` Name string `json:"name" gorm:"size:50"` } diff --git a/internal/domain/main-entities/division/entity.go b/internal/domain/main-entities/division/entity.go index 55918a8d..7d3bc65d 100644 --- a/internal/domain/main-entities/division/entity.go +++ b/internal/domain/main-entities/division/entity.go @@ -6,7 +6,7 @@ import ( type Division struct { ecore.SmallMain // adjust this according to the needs - Code string `json:"code" gorm:"size:10"` + Code string `json:"code" gorm:"unique;size:10"` Name string `json:"name" gorm:"size:50"` Parent_Id *int16 `json:"parent_id"` } diff --git a/internal/domain/main-entities/installation/entity.go b/internal/domain/main-entities/installation/entity.go index 84159810..203b231c 100644 --- a/internal/domain/main-entities/installation/entity.go +++ b/internal/domain/main-entities/installation/entity.go @@ -7,7 +7,7 @@ import ( type Installation struct { ecore.SmallMain // adjust this according to the needs - Code string `json:"code" gorm:"size:10"` + Code string `json:"code" gorm:"unique;size:10"` Name string `json:"name" gorm:"size:50"` EncounterClass_Code ere.EncounterClass `json:"encounterClass_code" gorm:"size:10"` } diff --git a/internal/domain/main-entities/province/dto.go b/internal/domain/main-entities/province/dto.go index 5fb9aae3..c1b771fa 100644 --- a/internal/domain/main-entities/province/dto.go +++ b/internal/domain/main-entities/province/dto.go @@ -1,12 +1,8 @@ package province -import ( - ecore "simrs-vx/internal/domain/base-entities/core" -) - type CreateDto struct { - Code string `json:"code"` - Name string `json:"name"` + Code string `json:"code" validate:"required;minLength=2;maxLength=2"` + Name string `json:"name" validate:"required;maxLength=10"` } type ReadListDto struct { @@ -19,16 +15,18 @@ type ReadListDto struct { } type ReadDetailDto struct { + Id int16 `json:"id"` Code string `json:"code"` Name string `json:"name"` } type UpdateDto struct { + Id int16 `json:"id"` CreateDto } type DeleteDto struct { - Code string `json:"code"` + Id int16 `json:"id"` } type MetaDto struct { @@ -38,14 +36,14 @@ type MetaDto struct { } type ResponseDto struct { - ecore.SmallMain - Code string `json:"code"` - Name string `json:"name"` - Parent_Id *int16 `json:"parent_id"` + Id int16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` } func (d Province) ToResponse() ResponseDto { resp := ResponseDto{ + Id: d.Id, Code: d.Code, Name: d.Name, } diff --git a/internal/domain/main-entities/province/entity.go b/internal/domain/main-entities/province/entity.go index dbe76750..ab024b22 100644 --- a/internal/domain/main-entities/province/entity.go +++ b/internal/domain/main-entities/province/entity.go @@ -1,6 +1,10 @@ package province +import er "simrs-vx/internal/domain/main-entities/regency" + type Province struct { - Code string `json:"code" gorm:"size:2"` - Name string `json:"name" gorm:"size:50"` + Id int16 `json:"id" gorm:"primaryKey"` + Code string `json:"code" gorm:"unique;size:2"` + Name string `json:"name" gorm:"size:50"` + Regencies []*er.Regency `json:"regencies,omitempty" gorm:"foreignKey:Province_Code;references:Code"` } diff --git a/internal/domain/main-entities/regency/dto.go b/internal/domain/main-entities/regency/dto.go new file mode 100644 index 00000000..56cc0a76 --- /dev/null +++ b/internal/domain/main-entities/regency/dto.go @@ -0,0 +1,62 @@ +package regency + +import ed "simrs-vx/internal/domain/main-entities/district" + +type CreateDto struct { + Province_Code string `json:"province_code" validate:"numeric;maxLength=2"` + Code string `json:"code" validate:"numeric;maxLength=4"` + Name string `json:"name" validate:"alphaSpace;maxLength=50"` +} + +type ReadListDto struct { + Province_Code string `json:"province_code"` + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Province_Code string `json:"province_code"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + Id uint16 `json:"id"` + Province_Code string `json:"province_code"` + Code string `json:"code"` + Name string `json:"name"` + Districts []*ed.District `json:"districts,omitempty"` +} + +func (r Regency) ToResponse() ResponseDto { + resp := ResponseDto(r) + return resp +} + +func ToResponseList(users []Regency) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/regency/entity.go b/internal/domain/main-entities/regency/entity.go new file mode 100644 index 00000000..3bdcf934 --- /dev/null +++ b/internal/domain/main-entities/regency/entity.go @@ -0,0 +1,11 @@ +package regency + +import ed "simrs-vx/internal/domain/main-entities/district" + +type Regency struct { + Id uint16 `json:"id" gorm:"primaryKey"` + Province_Code string `json:"province_code" gorm:"size:2"` + Code string `json:"code" gorm:"unique;size:4"` + Name string `json:"name" gorm:"size:50"` + Districts []*ed.District `json:"districts,omitempty" gorm:"foreignKey:Regency_Code;references:Code"` +} diff --git a/internal/domain/main-entities/unit/entity.go b/internal/domain/main-entities/unit/entity.go index 3953692f..3b93475f 100644 --- a/internal/domain/main-entities/unit/entity.go +++ b/internal/domain/main-entities/unit/entity.go @@ -9,6 +9,6 @@ type Unit struct { ecore.SmallMain // adjust this according to the needs Installation_Id *uint16 `json:"installation_id"` Installation *ei.Installation `json:"installation" gorm:"foreignKey:Installation_Id"` - Code string `json:"code" gorm:"size:10"` + Code string `json:"code" gorm:"unique;size:10"` Name string `json:"name" gorm:"size:50"` } diff --git a/internal/domain/main-entities/village/dto.go b/internal/domain/main-entities/village/dto.go new file mode 100644 index 00000000..750a382c --- /dev/null +++ b/internal/domain/main-entities/village/dto.go @@ -0,0 +1,59 @@ +package village + +type CreateDto struct { + District_Code string `json:"district_code" validate:"numeric;maxLength=6"` + Code string `json:"code" validate:"numeric;maxLength=10"` + Name string `json:"name" validate:"alphaSpace;maxLength=50"` +} + +type ReadListDto struct { + District_Code string `json:"district_code"` + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint32 `json:"id"` + District_Code string `json:"district_code"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint32 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint32 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + Id uint32 `json:"id"` + District_Code string `json:"district_code"` + Code string `json:"code"` + Name string `json:"name"` +} + +func (v Village) ToResponse() ResponseDto { + resp := ResponseDto(v) + return resp +} + +func ToResponseList(users []Village) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/village/entity.go b/internal/domain/main-entities/village/entity.go new file mode 100644 index 00000000..aae0caf5 --- /dev/null +++ b/internal/domain/main-entities/village/entity.go @@ -0,0 +1,8 @@ +package village + +type Village struct { + Id uint32 `json:"id" gorm:"primaryKey"` + District_Code string `json:"district_code" gorm:"size:6"` // NOT: THE PROPER SIZE IS 6 + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/interface/main-handler/district/handler.go b/internal/interface/main-handler/district/handler.go new file mode 100644 index 00000000..bdba5d96 --- /dev/null +++ b/internal/interface/main-handler/district/handler.go @@ -0,0 +1,71 @@ +package district + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/district" + u "simrs-vx/internal/use-case/main-use-case/district" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint32(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint32(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint32(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 6659b264..d066f8ff 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -27,6 +27,11 @@ import ( installation "simrs-vx/internal/interface/main-handler/installation" unit "simrs-vx/internal/interface/main-handler/unit" + district "simrs-vx/internal/interface/main-handler/district" + province "simrs-vx/internal/interface/main-handler/province" + regency "simrs-vx/internal/interface/main-handler/regency" + village "simrs-vx/internal/interface/main-handler/village" + ///// Internal "simrs-vx/internal/interface/main-handler/home" ) @@ -55,6 +60,11 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/installation", installation.O) hc.RegCrud(r, "/v1/unit", unit.O) + hc.RegCrud(r, "/v1/village", village.O) + hc.RegCrud(r, "/v1/district", district.O) + hc.RegCrud(r, "/v1/regency", regency.O) + hc.RegCrud(r, "/v1/province", province.O) + ///// return cmw.SetCors(handlerlogger.SetLog(r)) } diff --git a/internal/interface/main-handler/province/handler.go b/internal/interface/main-handler/province/handler.go new file mode 100644 index 00000000..f95aec2e --- /dev/null +++ b/internal/interface/main-handler/province/handler.go @@ -0,0 +1,71 @@ +package province + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/province" + u "simrs-vx/internal/use-case/main-use-case/province" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = int16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = int16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = int16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/regency/handler.go b/internal/interface/main-handler/regency/handler.go new file mode 100644 index 00000000..e6170867 --- /dev/null +++ b/internal/interface/main-handler/regency/handler.go @@ -0,0 +1,71 @@ +package regency + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/regency" + u "simrs-vx/internal/use-case/main-use-case/regency" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/village/handler.go b/internal/interface/main-handler/village/handler.go new file mode 100644 index 00000000..76138e72 --- /dev/null +++ b/internal/interface/main-handler/village/handler.go @@ -0,0 +1,71 @@ +package village + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/village" + u "simrs-vx/internal/use-case/main-use-case/village" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint32(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint32(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint32(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 723d097e..4f962b4b 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -5,11 +5,15 @@ import ( "io" "os" "os/exec" - ed "simrs-vx/internal/domain/main-entities/division" - edp "simrs-vx/internal/domain/main-entities/division-position" - ei "simrs-vx/internal/domain/main-entities/installation" - eun "simrs-vx/internal/domain/main-entities/unit" - eu "simrs-vx/internal/domain/main-entities/user" + district "simrs-vx/internal/domain/main-entities/district" + division "simrs-vx/internal/domain/main-entities/division" + divisionposition "simrs-vx/internal/domain/main-entities/division-position" + installation "simrs-vx/internal/domain/main-entities/installation" + province "simrs-vx/internal/domain/main-entities/province" + regency "simrs-vx/internal/domain/main-entities/regency" + unit "simrs-vx/internal/domain/main-entities/unit" + user "simrs-vx/internal/domain/main-entities/user" + village "simrs-vx/internal/domain/main-entities/village" "ariga.io/atlas-provider-gorm/gormschema" "gorm.io/gorm" @@ -44,11 +48,15 @@ func Loader() { func GetEntities() []any { return []any{ - &eu.User{}, - &ed.Division{}, - &edp.DivisionPosition{}, - &ei.Installation{}, - &eun.Unit{}, + &user.User{}, + &division.Division{}, + &divisionposition.DivisionPosition{}, + &installation.Installation{}, + &unit.Unit{}, + &village.Village{}, + &district.District{}, + ®ency.Regency{}, + &province.Province{}, } } diff --git a/internal/use-case/main-use-case/district/case.go b/internal/use-case/main-use-case/district/case.go new file mode 100644 index 00000000..c5f16ca9 --- /dev/null +++ b/internal/use-case/main-use-case/district/case.go @@ -0,0 +1,430 @@ +package district + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/district" + "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" +) + +const source = "district" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.District{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.District + var dataList []e.District + 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 { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + 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": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.District + 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 { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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: pu.SafeToResponse(data), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.District + 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") + data, err = ReadDetailData(rdDto, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); 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") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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.District + 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") + data, err = ReadDetailData(rdDto, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); 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") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/district/helper.go b/internal/use-case/main-use-case/district/helper.go new file mode 100644 index 00000000..3959233c --- /dev/null +++ b/internal/use-case/main-use-case/district/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package district + +import ( + e "simrs-vx/internal/domain/main-entities/district" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.District) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Regency_Code = inputSrc.Regency_Code + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/district/lib.go b/internal/use-case/main-use-case/district/lib.go new file mode 100644 index 00000000..402cae63 --- /dev/null +++ b/internal/use-case/main-use-case/district/lib.go @@ -0,0 +1,97 @@ +package district + +import ( + e "simrs-vx/internal/domain/main-entities/district" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.District, dbx ...*gorm.DB) (*e.District, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.District, *e.MetaDto, error) { + data := []e.District{} + 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.District{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)) + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.District, error) { + data := e.District{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.District, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.District, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/district/tycovar.go b/internal/use-case/main-use-case/district/tycovar.go new file mode 100644 index 00000000..99670a00 --- /dev/null +++ b/internal/use-case/main-use-case/district/tycovar.go @@ -0,0 +1,32 @@ +/* +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 district + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/district" +) + +type createMw func(input *e.CreateDto, data *e.District, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.District, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.District, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.District, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.District, tx *gorm.DB) error + +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 diff --git a/internal/use-case/main-use-case/division-position/case.go b/internal/use-case/main-use-case/division-position/case.go index 2749ca1b..7d00343e 100644 --- a/internal/use-case/main-use-case/division-position/case.go +++ b/internal/use-case/main-use-case/division-position/case.go @@ -1,7 +1,6 @@ package divisionposition import ( - "errors" "fmt" e "simrs-vx/internal/domain/main-entities/division-position" "strconv" @@ -10,6 +9,7 @@ import ( d "github.com/karincake/dodol" pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" ) @@ -214,24 +214,10 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if errors.Is(err, gorm.ErrRecordNotFound) { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-notFound", - Detail: fmt.Sprintf("Data with ID %v not found", input.Id), - Raw: err, - } - } else { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - for i := range readDetailPostMw { mwName := fmt.Sprintf("readDetailPostMw[%d]", i) @@ -263,7 +249,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: data.ToResponse(), + Data: pu.SafeToResponse(data), }, nil } @@ -283,17 +269,9 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - - pl.SetLogInfo(&event, input, "started", "setUpdate") setData(&input, data) for i := range updatePreMw { @@ -379,18 +357,10 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - for i := range deletePreMw { mwName := fmt.Sprintf("deletePreMw[%d]", i) diff --git a/internal/use-case/main-use-case/division/case.go b/internal/use-case/main-use-case/division/case.go index dfd9d985..3333d61b 100644 --- a/internal/use-case/main-use-case/division/case.go +++ b/internal/use-case/main-use-case/division/case.go @@ -1,7 +1,6 @@ package division import ( - "errors" "fmt" e "simrs-vx/internal/domain/main-entities/division" "strconv" @@ -10,6 +9,7 @@ import ( d "github.com/karincake/dodol" pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" ) @@ -214,24 +214,10 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if errors.Is(err, gorm.ErrRecordNotFound) { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-notFound", - Detail: fmt.Sprintf("Data with ID %v not found", input.Id), - Raw: err, - } - } else { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - for i := range readDetailPostMw { mwName := fmt.Sprintf("readDetailPostMw[%d]", i) @@ -263,7 +249,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: data.ToResponse(), + Data: pu.SafeToResponse(data), }, nil } @@ -283,14 +269,8 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } pl.SetLogInfo(&event, input, "started", "setUpdate") @@ -379,18 +359,10 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - for i := range deletePreMw { mwName := fmt.Sprintf("deletePreMw[%d]", i) diff --git a/internal/use-case/main-use-case/installation/case.go b/internal/use-case/main-use-case/installation/case.go index 9a2689ec..e12186f6 100644 --- a/internal/use-case/main-use-case/installation/case.go +++ b/internal/use-case/main-use-case/installation/case.go @@ -1,7 +1,6 @@ package installation import ( - "errors" "fmt" e "simrs-vx/internal/domain/main-entities/installation" "strconv" @@ -10,6 +9,7 @@ import ( d "github.com/karincake/dodol" pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" ) @@ -214,24 +214,10 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if errors.Is(err, gorm.ErrRecordNotFound) { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-notFound", - Detail: fmt.Sprintf("Data with ID %v not found", input.Id), - Raw: err, - } - } else { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - for i := range readDetailPostMw { mwName := fmt.Sprintf("readDetailPostMw[%d]", i) @@ -263,7 +249,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: data.ToResponse(), + Data: pu.SafeToResponse(data), }, nil } @@ -283,14 +269,8 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } pl.SetLogInfo(&event, input, "started", "setUpdate") @@ -379,18 +359,10 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - for i := range deletePreMw { mwName := fmt.Sprintf("deletePreMw[%d]", i) diff --git a/internal/use-case/main-use-case/province/case.go b/internal/use-case/main-use-case/province/case.go new file mode 100644 index 00000000..758f4c18 --- /dev/null +++ b/internal/use-case/main-use-case/province/case.go @@ -0,0 +1,431 @@ +package province + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/province" + "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" +) + +const source = "province" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Province{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Province + var dataList []e.Province + 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 { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + 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": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Province + 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 { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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: pu.SafeToResponse(data), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Province + 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") + data, err = ReadDetailData(rdDto, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); 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") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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.Province + 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") + data, err = ReadDetailData(rdDto, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); 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") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/province/helper.go b/internal/use-case/main-use-case/province/helper.go new file mode 100644 index 00000000..62774538 --- /dev/null +++ b/internal/use-case/main-use-case/province/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package province + +import ( + e "simrs-vx/internal/domain/main-entities/province" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Province) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/province/lib.go b/internal/use-case/main-use-case/province/lib.go new file mode 100644 index 00000000..df44515b --- /dev/null +++ b/internal/use-case/main-use-case/province/lib.go @@ -0,0 +1,97 @@ +package province + +import ( + e "simrs-vx/internal/domain/main-entities/province" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.Province, dbx ...*gorm.DB) (*e.Province, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Province, *e.MetaDto, error) { + data := []e.Province{} + 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.Province{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)) + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Province, error) { + data := e.Province{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.Province, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.Province, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/province/tycovar.go b/internal/use-case/main-use-case/province/tycovar.go new file mode 100644 index 00000000..e65ab008 --- /dev/null +++ b/internal/use-case/main-use-case/province/tycovar.go @@ -0,0 +1,32 @@ +/* +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 province + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/province" +) + +type createMw func(input *e.CreateDto, data *e.Province, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.Province, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.Province, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.Province, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.Province, tx *gorm.DB) error + +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 diff --git a/internal/use-case/main-use-case/regency/case.go b/internal/use-case/main-use-case/regency/case.go new file mode 100644 index 00000000..deabdc4c --- /dev/null +++ b/internal/use-case/main-use-case/regency/case.go @@ -0,0 +1,431 @@ +package regency + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/regency" + "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" +) + +const source = "regency" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Regency{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Regency + var dataList []e.Regency + 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 { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + 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": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Regency + 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 { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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: pu.SafeToResponse(data), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Regency + 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") + data, err = ReadDetailData(rdDto, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); 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") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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.Regency + 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") + data, err = ReadDetailData(rdDto, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); 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") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/regency/helper.go b/internal/use-case/main-use-case/regency/helper.go new file mode 100644 index 00000000..aa867cf0 --- /dev/null +++ b/internal/use-case/main-use-case/regency/helper.go @@ -0,0 +1,29 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package regency + +import ( + e "simrs-vx/internal/domain/main-entities/regency" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Regency) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + data.Province_Code = inputSrc.Province_Code + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} + +func toResponseOrNil(data interface{ ToResponse() any }) any { + if data == nil { + return nil + } + return data.ToResponse() +} diff --git a/internal/use-case/main-use-case/regency/lib.go b/internal/use-case/main-use-case/regency/lib.go new file mode 100644 index 00000000..67bb1a17 --- /dev/null +++ b/internal/use-case/main-use-case/regency/lib.go @@ -0,0 +1,97 @@ +package regency + +import ( + e "simrs-vx/internal/domain/main-entities/regency" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.Regency, dbx ...*gorm.DB) (*e.Regency, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Regency, *e.MetaDto, error) { + data := []e.Regency{} + 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.Regency{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)) + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Regency, error) { + data := e.Regency{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.Regency, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.Regency, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/regency/tycovar.go b/internal/use-case/main-use-case/regency/tycovar.go new file mode 100644 index 00000000..711d0831 --- /dev/null +++ b/internal/use-case/main-use-case/regency/tycovar.go @@ -0,0 +1,32 @@ +/* +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 regency + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/regency" +) + +type createMw func(input *e.CreateDto, data *e.Regency, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.Regency, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.Regency, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.Regency, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.Regency, tx *gorm.DB) error + +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 diff --git a/internal/use-case/main-use-case/unit/case.go b/internal/use-case/main-use-case/unit/case.go index 37082abf..78f86cc5 100644 --- a/internal/use-case/main-use-case/unit/case.go +++ b/internal/use-case/main-use-case/unit/case.go @@ -1,7 +1,6 @@ package unit import ( - "errors" "fmt" e "simrs-vx/internal/domain/main-entities/unit" "strconv" @@ -10,6 +9,7 @@ import ( d "github.com/karincake/dodol" pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" ) @@ -214,24 +214,9 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if errors.Is(err, gorm.ErrRecordNotFound) { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-notFound", - Detail: fmt.Sprintf("Data with ID %v not found", input.Id), - Raw: err, - } - } else { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - return pl.SetLogError(event, input) - - pl.SetLogInfo(&event, nil, "complete") for i := range readDetailPostMw { mwName := fmt.Sprintf("readDetailPostMw[%d]", i) @@ -264,7 +249,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: data.ToResponse(), + Data: pu.SafeToResponse(data), }, nil } @@ -284,14 +269,8 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } pl.SetLogInfo(&event, input, "started", "setUpdate") @@ -380,18 +359,10 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - for i := range deletePreMw { mwName := fmt.Sprintf("deletePreMw[%d]", i) diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index fbcb65f3..0f901af9 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -1,7 +1,6 @@ package user import ( - "errors" "fmt" e "simrs-vx/internal/domain/main-entities/user" "strconv" @@ -10,6 +9,7 @@ import ( d "github.com/karincake/dodol" pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" ) @@ -214,24 +214,10 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if errors.Is(err, gorm.ErrRecordNotFound) { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-notFound", - Detail: fmt.Sprintf("Data with ID %v not found", input.Id), - Raw: err, - } - } else { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - for i := range readDetailPostMw { mwName := fmt.Sprintf("readDetailPostMw[%d]", i) @@ -263,7 +249,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: data.ToResponse(), + Data: pu.SafeToResponse(data), }, nil } @@ -283,18 +269,10 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - pl.SetLogInfo(&event, input, "started", "setUpdate") err = setUpdate(input, data) if err != nil { @@ -392,18 +370,10 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr } - pl.SetLogInfo(&event, nil, "complete") - for i := range deletePreMw { mwName := fmt.Sprintf("deletePreMw[%d]", i) diff --git a/internal/use-case/main-use-case/village/case.go b/internal/use-case/main-use-case/village/case.go new file mode 100644 index 00000000..dbcc501a --- /dev/null +++ b/internal/use-case/main-use-case/village/case.go @@ -0,0 +1,439 @@ +package village + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/village" + "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" +) + +const source = "village" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Village{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Village + var dataList []e.Village + 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 { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + 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": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Village + 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 { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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: pu.SafeToResponse(data), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Village + 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") + data, err = ReadDetailData(rdDto, tx) + if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { + return processedErr + } + + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); 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") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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.Village + 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") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); 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") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + 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": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/village/helper.go b/internal/use-case/main-use-case/village/helper.go new file mode 100644 index 00000000..bc50fd04 --- /dev/null +++ b/internal/use-case/main-use-case/village/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package village + +import ( + e "simrs-vx/internal/domain/main-entities/village" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Village) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + data.District_Code = inputSrc.District_Code + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/village/lib.go b/internal/use-case/main-use-case/village/lib.go new file mode 100644 index 00000000..aec8e05a --- /dev/null +++ b/internal/use-case/main-use-case/village/lib.go @@ -0,0 +1,97 @@ +package village + +import ( + e "simrs-vx/internal/domain/main-entities/village" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.Village, dbx ...*gorm.DB) (*e.Village, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Village, *e.MetaDto, error) { + data := []e.Village{} + 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.Village{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)) + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Village, error) { + data := e.Village{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.Village, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.Village, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/village/tycovar.go b/internal/use-case/main-use-case/village/tycovar.go new file mode 100644 index 00000000..e1aa31c5 --- /dev/null +++ b/internal/use-case/main-use-case/village/tycovar.go @@ -0,0 +1,32 @@ +/* +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 village + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/village" +) + +type createMw func(input *e.CreateDto, data *e.Village, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.Village, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.Village, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.Village, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.Village, tx *gorm.DB) error + +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 diff --git a/pkg/use-case-helper/use-case-helper.go b/pkg/use-case-helper/use-case-helper.go new file mode 100644 index 00000000..20550048 --- /dev/null +++ b/pkg/use-case-helper/use-case-helper.go @@ -0,0 +1,48 @@ +package usecasehelper + +import ( + "errors" + "fmt" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +func SafeToResponse[T any](data *T) any { + if data == nil { + return nil + } + + // Use type assertion to call ToResponse if the type has it + if converter, ok := any(data).(interface{ ToResponse() any }); ok { + return converter.ToResponse() + } + + return nil +} + +func HandleReadError(err error, event *pl.Event, itemType string, id interface{}, data any) error { + if err == nil { + pl.SetLogInfo(event, data, "complete") + return nil + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("%s with ID %v not found", itemType, id), + Raw: err, + } + } else { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: fmt.Sprintf("%s read failed", itemType), + Raw: err, + } + } + + return pl.SetLogError(*event, nil) +} From 7a032ff51843b1c173c282e1a259c46b83e73033 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 21 Aug 2025 16:24:48 +0700 Subject: [PATCH 14/40] refactor mw example --- internal/use-case/main-use-case/user/case.go | 198 ++++-------------- .../use-case/main-use-case/user/helper.go | 104 +++++++++ .../use-case/main-use-case/user/middleware.go | 159 ++++++++++++++ pkg/use-case-helper/tycovar.go | 8 + pkg/use-case-helper/use-case-helper.go | 8 + 5 files changed, 324 insertions(+), 153 deletions(-) create mode 100644 internal/use-case/main-use-case/user/middleware.go create mode 100644 pkg/use-case-helper/tycovar.go diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index 0f901af9..c125afd0 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -1,7 +1,6 @@ package user import ( - "fmt" e "simrs-vx/internal/domain/main-entities/user" "strconv" @@ -30,22 +29,12 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, data, "started", "DBCreate") @@ -62,19 +51,10 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,22 +91,12 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } pl.SetLogInfo(&event, input, "started", "DBReadList") @@ -143,22 +113,10 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,22 +152,12 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } pl.SetLogInfo(&event, input, "started", "DBReadDetail") @@ -218,22 +166,10 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { return processedErr } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -287,22 +223,12 @@ func Update(input e.UpdateDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } pl.SetLogInfo(&event, data, "started", "DBUpdate") @@ -318,22 +244,10 @@ func Update(input e.UpdateDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil @@ -374,22 +288,12 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return processedErr } - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) + executor := newMiddlewareExecutor(&event, tx) + executor.setMwtype(pu.MWTPre) - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + // Execute pre-middleware + if err := executor.ExecuteDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } pl.SetLogInfo(&event, data, "started", "DBDelete") @@ -405,22 +309,10 @@ func Delete(input e.DeleteDto) (*d.Data, error) { pl.SetLogInfo(&event, nil, "complete") - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + executor.setMwtype(pu.MWTPost) + // Execute post-middleware + if err := executor.ExecuteDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/user/helper.go b/internal/use-case/main-use-case/user/helper.go index 1d334fb7..7fa1ec34 100644 --- a/internal/use-case/main-use-case/user/helper.go +++ b/internal/use-case/main-use-case/user/helper.go @@ -5,9 +5,13 @@ Any functions that are used internally by the use-case package user import ( + "fmt" e "simrs-vx/internal/domain/main-entities/user" + pl "simrs-vx/pkg/logger" p "simrs-vx/pkg/password" + + "gorm.io/gorm" ) func setCreate(src e.CreateDto, dst *e.User) error { @@ -29,3 +33,103 @@ func setUpdate(src e.UpdateDto, dst *e.User) error { return nil } + +// executeCreateMiddleware executes create middleware (pre or post) +func executeCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.User, tx *gorm.DB, event *pl.Event, mwType string) error { + for i := range middlewares { + mwName := fmt.Sprintf("%s[%d]", mwType, i) + + pl.SetLogInfo(event, data, "started", mwName) + + if err := middlewares[i](input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: getMiddlewareErrorCode(mwType), + Detail: fmt.Sprintf("%s middleware %s failed", getMiddlewareTypeLabel(mwType), mwName), + Raw: err, + } + return pl.SetLogError(*event, data) + } + + pl.SetLogInfo(event, nil, "complete") + } + return nil +} + +// executeReadListMiddleware executes read list middleware (pre or post) +func executeReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.User, tx *gorm.DB, event *pl.Event, mwType string) error { + for i := range middlewares { + mwName := fmt.Sprintf("%s[%d]", mwType, i) + + pl.SetLogInfo(event, input, "started", mwName) + + if err := middlewares[i](input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: getMiddlewareErrorCode(mwType), + Detail: fmt.Sprintf("%s middleware %s failed", getMiddlewareTypeLabel(mwType), mwName), + Raw: err, + } + return pl.SetLogError(*event, input) + } + + pl.SetLogInfo(event, nil, "complete") + } + return nil +} + +// executeReadDetailMiddleware executes read detail middleware (pre or post) +func executeReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User, tx *gorm.DB, event *pl.Event, mwType string) error { + for i := range middlewares { + mwName := fmt.Sprintf("%s[%d]", mwType, i) + + // Use data for logging if available, otherwise use input + logData := interface{}(input) + if data != nil { + logData = data + } + + pl.SetLogInfo(event, logData, "started", mwName) + + if err := middlewares[i](input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: getMiddlewareErrorCode(mwType), + Detail: fmt.Sprintf("%s middleware %s failed", getMiddlewareTypeLabel(mwType), mwName), + Raw: err, + } + return pl.SetLogError(*event, logData) + } + + pl.SetLogInfo(event, nil, "complete") + } + return nil +} + +// Helper functions to determine error codes and labels based on middleware type +func getMiddlewareErrorCode(mwType string) string { + if containsString(mwType, "Pre") { + return "MW_PRE_FAILED" + } + return "MW_POST_FAILED" +} + +func getMiddlewareTypeLabel(mwType string) string { + if containsString(mwType, "Pre") { + return "Pre" + } + return "Post" +} + +func containsString(str, substr string) bool { + return len(str) >= len(substr) && str[len(str)-len(substr):] != substr && + (len(str) == len(substr) || str[len(str)-len(substr)-1:len(str)-len(substr)] != substr) && + func() bool { + for i := 0; i <= len(str)-len(substr); i++ { + if str[i:i+len(substr)] == substr { + return true + } + } + return false + }() +} diff --git a/internal/use-case/main-use-case/user/middleware.go b/internal/use-case/main-use-case/user/middleware.go new file mode 100644 index 00000000..208468b6 --- /dev/null +++ b/internal/use-case/main-use-case/user/middleware.go @@ -0,0 +1,159 @@ +package user + +// pm "simrs-vx/internal/use-case/plugin/modifier" + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/user" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +// func init() { +// createPreMw = append(createPreMw, pm.ModifInput) +// createPreMw = append(createPreMw, pm.CheckData) +// } + +type middlewareExecutor struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareExecutor(event *pl.Event, tx *gorm.DB) *middlewareExecutor { + return &middlewareExecutor{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareExecutor) ExecuteCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + pl.SetLogInfo(me.Event, data, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, data) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) ExecuteReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + pl.SetLogInfo(me.Event, input, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, input) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) ExecuteReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + // Use data for logging if available, otherwise use input + logData := interface{}(input) + if data != nil { + logData = data + } + + pl.SetLogInfo(me.Event, logData, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, logData) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) ExecuteUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + // Use data for logging if available, otherwise use input + logData := interface{}(input) + if data != nil { + logData = data + } + + pl.SetLogInfo(me.Event, logData, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, logData) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) ExecuteDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User) error { + for i, middleware := range middlewares { + mwName := fmt.Sprintf("%s[%d]", me.MwType, i) + + // Use data for logging if available, otherwise use input + logData := interface{}(input) + if data != nil { + logData = data + } + + pl.SetLogInfo(me.Event, logData, "started", mwName) + + if err := middleware(input, data, me.Tx); err != nil { + me.Event.Status = "failed" + me.Event.ErrInfo = pl.ErrorInfo{ + Code: pu.GetMiddlewareErrorCode(me.MwType), + Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), + Raw: err, + } + return pl.SetLogError(*me.Event, logData) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareExecutor) setMwtype(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/pkg/use-case-helper/tycovar.go b/pkg/use-case-helper/tycovar.go new file mode 100644 index 00000000..c515b158 --- /dev/null +++ b/pkg/use-case-helper/tycovar.go @@ -0,0 +1,8 @@ +package usecasehelper + +type MWType string + +const ( + MWTPre MWType = "Pre" + MWTPost MWType = "Post" +) diff --git a/pkg/use-case-helper/use-case-helper.go b/pkg/use-case-helper/use-case-helper.go index 20550048..999bc732 100644 --- a/pkg/use-case-helper/use-case-helper.go +++ b/pkg/use-case-helper/use-case-helper.go @@ -3,6 +3,7 @@ package usecasehelper import ( "errors" "fmt" + "strings" pl "simrs-vx/pkg/logger" @@ -46,3 +47,10 @@ func HandleReadError(err error, event *pl.Event, itemType string, id interface{} return pl.SetLogError(*event, nil) } + +func GetMiddlewareErrorCode(mwType MWType) string { + if strings.Contains(string(mwType), "Pre") { + return "MW_PRE_FAILED" + } + return "MW_POST_FAILED" +} From a4a0a4f672eae001f93f60f75bea154d569cc8ad Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 22 Aug 2025 15:18:25 +0700 Subject: [PATCH 15/40] refactor : adjust use case after mw refactored --- internal/domain/main-entities/user/dto.go | 2 +- .../use-case/main-use-case/district/case.go | 283 ++++------------- .../use-case/main-use-case/district/lib.go | 79 ++++- .../district/middleware-runner.go | 103 +++++++ .../main-use-case/district/middleware.go | 9 + .../main-use-case/district/tycovar.go | 22 +- .../main-use-case/division-position/case.go | 282 ++++------------- .../main-use-case/division-position/lib.go | 81 ++++- .../division-position/middleware-runner.go | 103 +++++++ .../division-position/middleware.go | 9 + .../division-position/tycovar.go | 22 +- .../use-case/main-use-case/division/case.go | 280 ++++------------- .../use-case/main-use-case/division/lib.go | 80 ++++- .../division/middleware-runner.go | 103 +++++++ .../main-use-case/division/middleware.go | 9 + .../main-use-case/division/tycovar.go | 22 +- .../main-use-case/installation/case.go | 280 ++++------------- .../main-use-case/installation/lib.go | 80 ++++- .../installation/middleware-runner.go | 103 +++++++ .../main-use-case/installation/middleware.go | 9 + .../main-use-case/installation/tycovar.go | 22 +- .../use-case/main-use-case/province/case.go | 280 ++++------------- .../use-case/main-use-case/province/lib.go | 79 ++++- .../province/middleware-runner.go | 105 +++++++ .../main-use-case/province/middleware.go | 9 + .../main-use-case/province/tycovar.go | 22 +- .../use-case/main-use-case/regency/case.go | 280 ++++------------- .../use-case/main-use-case/regency/lib.go | 79 ++++- .../regency/middleware-runner.go | 105 +++++++ .../main-use-case/regency/middleware.go | 9 + .../use-case/main-use-case/regency/tycovar.go | 22 +- internal/use-case/main-use-case/unit/case.go | 280 ++++------------- internal/use-case/main-use-case/unit/lib.go | 81 ++++- .../main-use-case/unit/middleware-runner.go | 103 +++++++ .../use-case/main-use-case/unit/middleware.go | 9 + .../use-case/main-use-case/unit/tycovar.go | 22 +- internal/use-case/main-use-case/user/case.go | 169 ++++------ .../use-case/main-use-case/user/helper.go | 107 +------ internal/use-case/main-use-case/user/lib.go | 79 ++++- .../main-use-case/user/middleware-runner.go | 103 +++++++ .../use-case/main-use-case/user/middleware.go | 160 +--------- .../use-case/main-use-case/user/tycovar.go | 22 +- .../use-case/main-use-case/village/case.go | 288 ++++-------------- .../use-case/main-use-case/village/lib.go | 79 ++++- .../village/middleware-runner.go | 103 +++++++ .../main-use-case/village/middleware.go | 9 + .../use-case/main-use-case/village/tycovar.go | 22 +- pkg/logger/logger.go | 2 +- pkg/use-case-helper/use-case-helper.go | 24 +- 49 files changed, 2331 insertions(+), 2304 deletions(-) create mode 100644 internal/use-case/main-use-case/district/middleware-runner.go create mode 100644 internal/use-case/main-use-case/district/middleware.go create mode 100644 internal/use-case/main-use-case/division-position/middleware-runner.go create mode 100644 internal/use-case/main-use-case/division-position/middleware.go create mode 100644 internal/use-case/main-use-case/division/middleware-runner.go create mode 100644 internal/use-case/main-use-case/division/middleware.go create mode 100644 internal/use-case/main-use-case/installation/middleware-runner.go create mode 100644 internal/use-case/main-use-case/installation/middleware.go create mode 100644 internal/use-case/main-use-case/province/middleware-runner.go create mode 100644 internal/use-case/main-use-case/province/middleware.go create mode 100644 internal/use-case/main-use-case/regency/middleware-runner.go create mode 100644 internal/use-case/main-use-case/regency/middleware.go create mode 100644 internal/use-case/main-use-case/unit/middleware-runner.go create mode 100644 internal/use-case/main-use-case/unit/middleware.go create mode 100644 internal/use-case/main-use-case/user/middleware-runner.go create mode 100644 internal/use-case/main-use-case/village/middleware-runner.go create mode 100644 internal/use-case/main-use-case/village/middleware.go diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index ab2bd7d2..87ce62d0 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -56,7 +56,7 @@ type ResponseDto struct { LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` } -func (u User) ToResponse() ResponseDto { +func (u *User) ToResponse() ResponseDto { resp := ResponseDto{ Name: u.Name, Status_Code: u.Status_Code, diff --git a/internal/use-case/main-use-case/district/case.go b/internal/use-case/main-use-case/district/case.go index c5f16ca9..1770e6f2 100644 --- a/internal/use-case/main-use-case/district/case.go +++ b/internal/use-case/main-use-case/district/case.go @@ -1,7 +1,6 @@ package district import ( - "fmt" e "simrs-vx/internal/domain/main-entities/district" "strconv" @@ -19,8 +18,6 @@ const source = "district" func Create(input e.CreateDto) (*d.Data, error) { data := e.District{} - setData(&input, &data) - event := pl.Event{ Feature: "Create", Source: source, @@ -30,51 +27,23 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBCreate") - _, err := CreateData(&data, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", - Raw: err, - } - return pl.SetLogError(event, data) + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData } - pl.SetLogInfo(&event, nil, "complete") - - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,54 +80,21 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadList") - dataList, metaList, err = ReadListData(input, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-list-fail", - Detail: "Database read list failed", - Raw: err, - } - return pl.SetLogError(event, input) + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,46 +130,21 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadDetail") - data, err = ReadDetailData(input, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -249,7 +160,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: pu.SafeToResponse(data), + Data: data.ToResponse(), }, nil } @@ -268,60 +179,27 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr - } - pl.SetLogInfo(&event, input, "started", "setUpdate") - setData(&input, data) - - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBUpdate") - if err := UpdateData(*data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: err, - } - return pl.SetLogError(event, data) + 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") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - 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 @@ -357,58 +235,25 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBDelete") - if err := DeleteData(data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-delete-fail", - Detail: "Database delete failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := DeleteData(data, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/district/lib.go b/internal/use-case/main-use-case/district/lib.go index 402cae63..0f199d86 100644 --- a/internal/use-case/main-use-case/district/lib.go +++ b/internal/use-case/main-use-case/district/lib.go @@ -2,13 +2,20 @@ package district import ( e "simrs-vx/internal/domain/main-entities/district" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input *e.District, dbx ...*gorm.DB) (*e.District, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.District, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.District{} + setData(&input, &data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -16,14 +23,22 @@ func CreateData(input *e.District, dbx ...*gorm.DB) (*e.District, error) { tx = dg.I } - if err := tx.Create(&input).Error; err != nil { - return nil, err + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) } - return input, nil + pl.SetLogInfo(event, nil, "complete") + return &data, nil } -func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.District, *e.MetaDto, error) { +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.District, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") data := []e.District{} pagination := gh.Pagination{} count := int64(0) @@ -38,8 +53,6 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.District, *e.MetaDt tx = tx. Model(&e.District{}). - // Joins("Patient"). // if needed - // Preload("Patient"). // if needed Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)) @@ -48,16 +61,25 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.District, *e.MetaDt if err == gorm.ErrRecordNotFound { return nil, &meta, nil } - return nil, nil, err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) } 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, dbx ...*gorm.DB) (*e.District, error) { +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.District, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.District{} var tx *gorm.DB @@ -68,13 +90,19 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.District, error) } if err := tx.First(&data, input.Id).Error; err != nil { - return nil, err + 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(input e.District, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.District, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -82,10 +110,22 @@ func UpdateData(input e.District, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Save(&input).Error + 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 DeleteData(input *e.District, dbx ...*gorm.DB) error { +func DeleteData(data *e.District, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -93,5 +133,16 @@ func DeleteData(input *e.District, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Delete(input).Error + 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 } diff --git a/internal/use-case/main-use-case/district/middleware-runner.go b/internal/use-case/main-use-case/district/middleware-runner.go new file mode 100644 index 00000000..7906dccb --- /dev/null +++ b/internal/use-case/main-use-case/district/middleware-runner.go @@ -0,0 +1,103 @@ +package district + +import ( + e "simrs-vx/internal/domain/main-entities/district" + 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.District) 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.District) 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.District) 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.District) 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.District) 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 +} diff --git a/internal/use-case/main-use-case/district/middleware.go b/internal/use-case/main-use-case/district/middleware.go new file mode 100644 index 00000000..3ad999c3 --- /dev/null +++ b/internal/use-case/main-use-case/district/middleware.go @@ -0,0 +1,9 @@ +package district + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/district/tycovar.go b/internal/use-case/main-use-case/district/tycovar.go index 99670a00..f64d1a46 100644 --- a/internal/use-case/main-use-case/district/tycovar.go +++ b/internal/use-case/main-use-case/district/tycovar.go @@ -14,11 +14,23 @@ import ( e "simrs-vx/internal/domain/main-entities/district" ) -type createMw func(input *e.CreateDto, data *e.District, tx *gorm.DB) error -type readListMw func(input *e.ReadListDto, data *e.District, tx *gorm.DB) error -type readDetailMw func(input *e.ReadDetailDto, data *e.District, tx *gorm.DB) error -type updateMw func(input *e.ReadDetailDto, data *e.District, tx *gorm.DB) error -type deleteMw func(input *e.ReadDetailDto, data *e.District, tx *gorm.DB) error +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.District, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.District, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.District, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware diff --git a/internal/use-case/main-use-case/division-position/case.go b/internal/use-case/main-use-case/division-position/case.go index 7d00343e..bc088fcc 100644 --- a/internal/use-case/main-use-case/division-position/case.go +++ b/internal/use-case/main-use-case/division-position/case.go @@ -1,7 +1,6 @@ package divisionposition import ( - "fmt" e "simrs-vx/internal/domain/main-entities/division-position" "strconv" @@ -19,8 +18,6 @@ const source = "division-position" func Create(input e.CreateDto) (*d.Data, error) { data := e.DivisionPosition{} - setData(&input, &data) - event := pl.Event{ Feature: "Create", Source: source, @@ -30,51 +27,23 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBCreate") - _, err := CreateData(&data, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", - Raw: err, - } - return pl.SetLogError(event, data) + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData } - pl.SetLogInfo(&event, nil, "complete") - - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,54 +80,21 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadList") - dataList, metaList, err = ReadListData(input, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-list-fail", - Detail: "Database read list failed", - Raw: err, - } - return pl.SetLogError(event, input) + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,46 +130,21 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadDetail") - data, err = ReadDetailData(input, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -249,7 +160,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: pu.SafeToResponse(data), + Data: data.ToResponse(), }, nil } @@ -268,59 +179,27 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr - } - setData(&input, data) - - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBUpdate") - if err := UpdateData(*data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: err, - } - return pl.SetLogError(event, data) + 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") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - 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 @@ -356,58 +235,25 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBDelete") - if err := DeleteData(data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-delete-fail", - Detail: "Database delete failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := DeleteData(data, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/division-position/lib.go b/internal/use-case/main-use-case/division-position/lib.go index 7b4058a6..2f0444ae 100644 --- a/internal/use-case/main-use-case/division-position/lib.go +++ b/internal/use-case/main-use-case/division-position/lib.go @@ -2,13 +2,20 @@ package divisionposition import ( e "simrs-vx/internal/domain/main-entities/division-position" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input *e.DivisionPosition, dbx ...*gorm.DB) (*e.DivisionPosition, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.DivisionPosition, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.DivisionPosition{} + setData(&input, &data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -16,14 +23,22 @@ func CreateData(input *e.DivisionPosition, dbx ...*gorm.DB) (*e.DivisionPosition tx = dg.I } - if err := tx.Create(&input).Error; err != nil { - return nil, err + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) } - return input, nil + pl.SetLogInfo(event, nil, "complete") + return &data, nil } -func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.DivisionPosition, *e.MetaDto, error) { +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.DivisionPosition, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") data := []e.DivisionPosition{} pagination := gh.Pagination{} count := int64(0) @@ -38,9 +53,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.DivisionPosition, * tx = tx. Model(&e.DivisionPosition{}). - // Joins("Patient"). // if needed - // Preload("Patient"). // if needed - Preload("Division"). // if needed + Preload("Division"). Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). @@ -50,16 +63,25 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.DivisionPosition, * if err == gorm.ErrRecordNotFound { return nil, &meta, nil } - return nil, nil, err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) } 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, dbx ...*gorm.DB) (*e.DivisionPosition, error) { +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.DivisionPosition, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.DivisionPosition{} var tx *gorm.DB @@ -70,13 +92,19 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.DivisionPosition } if err := tx.First(&data, input.Id).Error; err != nil { - return nil, err + 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(input e.DivisionPosition, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.DivisionPosition, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -84,10 +112,22 @@ func UpdateData(input e.DivisionPosition, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Save(&input).Error + 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 DeleteData(input *e.DivisionPosition, dbx ...*gorm.DB) error { +func DeleteData(data *e.DivisionPosition, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -95,5 +135,16 @@ func DeleteData(input *e.DivisionPosition, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Delete(input).Error + 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 } diff --git a/internal/use-case/main-use-case/division-position/middleware-runner.go b/internal/use-case/main-use-case/division-position/middleware-runner.go new file mode 100644 index 00000000..2662a95f --- /dev/null +++ b/internal/use-case/main-use-case/division-position/middleware-runner.go @@ -0,0 +1,103 @@ +package divisionposition + +import ( + e "simrs-vx/internal/domain/main-entities/division-position" + 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.DivisionPosition) 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.DivisionPosition) 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.DivisionPosition) 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.DivisionPosition) 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.DivisionPosition) 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 +} diff --git a/internal/use-case/main-use-case/division-position/middleware.go b/internal/use-case/main-use-case/division-position/middleware.go new file mode 100644 index 00000000..77a1c3dd --- /dev/null +++ b/internal/use-case/main-use-case/division-position/middleware.go @@ -0,0 +1,9 @@ +package divisionposition + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/division-position/tycovar.go b/internal/use-case/main-use-case/division-position/tycovar.go index 0684de01..4b084e23 100644 --- a/internal/use-case/main-use-case/division-position/tycovar.go +++ b/internal/use-case/main-use-case/division-position/tycovar.go @@ -14,11 +14,23 @@ import ( e "simrs-vx/internal/domain/main-entities/division-position" ) -type createMw func(input *e.CreateDto, data *e.DivisionPosition, tx *gorm.DB) error -type readListMw func(input *e.ReadListDto, data *e.DivisionPosition, tx *gorm.DB) error -type readDetailMw func(input *e.ReadDetailDto, data *e.DivisionPosition, tx *gorm.DB) error -type updateMw func(input *e.ReadDetailDto, data *e.DivisionPosition, tx *gorm.DB) error -type deleteMw func(input *e.ReadDetailDto, data *e.DivisionPosition, tx *gorm.DB) error +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.DivisionPosition, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.DivisionPosition, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.DivisionPosition, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware diff --git a/internal/use-case/main-use-case/division/case.go b/internal/use-case/main-use-case/division/case.go index 3333d61b..bf1b94fe 100644 --- a/internal/use-case/main-use-case/division/case.go +++ b/internal/use-case/main-use-case/division/case.go @@ -1,7 +1,6 @@ package division import ( - "fmt" e "simrs-vx/internal/domain/main-entities/division" "strconv" @@ -19,8 +18,6 @@ const source = "division" func Create(input e.CreateDto) (*d.Data, error) { data := e.Division{} - setData(&input, &data) - event := pl.Event{ Feature: "Create", Source: source, @@ -30,51 +27,23 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBCreate") - _, err := CreateData(&data, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", - Raw: err, - } - return pl.SetLogError(event, data) + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData } - pl.SetLogInfo(&event, nil, "complete") - - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,54 +80,21 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadList") - dataList, metaList, err = ReadListData(input, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-list-fail", - Detail: "Database read list failed", - Raw: err, - } - return pl.SetLogError(event, input) + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,46 +130,21 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadDetail") - data, err = ReadDetailData(input, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -249,7 +160,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: pu.SafeToResponse(data), + Data: data.ToResponse(), }, nil } @@ -268,61 +179,27 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "setUpdate") - setData(&input, data) - - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBUpdate") - if err := UpdateData(*data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := UpdateData(input, data, &event, tx); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - 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 @@ -358,58 +235,25 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBDelete") - if err := DeleteData(data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-delete-fail", - Detail: "Database delete failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := DeleteData(data, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/division/lib.go b/internal/use-case/main-use-case/division/lib.go index 1b13bcf5..0acd085d 100644 --- a/internal/use-case/main-use-case/division/lib.go +++ b/internal/use-case/main-use-case/division/lib.go @@ -2,13 +2,20 @@ package division import ( e "simrs-vx/internal/domain/main-entities/division" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input *e.Division, dbx ...*gorm.DB) (*e.Division, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Division, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Division{} + setData(&input, &data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -16,14 +23,22 @@ func CreateData(input *e.Division, dbx ...*gorm.DB) (*e.Division, error) { tx = dg.I } - if err := tx.Create(&input).Error; err != nil { - return nil, err + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) } - return input, nil + pl.SetLogInfo(event, nil, "complete") + return &data, nil } -func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Division, *e.MetaDto, error) { +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Division, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") data := []e.Division{} pagination := gh.Pagination{} count := int64(0) @@ -38,8 +53,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Division, *e.MetaDt tx = tx. Model(&e.Division{}). - // Joins("Patient"). // if needed - // Preload("Patient"). // if needed + Preload("Installation"). Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). @@ -49,16 +63,25 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Division, *e.MetaDt if err == gorm.ErrRecordNotFound { return nil, &meta, nil } - return nil, nil, err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) } 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, dbx ...*gorm.DB) (*e.Division, error) { +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Division, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.Division{} var tx *gorm.DB @@ -69,13 +92,19 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Division, error) } if err := tx.First(&data, input.Id).Error; err != nil { - return nil, err + 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(input e.Division, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.Division, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -83,10 +112,22 @@ func UpdateData(input e.Division, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Save(&input).Error + 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 DeleteData(input *e.Division, dbx ...*gorm.DB) error { +func DeleteData(data *e.Division, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -94,5 +135,16 @@ func DeleteData(input *e.Division, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Delete(input).Error + 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 } diff --git a/internal/use-case/main-use-case/division/middleware-runner.go b/internal/use-case/main-use-case/division/middleware-runner.go new file mode 100644 index 00000000..915cce28 --- /dev/null +++ b/internal/use-case/main-use-case/division/middleware-runner.go @@ -0,0 +1,103 @@ +package division + +import ( + e "simrs-vx/internal/domain/main-entities/division" + 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.Division) 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.Division) 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.Division) 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.Division) 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.Division) 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 +} diff --git a/internal/use-case/main-use-case/division/middleware.go b/internal/use-case/main-use-case/division/middleware.go new file mode 100644 index 00000000..f066ffb8 --- /dev/null +++ b/internal/use-case/main-use-case/division/middleware.go @@ -0,0 +1,9 @@ +package division + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/division/tycovar.go b/internal/use-case/main-use-case/division/tycovar.go index ba4154f2..c7733117 100644 --- a/internal/use-case/main-use-case/division/tycovar.go +++ b/internal/use-case/main-use-case/division/tycovar.go @@ -14,11 +14,23 @@ import ( e "simrs-vx/internal/domain/main-entities/division" ) -type createMw func(input *e.CreateDto, data *e.Division, tx *gorm.DB) error -type readListMw func(input *e.ReadListDto, data *e.Division, tx *gorm.DB) error -type readDetailMw func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error -type updateMw func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error -type deleteMw func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Division, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Division, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware diff --git a/internal/use-case/main-use-case/installation/case.go b/internal/use-case/main-use-case/installation/case.go index e12186f6..6de77882 100644 --- a/internal/use-case/main-use-case/installation/case.go +++ b/internal/use-case/main-use-case/installation/case.go @@ -1,7 +1,6 @@ package installation import ( - "fmt" e "simrs-vx/internal/domain/main-entities/installation" "strconv" @@ -19,8 +18,6 @@ const source = "installation" func Create(input e.CreateDto) (*d.Data, error) { data := e.Installation{} - setData(&input, &data) - event := pl.Event{ Feature: "Create", Source: source, @@ -30,51 +27,23 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBCreate") - _, err := CreateData(&data, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", - Raw: err, - } - return pl.SetLogError(event, data) + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData } - pl.SetLogInfo(&event, nil, "complete") - - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,54 +80,21 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadList") - dataList, metaList, err = ReadListData(input, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-list-fail", - Detail: "Database read list failed", - Raw: err, - } - return pl.SetLogError(event, input) + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,46 +130,21 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadDetail") - data, err = ReadDetailData(input, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -249,7 +160,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: pu.SafeToResponse(data), + Data: data.ToResponse(), }, nil } @@ -268,61 +179,27 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "setUpdate") - setData(&input, data) - - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBUpdate") - if err := UpdateData(*data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := UpdateData(input, data, &event, tx); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - 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 @@ -358,58 +235,25 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBDelete") - if err := DeleteData(data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-delete-fail", - Detail: "Database delete failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := DeleteData(data, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/installation/lib.go b/internal/use-case/main-use-case/installation/lib.go index 30129aa3..05c8fac3 100644 --- a/internal/use-case/main-use-case/installation/lib.go +++ b/internal/use-case/main-use-case/installation/lib.go @@ -2,13 +2,20 @@ package installation import ( e "simrs-vx/internal/domain/main-entities/installation" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input *e.Installation, dbx ...*gorm.DB) (*e.Installation, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Installation, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Installation{} + setData(&input, &data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -16,14 +23,22 @@ func CreateData(input *e.Installation, dbx ...*gorm.DB) (*e.Installation, error) tx = dg.I } - if err := tx.Create(&input).Error; err != nil { - return nil, err + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) } - return input, nil + pl.SetLogInfo(event, nil, "complete") + return &data, nil } -func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Installation, *e.MetaDto, error) { +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) @@ -38,8 +53,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Installation, *e.Me tx = tx. Model(&e.Installation{}). - // Joins("Patient"). // if needed - // Preload("Patient"). // if needed + Preload("Installation"). Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). @@ -49,16 +63,25 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Installation, *e.Me if err == gorm.ErrRecordNotFound { return nil, &meta, nil } - return nil, nil, err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) } 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, dbx ...*gorm.DB) (*e.Installation, error) { +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 @@ -69,13 +92,19 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Installation, er } if err := tx.First(&data, input.Id).Error; err != nil { - return nil, err + 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(input e.Installation, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.Installation, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -83,10 +112,22 @@ func UpdateData(input e.Installation, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Save(&input).Error + 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 DeleteData(input *e.Installation, dbx ...*gorm.DB) error { +func DeleteData(data *e.Installation, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -94,5 +135,16 @@ func DeleteData(input *e.Installation, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Delete(input).Error + 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 } diff --git a/internal/use-case/main-use-case/installation/middleware-runner.go b/internal/use-case/main-use-case/installation/middleware-runner.go new file mode 100644 index 00000000..fce572bb --- /dev/null +++ b/internal/use-case/main-use-case/installation/middleware-runner.go @@ -0,0 +1,103 @@ +package installation + +import ( + e "simrs-vx/internal/domain/main-entities/installation" + 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.Installation) 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.Installation) 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.Installation) 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.Installation) 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.Installation) 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 +} diff --git a/internal/use-case/main-use-case/installation/middleware.go b/internal/use-case/main-use-case/installation/middleware.go new file mode 100644 index 00000000..3d414c9b --- /dev/null +++ b/internal/use-case/main-use-case/installation/middleware.go @@ -0,0 +1,9 @@ +package installation + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/installation/tycovar.go b/internal/use-case/main-use-case/installation/tycovar.go index 072372e0..de8e9c9e 100644 --- a/internal/use-case/main-use-case/installation/tycovar.go +++ b/internal/use-case/main-use-case/installation/tycovar.go @@ -14,11 +14,23 @@ import ( e "simrs-vx/internal/domain/main-entities/installation" ) -type createMw func(input *e.CreateDto, data *e.Installation, tx *gorm.DB) error -type readListMw func(input *e.ReadListDto, data *e.Installation, tx *gorm.DB) error -type readDetailMw func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error -type updateMw func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error -type deleteMw func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Installation, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Installation, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware diff --git a/internal/use-case/main-use-case/province/case.go b/internal/use-case/main-use-case/province/case.go index 758f4c18..c8705614 100644 --- a/internal/use-case/main-use-case/province/case.go +++ b/internal/use-case/main-use-case/province/case.go @@ -1,7 +1,6 @@ package province import ( - "fmt" e "simrs-vx/internal/domain/main-entities/province" "strconv" @@ -19,8 +18,6 @@ const source = "province" func Create(input e.CreateDto) (*d.Data, error) { data := e.Province{} - setData(&input, &data) - event := pl.Event{ Feature: "Create", Source: source, @@ -30,51 +27,23 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBCreate") - _, err := CreateData(&data, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", - Raw: err, - } - return pl.SetLogError(event, data) + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData } - pl.SetLogInfo(&event, nil, "complete") - - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,54 +80,21 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadList") - dataList, metaList, err = ReadListData(input, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-list-fail", - Detail: "Database read list failed", - Raw: err, - } - return pl.SetLogError(event, input) + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,46 +130,21 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadDetail") - data, err = ReadDetailData(input, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -249,7 +160,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: pu.SafeToResponse(data), + Data: data.ToResponse(), }, nil } @@ -268,61 +179,27 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "setUpdate") - setData(&input, data) - - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBUpdate") - if err := UpdateData(*data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := UpdateData(input, data, &event, tx); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - 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 @@ -358,58 +235,25 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBDelete") - if err := DeleteData(data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-delete-fail", - Detail: "Database delete failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := DeleteData(data, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/province/lib.go b/internal/use-case/main-use-case/province/lib.go index df44515b..aaa53faa 100644 --- a/internal/use-case/main-use-case/province/lib.go +++ b/internal/use-case/main-use-case/province/lib.go @@ -2,13 +2,20 @@ package province import ( e "simrs-vx/internal/domain/main-entities/province" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input *e.Province, dbx ...*gorm.DB) (*e.Province, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Province, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Province{} + setData(&input, &data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -16,14 +23,22 @@ func CreateData(input *e.Province, dbx ...*gorm.DB) (*e.Province, error) { tx = dg.I } - if err := tx.Create(&input).Error; err != nil { - return nil, err + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) } - return input, nil + pl.SetLogInfo(event, nil, "complete") + return &data, nil } -func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Province, *e.MetaDto, error) { +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Province, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") data := []e.Province{} pagination := gh.Pagination{} count := int64(0) @@ -38,8 +53,6 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Province, *e.MetaDt tx = tx. Model(&e.Province{}). - // Joins("Patient"). // if needed - // Preload("Patient"). // if needed Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)) @@ -48,16 +61,25 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Province, *e.MetaDt if err == gorm.ErrRecordNotFound { return nil, &meta, nil } - return nil, nil, err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) } 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, dbx ...*gorm.DB) (*e.Province, error) { +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Province, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.Province{} var tx *gorm.DB @@ -68,13 +90,19 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Province, error) } if err := tx.First(&data, input.Id).Error; err != nil { - return nil, err + 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(input e.Province, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.Province, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -82,10 +110,22 @@ func UpdateData(input e.Province, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Save(&input).Error + 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 DeleteData(input *e.Province, dbx ...*gorm.DB) error { +func DeleteData(data *e.Province, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -93,5 +133,16 @@ func DeleteData(input *e.Province, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Delete(input).Error + 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 } diff --git a/internal/use-case/main-use-case/province/middleware-runner.go b/internal/use-case/main-use-case/province/middleware-runner.go new file mode 100644 index 00000000..9f735d90 --- /dev/null +++ b/internal/use-case/main-use-case/province/middleware-runner.go @@ -0,0 +1,105 @@ +package province + +// pm "simrs-vx/internal/use-case/plugin/modifier" + +import ( + e "simrs-vx/internal/domain/main-entities/province" + 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.Province) 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.Province) 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.Province) 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.Province) 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.Province) 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 +} diff --git a/internal/use-case/main-use-case/province/middleware.go b/internal/use-case/main-use-case/province/middleware.go new file mode 100644 index 00000000..0abd7dd9 --- /dev/null +++ b/internal/use-case/main-use-case/province/middleware.go @@ -0,0 +1,9 @@ +package province + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/province/tycovar.go b/internal/use-case/main-use-case/province/tycovar.go index e65ab008..0c4349aa 100644 --- a/internal/use-case/main-use-case/province/tycovar.go +++ b/internal/use-case/main-use-case/province/tycovar.go @@ -14,11 +14,23 @@ import ( e "simrs-vx/internal/domain/main-entities/province" ) -type createMw func(input *e.CreateDto, data *e.Province, tx *gorm.DB) error -type readListMw func(input *e.ReadListDto, data *e.Province, tx *gorm.DB) error -type readDetailMw func(input *e.ReadDetailDto, data *e.Province, tx *gorm.DB) error -type updateMw func(input *e.ReadDetailDto, data *e.Province, tx *gorm.DB) error -type deleteMw func(input *e.ReadDetailDto, data *e.Province, tx *gorm.DB) error +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Province, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Province, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Province, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware diff --git a/internal/use-case/main-use-case/regency/case.go b/internal/use-case/main-use-case/regency/case.go index deabdc4c..a0836549 100644 --- a/internal/use-case/main-use-case/regency/case.go +++ b/internal/use-case/main-use-case/regency/case.go @@ -1,7 +1,6 @@ package regency import ( - "fmt" e "simrs-vx/internal/domain/main-entities/regency" "strconv" @@ -19,8 +18,6 @@ const source = "regency" func Create(input e.CreateDto) (*d.Data, error) { data := e.Regency{} - setData(&input, &data) - event := pl.Event{ Feature: "Create", Source: source, @@ -30,51 +27,23 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBCreate") - _, err := CreateData(&data, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", - Raw: err, - } - return pl.SetLogError(event, data) + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData } - pl.SetLogInfo(&event, nil, "complete") - - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,54 +80,21 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadList") - dataList, metaList, err = ReadListData(input, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-list-fail", - Detail: "Database read list failed", - Raw: err, - } - return pl.SetLogError(event, input) + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,46 +130,21 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadDetail") - data, err = ReadDetailData(input, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -249,7 +160,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: pu.SafeToResponse(data), + Data: data.ToResponse(), }, nil } @@ -268,61 +179,27 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "setUpdate") - setData(&input, data) - - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBUpdate") - if err := UpdateData(*data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := UpdateData(input, data, &event, tx); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - 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 @@ -358,58 +235,25 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBDelete") - if err := DeleteData(data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-delete-fail", - Detail: "Database delete failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := DeleteData(data, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/regency/lib.go b/internal/use-case/main-use-case/regency/lib.go index 67bb1a17..61577d9c 100644 --- a/internal/use-case/main-use-case/regency/lib.go +++ b/internal/use-case/main-use-case/regency/lib.go @@ -2,13 +2,20 @@ package regency import ( e "simrs-vx/internal/domain/main-entities/regency" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input *e.Regency, dbx ...*gorm.DB) (*e.Regency, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Regency, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Regency{} + setData(&input, &data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -16,14 +23,22 @@ func CreateData(input *e.Regency, dbx ...*gorm.DB) (*e.Regency, error) { tx = dg.I } - if err := tx.Create(&input).Error; err != nil { - return nil, err + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) } - return input, nil + pl.SetLogInfo(event, nil, "complete") + return &data, nil } -func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Regency, *e.MetaDto, error) { +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Regency, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") data := []e.Regency{} pagination := gh.Pagination{} count := int64(0) @@ -38,8 +53,6 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Regency, *e.MetaDto tx = tx. Model(&e.Regency{}). - // Joins("Patient"). // if needed - // Preload("Patient"). // if needed Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)) @@ -48,16 +61,25 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Regency, *e.MetaDto if err == gorm.ErrRecordNotFound { return nil, &meta, nil } - return nil, nil, err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) } 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, dbx ...*gorm.DB) (*e.Regency, error) { +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Regency, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.Regency{} var tx *gorm.DB @@ -68,13 +90,19 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Regency, error) } if err := tx.First(&data, input.Id).Error; err != nil { - return nil, err + 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(input e.Regency, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.Regency, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -82,10 +110,22 @@ func UpdateData(input e.Regency, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Save(&input).Error + 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 DeleteData(input *e.Regency, dbx ...*gorm.DB) error { +func DeleteData(data *e.Regency, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -93,5 +133,16 @@ func DeleteData(input *e.Regency, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Delete(input).Error + 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 } diff --git a/internal/use-case/main-use-case/regency/middleware-runner.go b/internal/use-case/main-use-case/regency/middleware-runner.go new file mode 100644 index 00000000..777525a3 --- /dev/null +++ b/internal/use-case/main-use-case/regency/middleware-runner.go @@ -0,0 +1,105 @@ +package regency + +// pm "simrs-vx/internal/use-case/plugin/modifier" + +import ( + e "simrs-vx/internal/domain/main-entities/regency" + 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.Regency) 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.Regency) 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.Regency) 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.Regency) 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.Regency) 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 +} diff --git a/internal/use-case/main-use-case/regency/middleware.go b/internal/use-case/main-use-case/regency/middleware.go new file mode 100644 index 00000000..6b042fbd --- /dev/null +++ b/internal/use-case/main-use-case/regency/middleware.go @@ -0,0 +1,9 @@ +package regency + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/regency/tycovar.go b/internal/use-case/main-use-case/regency/tycovar.go index 711d0831..fb80215c 100644 --- a/internal/use-case/main-use-case/regency/tycovar.go +++ b/internal/use-case/main-use-case/regency/tycovar.go @@ -14,11 +14,23 @@ import ( e "simrs-vx/internal/domain/main-entities/regency" ) -type createMw func(input *e.CreateDto, data *e.Regency, tx *gorm.DB) error -type readListMw func(input *e.ReadListDto, data *e.Regency, tx *gorm.DB) error -type readDetailMw func(input *e.ReadDetailDto, data *e.Regency, tx *gorm.DB) error -type updateMw func(input *e.ReadDetailDto, data *e.Regency, tx *gorm.DB) error -type deleteMw func(input *e.ReadDetailDto, data *e.Regency, tx *gorm.DB) error +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Regency, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Regency, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Regency, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware diff --git a/internal/use-case/main-use-case/unit/case.go b/internal/use-case/main-use-case/unit/case.go index 78f86cc5..0ab8cdcb 100644 --- a/internal/use-case/main-use-case/unit/case.go +++ b/internal/use-case/main-use-case/unit/case.go @@ -1,7 +1,6 @@ package unit import ( - "fmt" e "simrs-vx/internal/domain/main-entities/unit" "strconv" @@ -19,8 +18,6 @@ const source = "unit" func Create(input e.CreateDto) (*d.Data, error) { data := e.Unit{} - setData(&input, &data) - event := pl.Event{ Feature: "Create", Source: source, @@ -30,51 +27,23 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBCreate") - _, err := CreateData(&data, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", - Raw: err, - } - return pl.SetLogError(event, data) + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData } - pl.SetLogInfo(&event, nil, "complete") - - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,54 +80,21 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadList") - dataList, metaList, err = ReadListData(input, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-list-fail", - Detail: "Database read list failed", - Raw: err, - } - return pl.SetLogError(event, input) + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,46 +130,21 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadDetail") - data, err = ReadDetailData(input, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -249,7 +160,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: pu.SafeToResponse(data), + Data: data.ToResponse(), }, nil } @@ -268,61 +179,27 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "setUpdate") - setData(&input, data) - - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBUpdate") - if err := UpdateData(*data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := UpdateData(input, data, &event, tx); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - 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 @@ -358,58 +235,25 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBDelete") - if err := DeleteData(data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-delete-fail", - Detail: "Database delete failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := DeleteData(data, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/unit/lib.go b/internal/use-case/main-use-case/unit/lib.go index ee4ddf1e..5a1776e6 100644 --- a/internal/use-case/main-use-case/unit/lib.go +++ b/internal/use-case/main-use-case/unit/lib.go @@ -2,13 +2,20 @@ package unit import ( e "simrs-vx/internal/domain/main-entities/unit" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input *e.Unit, dbx ...*gorm.DB) (*e.Unit, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Unit, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Unit{} + setData(&input, &data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -16,14 +23,22 @@ func CreateData(input *e.Unit, dbx ...*gorm.DB) (*e.Unit, error) { tx = dg.I } - if err := tx.Create(&input).Error; err != nil { - return nil, err + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) } - return input, nil + pl.SetLogInfo(event, nil, "complete") + return &data, nil } -func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Unit, *e.MetaDto, error) { +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Unit, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") data := []e.Unit{} pagination := gh.Pagination{} count := int64(0) @@ -38,9 +53,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Unit, *e.MetaDto, e tx = tx. Model(&e.Unit{}). - // Joins("Patient"). // if needed - // Preload("Patient"). // if needed - Preload("Installation"). // if needed + Preload("Installation"). Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). @@ -50,16 +63,25 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Unit, *e.MetaDto, e if err == gorm.ErrRecordNotFound { return nil, &meta, nil } - return nil, nil, err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) } 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, dbx ...*gorm.DB) (*e.Unit, error) { +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Unit, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.Unit{} var tx *gorm.DB @@ -70,13 +92,19 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Unit, error) { } if err := tx.First(&data, input.Id).Error; err != nil { - return nil, err + 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(input e.Unit, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.Unit, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -84,10 +112,22 @@ func UpdateData(input e.Unit, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Save(&input).Error + 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 DeleteData(input *e.Unit, dbx ...*gorm.DB) error { +func DeleteData(data *e.Unit, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -95,5 +135,16 @@ func DeleteData(input *e.Unit, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Delete(input).Error + 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 } diff --git a/internal/use-case/main-use-case/unit/middleware-runner.go b/internal/use-case/main-use-case/unit/middleware-runner.go new file mode 100644 index 00000000..fdce9d02 --- /dev/null +++ b/internal/use-case/main-use-case/unit/middleware-runner.go @@ -0,0 +1,103 @@ +package unit + +import ( + e "simrs-vx/internal/domain/main-entities/unit" + 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.Unit) 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.Unit) 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.Unit) 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.Unit) 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.Unit) 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 +} diff --git a/internal/use-case/main-use-case/unit/middleware.go b/internal/use-case/main-use-case/unit/middleware.go new file mode 100644 index 00000000..bac48f4d --- /dev/null +++ b/internal/use-case/main-use-case/unit/middleware.go @@ -0,0 +1,9 @@ +package unit + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/unit/tycovar.go b/internal/use-case/main-use-case/unit/tycovar.go index 410328d3..e1a7c69f 100644 --- a/internal/use-case/main-use-case/unit/tycovar.go +++ b/internal/use-case/main-use-case/unit/tycovar.go @@ -14,11 +14,23 @@ import ( e "simrs-vx/internal/domain/main-entities/unit" ) -type createMw func(input *e.CreateDto, data *e.Unit, tx *gorm.DB) error -type readListMw func(input *e.ReadListDto, data *e.Unit, tx *gorm.DB) error -type readDetailMw func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error -type updateMw func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error -type deleteMw func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Unit, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Unit, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index c125afd0..85902fc6 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -18,8 +18,6 @@ const source = "user" func Create(input e.CreateDto) (*d.Data, error) { data := e.User{} - setCreate(input, &data) - event := pl.Event{ Feature: "Create", Source: source, @@ -29,31 +27,22 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - executor := newMiddlewareExecutor(&event, tx) - executor.setMwtype(pu.MWTPre) - - // Execute pre-middleware - if err := executor.ExecuteCreateMiddleware(createPreMw, &input, &data); err != nil { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { return err } - pl.SetLogInfo(&event, data, "started", "DBCreate") - _, err := CreateData(&data, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", - Raw: err, - } - return pl.SetLogError(event, data) + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData } - pl.SetLogInfo(&event, nil, "complete") - - executor.setMwtype(pu.MWTPost) - // Execute post-middleware - if err := executor.ExecuteCreateMiddleware(createPostMw, &input, &data); err != nil { + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { return err } @@ -91,31 +80,20 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - executor := newMiddlewareExecutor(&event, tx) - executor.setMwtype(pu.MWTPre) - - // Execute pre-middleware - if err := executor.ExecuteReadListMiddleware(readListPreMw, &input, data); err != nil { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { return err } - pl.SetLogInfo(&event, input, "started", "DBReadList") - dataList, metaList, err = ReadListData(input, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-list-fail", - Detail: "Database read list failed", - Raw: err, - } - return pl.SetLogError(event, input) + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - executor.setMwtype(pu.MWTPost) - // Execute post-middleware - if err := executor.ExecuteReadListMiddleware(readListPostMw, &input, data); err != nil { + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { return err } @@ -152,23 +130,20 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - executor := newMiddlewareExecutor(&event, tx) - executor.setMwtype(pu.MWTPre) - - // Execute pre-middleware - if err := executor.ExecuteReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { return err } - pl.SetLogInfo(&event, input, "started", "DBReadDetail") - data, err = ReadDetailData(input, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err } - executor.setMwtype(pu.MWTPost) - // Execute post-middleware - if err := executor.ExecuteReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { return err } @@ -185,7 +160,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: pu.SafeToResponse(data), + Data: data.ToResponse(), }, nil } @@ -204,49 +179,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr - } - - pl.SetLogInfo(&event, input, "started", "setUpdate") - err = setUpdate(input, data) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "set-update-fail", - Detail: "Set update data failed", - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") - - executor := newMiddlewareExecutor(&event, tx) - executor.setMwtype(pu.MWTPre) - - // Execute pre-middleware - if err := executor.ExecuteUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, data, "started", "DBUpdate") - if err := UpdateData(*data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: err, - } - return pl.SetLogError(event, data) + 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") - executor.setMwtype(pu.MWTPost) - // Execute post-middleware - if err := executor.ExecuteUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { return err } @@ -283,35 +235,24 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr - } - - executor := newMiddlewareExecutor(&event, tx) - executor.setMwtype(pu.MWTPre) - - // Execute pre-middleware - if err := executor.ExecuteDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, data, "started", "DBDelete") - if err := DeleteData(data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-delete-fail", - Detail: "Database delete failed", - Raw: err, - } - return pl.SetLogError(event, data) + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") + if err := DeleteData(data, &event, tx); err != nil { + return err + } - executor.setMwtype(pu.MWTPost) - // Execute post-middleware - if err := executor.ExecuteDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { return err } diff --git a/internal/use-case/main-use-case/user/helper.go b/internal/use-case/main-use-case/user/helper.go index 7fa1ec34..37815b51 100644 --- a/internal/use-case/main-use-case/user/helper.go +++ b/internal/use-case/main-use-case/user/helper.go @@ -5,13 +5,9 @@ Any functions that are used internally by the use-case package user import ( - "fmt" e "simrs-vx/internal/domain/main-entities/user" - pl "simrs-vx/pkg/logger" p "simrs-vx/pkg/password" - - "gorm.io/gorm" ) func setCreate(src e.CreateDto, dst *e.User) error { @@ -27,109 +23,8 @@ func setCreate(src e.CreateDto, dst *e.User) error { return nil } -func setUpdate(src e.UpdateDto, dst *e.User) error { +func setUpdate(src e.UpdateDto, dst *e.User) { dst.Name = src.Name dst.Status_Code = src.Status_Code - return nil -} - -// executeCreateMiddleware executes create middleware (pre or post) -func executeCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.User, tx *gorm.DB, event *pl.Event, mwType string) error { - for i := range middlewares { - mwName := fmt.Sprintf("%s[%d]", mwType, i) - - pl.SetLogInfo(event, data, "started", mwName) - - if err := middlewares[i](input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: getMiddlewareErrorCode(mwType), - Detail: fmt.Sprintf("%s middleware %s failed", getMiddlewareTypeLabel(mwType), mwName), - Raw: err, - } - return pl.SetLogError(*event, data) - } - - pl.SetLogInfo(event, nil, "complete") - } - return nil -} - -// executeReadListMiddleware executes read list middleware (pre or post) -func executeReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.User, tx *gorm.DB, event *pl.Event, mwType string) error { - for i := range middlewares { - mwName := fmt.Sprintf("%s[%d]", mwType, i) - - pl.SetLogInfo(event, input, "started", mwName) - - if err := middlewares[i](input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: getMiddlewareErrorCode(mwType), - Detail: fmt.Sprintf("%s middleware %s failed", getMiddlewareTypeLabel(mwType), mwName), - Raw: err, - } - return pl.SetLogError(*event, input) - } - - pl.SetLogInfo(event, nil, "complete") - } - return nil -} - -// executeReadDetailMiddleware executes read detail middleware (pre or post) -func executeReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User, tx *gorm.DB, event *pl.Event, mwType string) error { - for i := range middlewares { - mwName := fmt.Sprintf("%s[%d]", mwType, i) - - // Use data for logging if available, otherwise use input - logData := interface{}(input) - if data != nil { - logData = data - } - - pl.SetLogInfo(event, logData, "started", mwName) - - if err := middlewares[i](input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: getMiddlewareErrorCode(mwType), - Detail: fmt.Sprintf("%s middleware %s failed", getMiddlewareTypeLabel(mwType), mwName), - Raw: err, - } - return pl.SetLogError(*event, logData) - } - - pl.SetLogInfo(event, nil, "complete") - } - return nil -} - -// Helper functions to determine error codes and labels based on middleware type -func getMiddlewareErrorCode(mwType string) string { - if containsString(mwType, "Pre") { - return "MW_PRE_FAILED" - } - return "MW_POST_FAILED" -} - -func getMiddlewareTypeLabel(mwType string) string { - if containsString(mwType, "Pre") { - return "Pre" - } - return "Post" -} - -func containsString(str, substr string) bool { - return len(str) >= len(substr) && str[len(str)-len(substr):] != substr && - (len(str) == len(substr) || str[len(str)-len(substr)-1:len(str)-len(substr)] != substr) && - func() bool { - for i := 0; i <= len(str)-len(substr); i++ { - if str[i:i+len(substr)] == substr { - return true - } - } - return false - }() } diff --git a/internal/use-case/main-use-case/user/lib.go b/internal/use-case/main-use-case/user/lib.go index c767bdf1..40ad6e17 100644 --- a/internal/use-case/main-use-case/user/lib.go +++ b/internal/use-case/main-use-case/user/lib.go @@ -2,13 +2,20 @@ package user import ( e "simrs-vx/internal/domain/main-entities/user" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input *e.User, dbx ...*gorm.DB) (*e.User, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.User, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.User{} + setCreate(input, &data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -16,14 +23,22 @@ func CreateData(input *e.User, dbx ...*gorm.DB) (*e.User, error) { tx = dg.I } - if err := tx.Create(&input).Error; err != nil { - return nil, err + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) } - return input, nil + pl.SetLogInfo(event, nil, "complete") + return &data, nil } -func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.User, *e.MetaDto, error) { +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.User, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") data := []e.User{} pagination := gh.Pagination{} count := int64(0) @@ -38,8 +53,6 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.User, *e.MetaDto, e tx = tx. Model(&e.User{}). - // Joins("Patient"). // if needed - // Preload("Patient"). // if needed Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). @@ -49,16 +62,25 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.User, *e.MetaDto, e if err == gorm.ErrRecordNotFound { return nil, &meta, nil } - return nil, nil, err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) } 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, dbx ...*gorm.DB) (*e.User, error) { +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.User, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.User{} var tx *gorm.DB @@ -69,13 +91,19 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.User, error) { } if err := tx.First(&data, input.Id).Error; err != nil { - return nil, err + 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(input e.User, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.User, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setUpdate(input, data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -83,10 +111,22 @@ func UpdateData(input e.User, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Save(&input).Error + 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 DeleteData(input *e.User, dbx ...*gorm.DB) error { +func DeleteData(data *e.User, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -94,5 +134,16 @@ func DeleteData(input *e.User, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Delete(input).Error + 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 } diff --git a/internal/use-case/main-use-case/user/middleware-runner.go b/internal/use-case/main-use-case/user/middleware-runner.go new file mode 100644 index 00000000..89b61c74 --- /dev/null +++ b/internal/use-case/main-use-case/user/middleware-runner.go @@ -0,0 +1,103 @@ +package user + +import ( + e "simrs-vx/internal/domain/main-entities/user" + 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.User) 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.User) 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.User) 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.User) 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.User) 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 +} diff --git a/internal/use-case/main-use-case/user/middleware.go b/internal/use-case/main-use-case/user/middleware.go index 208468b6..6cf33b97 100644 --- a/internal/use-case/main-use-case/user/middleware.go +++ b/internal/use-case/main-use-case/user/middleware.go @@ -1,159 +1,9 @@ package user -// pm "simrs-vx/internal/use-case/plugin/modifier" - -import ( - "fmt" - e "simrs-vx/internal/domain/main-entities/user" - pl "simrs-vx/pkg/logger" - pu "simrs-vx/pkg/use-case-helper" - - "gorm.io/gorm" -) - +// example of middleware // func init() { -// createPreMw = append(createPreMw, pm.ModifInput) -// createPreMw = append(createPreMw, pm.CheckData) +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) // } - -type middlewareExecutor struct { - Event *pl.Event - Tx *gorm.DB - MwType pu.MWType -} - -// NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareExecutor(event *pl.Event, tx *gorm.DB) *middlewareExecutor { - return &middlewareExecutor{ - Event: event, - Tx: tx, - } -} - -// ExecuteCreateMiddleware executes create middleware -func (me *middlewareExecutor) ExecuteCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.User) error { - for i, middleware := range middlewares { - mwName := fmt.Sprintf("%s[%d]", me.MwType, i) - - pl.SetLogInfo(me.Event, data, "started", mwName) - - if err := middleware(input, data, me.Tx); err != nil { - me.Event.Status = "failed" - me.Event.ErrInfo = pl.ErrorInfo{ - Code: pu.GetMiddlewareErrorCode(me.MwType), - Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), - Raw: err, - } - return pl.SetLogError(*me.Event, data) - } - - pl.SetLogInfo(me.Event, nil, "complete") - } - return nil -} - -func (me *middlewareExecutor) ExecuteReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.User) error { - for i, middleware := range middlewares { - mwName := fmt.Sprintf("%s[%d]", me.MwType, i) - - pl.SetLogInfo(me.Event, input, "started", mwName) - - if err := middleware(input, data, me.Tx); err != nil { - me.Event.Status = "failed" - me.Event.ErrInfo = pl.ErrorInfo{ - Code: pu.GetMiddlewareErrorCode(me.MwType), - Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), - Raw: err, - } - return pl.SetLogError(*me.Event, input) - } - - pl.SetLogInfo(me.Event, nil, "complete") - } - return nil -} - -func (me *middlewareExecutor) ExecuteReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User) error { - for i, middleware := range middlewares { - mwName := fmt.Sprintf("%s[%d]", me.MwType, i) - - // Use data for logging if available, otherwise use input - logData := interface{}(input) - if data != nil { - logData = data - } - - pl.SetLogInfo(me.Event, logData, "started", mwName) - - if err := middleware(input, data, me.Tx); err != nil { - me.Event.Status = "failed" - me.Event.ErrInfo = pl.ErrorInfo{ - Code: pu.GetMiddlewareErrorCode(me.MwType), - Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), - Raw: err, - } - return pl.SetLogError(*me.Event, logData) - } - - pl.SetLogInfo(me.Event, nil, "complete") - } - return nil -} - -func (me *middlewareExecutor) ExecuteUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User) error { - for i, middleware := range middlewares { - mwName := fmt.Sprintf("%s[%d]", me.MwType, i) - - // Use data for logging if available, otherwise use input - logData := interface{}(input) - if data != nil { - logData = data - } - - pl.SetLogInfo(me.Event, logData, "started", mwName) - - if err := middleware(input, data, me.Tx); err != nil { - me.Event.Status = "failed" - me.Event.ErrInfo = pl.ErrorInfo{ - Code: pu.GetMiddlewareErrorCode(me.MwType), - Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), - Raw: err, - } - return pl.SetLogError(*me.Event, logData) - } - - pl.SetLogInfo(me.Event, nil, "complete") - } - return nil -} - -func (me *middlewareExecutor) ExecuteDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.User) error { - for i, middleware := range middlewares { - mwName := fmt.Sprintf("%s[%d]", me.MwType, i) - - // Use data for logging if available, otherwise use input - logData := interface{}(input) - if data != nil { - logData = data - } - - pl.SetLogInfo(me.Event, logData, "started", mwName) - - if err := middleware(input, data, me.Tx); err != nil { - me.Event.Status = "failed" - me.Event.ErrInfo = pl.ErrorInfo{ - Code: pu.GetMiddlewareErrorCode(me.MwType), - Detail: fmt.Sprintf("%s middleware %s failed", me.MwType, mwName), - Raw: err, - } - return pl.SetLogError(*me.Event, logData) - } - - pl.SetLogInfo(me.Event, nil, "complete") - } - return nil -} - -func (me *middlewareExecutor) setMwtype(mwType pu.MWType) { - me.MwType = mwType -} diff --git a/internal/use-case/main-use-case/user/tycovar.go b/internal/use-case/main-use-case/user/tycovar.go index e8d564df..1fc948e4 100644 --- a/internal/use-case/main-use-case/user/tycovar.go +++ b/internal/use-case/main-use-case/user/tycovar.go @@ -14,11 +14,23 @@ import ( e "simrs-vx/internal/domain/main-entities/user" ) -type createMw func(input *e.CreateDto, data *e.User, tx *gorm.DB) error -type readListMw func(input *e.ReadListDto, data *e.User, tx *gorm.DB) error -type readDetailMw func(input *e.ReadDetailDto, data *e.User, tx *gorm.DB) error -type updateMw func(input *e.ReadDetailDto, data *e.User, tx *gorm.DB) error -type deleteMw func(input *e.ReadDetailDto, data *e.User, tx *gorm.DB) error +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.User, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.User, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.User, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware diff --git a/internal/use-case/main-use-case/village/case.go b/internal/use-case/main-use-case/village/case.go index dbcc501a..dbdeb33d 100644 --- a/internal/use-case/main-use-case/village/case.go +++ b/internal/use-case/main-use-case/village/case.go @@ -1,7 +1,6 @@ package village import ( - "fmt" e "simrs-vx/internal/domain/main-entities/village" "strconv" @@ -19,8 +18,6 @@ const source = "village" func Create(input e.CreateDto) (*d.Data, error) { data := e.Village{} - setData(&input, &data) - event := pl.Event{ Feature: "Create", Source: source, @@ -30,51 +27,23 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { - for i := range createPreMw { - mwName := fmt.Sprintf("createPreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := createPreMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBCreate") - _, err := CreateData(&data, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", - Raw: err, - } - return pl.SetLogError(event, data) + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + data = *resData } - pl.SetLogInfo(&event, nil, "complete") - - for i := range createPostMw { - mwName := fmt.Sprintf("createPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - if err := createPostMw[i](&input, &data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") @@ -111,54 +80,21 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readListPreMw { - mwName := fmt.Sprintf("readListPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadList") - dataList, metaList, err = ReadListData(input, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-list-fail", - Detail: "Database read list failed", - Raw: err, - } - return pl.SetLogError(event, input) + if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range readListPostMw { - mwName := fmt.Sprintf("readListPostMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readListPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { + return err } return nil @@ -194,46 +130,21 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - for i := range readDetailPreMw { - mwName := fmt.Sprintf("readDetailPreMw[%d]", i) - - pl.SetLogInfo(&event, input, "started", mwName) - - if err := readDetailPreMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, input) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "DBReadDetail") - data, err = ReadDetailData(input, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(input, &event, tx); err != nil { + return err } - for i := range readDetailPostMw { - mwName := fmt.Sprintf("readDetailPostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := readDetailPostMw[i](&input, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { + return err } return nil @@ -249,7 +160,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { "structure": "single-data", "status": "fetched", }, - Data: pu.SafeToResponse(data), + Data: data.ToResponse(), }, nil } @@ -268,61 +179,27 @@ func Update(input e.UpdateDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if processedErr := pu.HandleReadError(err, &event, source, input.Id, data); processedErr != nil { - return processedErr + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, input, "started", "setUpdate") - setData(&input, data) - - for i := range updatePreMw { - mwName := fmt.Sprintf("updatePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBUpdate") - if err := UpdateData(*data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := UpdateData(input, data, &event, tx); err != nil { + return err } pl.SetLogInfo(&event, nil, "complete") - for i := range updatePostMw { - mwName := fmt.Sprintf("updatePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := updatePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - 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 @@ -358,66 +235,25 @@ func Delete(input e.DeleteDto) (*d.Data, error) { err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") - data, err = ReadDetailData(rdDto, tx) - if err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-read-detail-fail", - Detail: "Database read detail failed", - Raw: err, - } - return pl.SetLogError(event, rdDto) + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range deletePreMw { - mwName := fmt.Sprintf("deletePreMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePreMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_PRE_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err } - pl.SetLogInfo(&event, data, "started", "DBDelete") - if err := DeleteData(data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-delete-fail", - Detail: "Database delete failed", - Raw: err, - } - return pl.SetLogError(event, data) + if err := DeleteData(data, &event, tx); err != nil { + return err } - pl.SetLogInfo(&event, nil, "complete") - - for i := range deletePostMw { - mwName := fmt.Sprintf("deletePostMw[%d]", i) - - pl.SetLogInfo(&event, data, "started", mwName) - - if err := deletePostMw[i](&rdDto, data, tx); err != nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "MW_POST_FAILED", // TODO: add to lang json - Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: err, - } - return pl.SetLogError(event, data) - } - - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + return err } return nil diff --git a/internal/use-case/main-use-case/village/lib.go b/internal/use-case/main-use-case/village/lib.go index aec8e05a..154f1fb9 100644 --- a/internal/use-case/main-use-case/village/lib.go +++ b/internal/use-case/main-use-case/village/lib.go @@ -2,13 +2,20 @@ package village import ( e "simrs-vx/internal/domain/main-entities/village" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input *e.Village, dbx ...*gorm.DB) (*e.Village, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Village, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Village{} + setData(&input, &data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -16,14 +23,22 @@ func CreateData(input *e.Village, dbx ...*gorm.DB) (*e.Village, error) { tx = dg.I } - if err := tx.Create(&input).Error; err != nil { - return nil, err + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) } - return input, nil + pl.SetLogInfo(event, nil, "complete") + return &data, nil } -func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Village, *e.MetaDto, error) { +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Village, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") data := []e.Village{} pagination := gh.Pagination{} count := int64(0) @@ -38,8 +53,6 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Village, *e.MetaDto tx = tx. Model(&e.Village{}). - // Joins("Patient"). // if needed - // Preload("Patient"). // if needed Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)) @@ -48,16 +61,25 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Village, *e.MetaDto if err == gorm.ErrRecordNotFound { return nil, &meta, nil } - return nil, nil, err + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) } 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, dbx ...*gorm.DB) (*e.Village, error) { +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Village, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") data := e.Village{} var tx *gorm.DB @@ -68,13 +90,19 @@ func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Village, error) } if err := tx.First(&data, input.Id).Error; err != nil { - return nil, err + 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(input e.Village, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.Village, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBUpdate") + setData(&input, data) + var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -82,10 +110,22 @@ func UpdateData(input e.Village, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Save(&input).Error + 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 DeleteData(input *e.Village, dbx ...*gorm.DB) error { +func DeleteData(data *e.Village, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { tx = dbx[0] @@ -93,5 +133,16 @@ func DeleteData(input *e.Village, dbx ...*gorm.DB) error { tx = dg.I } - return tx.Delete(input).Error + 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 } diff --git a/internal/use-case/main-use-case/village/middleware-runner.go b/internal/use-case/main-use-case/village/middleware-runner.go new file mode 100644 index 00000000..db1d2c0c --- /dev/null +++ b/internal/use-case/main-use-case/village/middleware-runner.go @@ -0,0 +1,103 @@ +package village + +import ( + e "simrs-vx/internal/domain/main-entities/village" + 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.Village) 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.Village) 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.Village) 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.Village) 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.Village) 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 +} diff --git a/internal/use-case/main-use-case/village/middleware.go b/internal/use-case/main-use-case/village/middleware.go new file mode 100644 index 00000000..3a113862 --- /dev/null +++ b/internal/use-case/main-use-case/village/middleware.go @@ -0,0 +1,9 @@ +package village + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/village/tycovar.go b/internal/use-case/main-use-case/village/tycovar.go index e1aa31c5..0ca1b412 100644 --- a/internal/use-case/main-use-case/village/tycovar.go +++ b/internal/use-case/main-use-case/village/tycovar.go @@ -14,11 +14,23 @@ import ( e "simrs-vx/internal/domain/main-entities/village" ) -type createMw func(input *e.CreateDto, data *e.Village, tx *gorm.DB) error -type readListMw func(input *e.ReadListDto, data *e.Village, tx *gorm.DB) error -type readDetailMw func(input *e.ReadDetailDto, data *e.Village, tx *gorm.DB) error -type updateMw func(input *e.ReadDetailDto, data *e.Village, tx *gorm.DB) error -type deleteMw func(input *e.ReadDetailDto, data *e.Village, tx *gorm.DB) error +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Village, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Village, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Village, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 73f884bd..8666e56b 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -49,7 +49,7 @@ func SetLogInfo(e *Event, data any, args ...string) { Send() } -func SetLogError(e Event, data any) error { +func SetLogError(e *Event, data any) error { dataString, _ := json.Marshal(data) msg := l.I.Msg(e.ErrInfo.Code) diff --git a/pkg/use-case-helper/use-case-helper.go b/pkg/use-case-helper/use-case-helper.go index 999bc732..b88db3b4 100644 --- a/pkg/use-case-helper/use-case-helper.go +++ b/pkg/use-case-helper/use-case-helper.go @@ -20,6 +20,10 @@ func SafeToResponse[T any](data *T) any { return converter.ToResponse() } + if converter, ok := any(*data).(interface{ ToResponse() any }); ok { + return converter.ToResponse() + } + return nil } @@ -45,7 +49,7 @@ func HandleReadError(err error, event *pl.Event, itemType string, id interface{} } } - return pl.SetLogError(*event, nil) + return pl.SetLogError(event, nil) } func GetMiddlewareErrorCode(mwType MWType) string { @@ -54,3 +58,21 @@ func GetMiddlewareErrorCode(mwType MWType) string { } return "MW_POST_FAILED" } + +// GetLogData returns whichever of data or input is non-nil (prefers data) +func GetLogData(input interface{}, data interface{}) interface{} { + if data != nil { + return data + } + return input +} + +func HandleMiddlewareError(event *pl.Event, mwType, mwName string, logData interface{}, err error) error { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: GetMiddlewareErrorCode(MWType(mwType)), + Detail: fmt.Sprintf("%s middleware %s failed", mwType, mwName), + Raw: err, + } + return pl.SetLogError(event, logData) +} From 497d2094562f3dee9df5fa29d5dfbe94308dbfdd Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 25 Aug 2025 09:41:07 +0700 Subject: [PATCH 16/40] add logger output --- .../interface/main-handler/main-handler.go | 2 ++ pkg/zerolog-ctx/zerolog-ctx.go | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 pkg/zerolog-ctx/zerolog-ctx.go diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index d066f8ff..91deb4b1 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -20,6 +20,7 @@ import ( hc "simrs-vx/pkg/handler-crud-helper" lh "simrs-vx/pkg/lang-helper" handlerlogger "simrs-vx/pkg/middleware/handler-logger" + zlc "simrs-vx/pkg/zerolog-ctx" /******************** sources ********************/ division "simrs-vx/internal/interface/main-handler/division" @@ -40,6 +41,7 @@ import ( func SetRoutes() http.Handler { ///// a.RegisterExtCall(gs.Adjust) + a.RegisterExtCall(zlc.Adjust) a.RegisterExtCall(ssdb.Init) a.RegisterExtCall(lh.Populate) diff --git a/pkg/zerolog-ctx/zerolog-ctx.go b/pkg/zerolog-ctx/zerolog-ctx.go new file mode 100644 index 00000000..461b26bd --- /dev/null +++ b/pkg/zerolog-ctx/zerolog-ctx.go @@ -0,0 +1,26 @@ +package zerologctx + +import ( + "fmt" + "os" + + lz "github.com/karincake/apem/logger-zerolog" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +func Adjust() { + lz.Ctx = log.Output(zerolog.ConsoleWriter{ + Out: os.Stdout, + TimeFormat: "2006/01/02 15:04:05", + NoColor: true, + PartsOrder: []string{"time", "method", "status", "path", "query", "message"}, + FieldsExclude: []string{"time", "scope", "method", "status", "path", "query"}, + FormatFieldValue: func(i interface{}) string { + if i == nil { + return "" + } + return fmt.Sprintf("%v", i) + }, + }).With() +} From 4d10a8f99f885c8112ac21f3ca87fc9f7a8d21da Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 25 Aug 2025 09:41:27 +0700 Subject: [PATCH 17/40] feat (user): add sanitize to hide password for log --- internal/domain/main-entities/user/dto.go | 6 ++++++ internal/use-case/main-use-case/user/case.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index 87ce62d0..b3c2cac8 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -75,3 +75,9 @@ func ToResponseList(users []User) []ResponseDto { } return resp } + +func (c CreateDto) Sanitize() CreateDto { + sanitized := c + sanitized.Password = "[REDACTED]" + return sanitized +} diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index 85902fc6..63d59d0f 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -24,7 +24,7 @@ func Create(input e.CreateDto) (*d.Data, error) { } // Start log - pl.SetLogInfo(&event, input, "started", "create") + pl.SetLogInfo(&event, input.Sanitize(), "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { mwRunner := newMiddlewareRunner(&event, tx) From d10b92c7b1eac14656c351bab477e2dea03ed8f6 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 25 Aug 2025 09:57:55 +0700 Subject: [PATCH 18/40] feat (user): add block and active --- .../interface/main-handler/main-handler.go | 10 +- .../interface/main-handler/user/handler.go | 24 +++++ internal/use-case/main-use-case/user/case.go | 102 +++++++++++++++++- 3 files changed, 131 insertions(+), 5 deletions(-) diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 91deb4b1..9d0d549f 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -54,7 +54,15 @@ func SetRoutes() http.Handler { // r.HandleFunc("POST /v1/authentication/logout", auth.Logout) hk.Route("POST /v1/authentication/logout", r, auth.GuardMW, auth.Logout) - hc.RegCrud(r, "/v1/user", user.O) + hk.GroupRoutes("/v1/user", r, hk.MapHandlerFunc{ + "GET /": user.O.GetList, + "GET /{id}": user.O.GetDetail, + "POST /": user.O.Create, + "PATCH /{id}": user.O.Update, + "DELETE /{id}": user.O.Delete, + "PATCH /{id}/block": user.O.Block, + "PATCH /{id}/active": user.O.Active, + }) /******************** sources ********************/ hc.RegCrud(r, "/v1/division", division.O) diff --git a/internal/interface/main-handler/user/handler.go b/internal/interface/main-handler/user/handler.go index 99ea784b..a4f49d0d 100644 --- a/internal/interface/main-handler/user/handler.go +++ b/internal/interface/main-handler/user/handler.go @@ -69,3 +69,27 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { res, err := u.Delete(dto) rw.DataResponse(w, res, err) } + +func (obj myBase) Block(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.Block(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Active(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.Active(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index 63d59d0f..fd252bac 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -1,16 +1,18 @@ package user import ( - e "simrs-vx/internal/domain/main-entities/user" "strconv" - dg "github.com/karincake/apem/db-gorm-pg" - d "github.com/karincake/dodol" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/user" + erc "simrs-vx/internal/domain/references/common" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" - "gorm.io/gorm" + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" ) const source = "user" @@ -273,3 +275,95 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func Block(input e.ReadDetailDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.User + var err error + + event := pl.Event{ + Feature: "Block", + 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 data != nil { + pl.SetLogInfo(&event, rdDto, "started", "DBUpdate") + data.Status_Code = erc.SCBlocked + if err := tx.Save(&data).Error; 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 Active(input e.ReadDetailDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.User + var err error + + event := pl.Event{ + Feature: "Active", + 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 data != nil { + pl.SetLogInfo(&event, rdDto, "started", "DBUpdate") + data.Status_Code = erc.SCActive + if err := tx.Save(&data).Error; 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 + +} From 280d37357644f1ccf904af4cd3fca1190bbfaaf9 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 25 Aug 2025 14:07:14 +0700 Subject: [PATCH 19/40] feat (crud): add person, person-contact, person-address --- ...{20250820083721.sql => 20250825054027.sql} | 44 +++ cmd/migration/migrations/20250825060522.sql | 2 + cmd/migration/migrations/atlas.sum | 5 +- go.mod | 2 +- .../domain/main-entities/division copy/dto.go | 68 +++++ .../main-entities/division copy/entity.go | 12 + .../main-entities/person-address/dto.go | 72 +++++ .../main-entities/person-address/entity.go | 14 + .../main-entities/person-contact/dto.go | 65 +++++ .../main-entities/person-contact/entity.go | 13 + internal/domain/main-entities/person/dto.go | 100 +++++++ .../domain/main-entities/person/entity.go | 26 ++ internal/domain/references/person/person.go | 76 +++-- .../interface/main-handler/main-handler.go | 9 + .../main-handler/person-address/handler.go | 71 +++++ .../main-handler/person-contact/handler.go | 71 +++++ .../interface/main-handler/person/handler.go | 71 +++++ internal/interface/migration/migration.go | 6 + .../use-case/main-use-case/district/lib.go | 4 +- .../main-use-case/division-position/lib.go | 4 +- .../use-case/main-use-case/division/lib.go | 5 +- .../main-use-case/installation/lib.go | 5 +- .../main-use-case/person-address/case.go | 275 ++++++++++++++++++ .../main-use-case/person-address/helper.go | 25 ++ .../main-use-case/person-address/lib.go | 149 ++++++++++ .../person-address/middleware-runner.go | 103 +++++++ .../person-address/middleware.go | 9 + .../main-use-case/person-address/tycovar.go | 44 +++ .../main-use-case/person-contact/case.go | 275 ++++++++++++++++++ .../main-use-case/person-contact/helper.go | 23 ++ .../main-use-case/person-contact/lib.go | 149 ++++++++++ .../person-contact/middleware-runner.go | 103 +++++++ .../person-contact/middleware.go | 9 + .../main-use-case/person-contact/tycovar.go | 44 +++ .../use-case/main-use-case/person/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/person/helper.go | 30 ++ internal/use-case/main-use-case/person/lib.go | 151 ++++++++++ .../main-use-case/person/middleware-runner.go | 103 +++++++ .../main-use-case/person/middleware.go | 9 + .../use-case/main-use-case/person/tycovar.go | 44 +++ .../use-case/main-use-case/province/lib.go | 4 +- .../use-case/main-use-case/regency/lib.go | 4 +- internal/use-case/main-use-case/unit/lib.go | 4 +- internal/use-case/main-use-case/user/lib.go | 4 +- .../use-case/main-use-case/village/lib.go | 4 +- 45 files changed, 2536 insertions(+), 49 deletions(-) rename cmd/migration/migrations/{20250820083721.sql => 20250825054027.sql} (69%) create mode 100644 cmd/migration/migrations/20250825060522.sql create mode 100644 internal/domain/main-entities/division copy/dto.go create mode 100644 internal/domain/main-entities/division copy/entity.go create mode 100644 internal/domain/main-entities/person-address/dto.go create mode 100644 internal/domain/main-entities/person-address/entity.go create mode 100644 internal/domain/main-entities/person-contact/dto.go create mode 100644 internal/domain/main-entities/person-contact/entity.go create mode 100644 internal/domain/main-entities/person/dto.go create mode 100644 internal/domain/main-entities/person/entity.go create mode 100644 internal/interface/main-handler/person-address/handler.go create mode 100644 internal/interface/main-handler/person-contact/handler.go create mode 100644 internal/interface/main-handler/person/handler.go create mode 100644 internal/use-case/main-use-case/person-address/case.go create mode 100644 internal/use-case/main-use-case/person-address/helper.go create mode 100644 internal/use-case/main-use-case/person-address/lib.go create mode 100644 internal/use-case/main-use-case/person-address/middleware-runner.go create mode 100644 internal/use-case/main-use-case/person-address/middleware.go create mode 100644 internal/use-case/main-use-case/person-address/tycovar.go create mode 100644 internal/use-case/main-use-case/person-contact/case.go create mode 100644 internal/use-case/main-use-case/person-contact/helper.go create mode 100644 internal/use-case/main-use-case/person-contact/lib.go create mode 100644 internal/use-case/main-use-case/person-contact/middleware-runner.go create mode 100644 internal/use-case/main-use-case/person-contact/middleware.go create mode 100644 internal/use-case/main-use-case/person-contact/tycovar.go create mode 100644 internal/use-case/main-use-case/person/case.go create mode 100644 internal/use-case/main-use-case/person/helper.go create mode 100644 internal/use-case/main-use-case/person/lib.go create mode 100644 internal/use-case/main-use-case/person/middleware-runner.go create mode 100644 internal/use-case/main-use-case/person/middleware.go create mode 100644 internal/use-case/main-use-case/person/tycovar.go diff --git a/cmd/migration/migrations/20250820083721.sql b/cmd/migration/migrations/20250825054027.sql similarity index 69% rename from cmd/migration/migrations/20250820083721.sql rename to cmd/migration/migrations/20250825054027.sql index cee52edc..a0eb2358 100644 --- a/cmd/migration/migrations/20250820083721.sql +++ b/cmd/migration/migrations/20250825054027.sql @@ -66,6 +66,50 @@ CREATE TABLE "public"."DivisionPosition" ( CONSTRAINT "uni_DivisionPosition_Code" UNIQUE ("Code"), CONSTRAINT "fk_DivisionPosition_Division" FOREIGN KEY ("Division_Id") REFERENCES "public"."Division" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION ); +-- Create "Person" table +CREATE TABLE "public"."Person" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Name" character varying(150) NOT NULL, + "BirthDate" timestamptz NULL, + "BirthRegency_Code" character varying(4) NULL, + "Gender_Code" character varying(10) NULL, + "ResidentIdentityNumber" character varying(16) NULL, + "Religion_Code" character varying(10) NULL, + "Education_Code" character varying(10) NULL, + "Ocupation_Code" character varying(15) NULL, + "Ocupation_Name" character varying(50) NULL, + "Ethnic_Code" character varying(15) NULL, + PRIMARY KEY ("Id") +); +-- Create "PersonAddress" table +CREATE TABLE "public"."PersonAddress" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Person_Id" bigint NULL, + "Address" character varying(150) NULL, + "Rt" character varying(2) NULL, + "Rw" character varying(2) NULL, + "Village_Code" character varying(10) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Person_Addresses" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "PersonContact" table +CREATE TABLE "public"."PersonContact" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Person_Id" bigint NULL, + "Type_Code" character varying(10) NULL, + "Value" character varying(100) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Person_Contacts" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); -- Create "Installation" table CREATE TABLE "public"."Installation" ( "Id" serial NOT NULL, diff --git a/cmd/migration/migrations/20250825060522.sql b/cmd/migration/migrations/20250825060522.sql new file mode 100644 index 00000000..1c1306c1 --- /dev/null +++ b/cmd/migration/migrations/20250825060522.sql @@ -0,0 +1,2 @@ +-- Modify "PersonContact" table +ALTER TABLE "public"."PersonContact" ALTER COLUMN "Type_Code" TYPE character varying(15); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index b94d1d8d..7cb26096 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,2 +1,3 @@ -h1:BeM3qkN2alMJypXIeFt15SbwthvdFivDIoB6gVZayPM= -20250820083721.sql h1:I3MicNCsXGQJLAWD6axmyvjKZHEObHbF5WKfhQf1ijQ= +h1:0EV4fJWckR7Ma3cBvARIaNvZvwO/9rXVWEknYQ5KuS8= +20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= +20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= diff --git a/go.mod b/go.mod index daf9b4ff..da8ef314 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/karincake/lepet v0.0.1 github.com/karincake/risoles v0.0.3 github.com/karincake/semprit v0.0.3 + github.com/rs/zerolog v1.33.0 golang.org/x/crypto v0.41.0 gorm.io/driver/postgres v1.5.11 gorm.io/gorm v1.25.12 @@ -39,7 +40,6 @@ require ( github.com/mattn/go-sqlite3 v1.14.28 // indirect github.com/microsoft/go-mssqldb v1.7.2 // indirect github.com/nxadm/tail v1.4.11 // indirect - github.com/rs/zerolog v1.33.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.35.0 // indirect diff --git a/internal/domain/main-entities/division copy/dto.go b/internal/domain/main-entities/division copy/dto.go new file mode 100644 index 00000000..3d369cdf --- /dev/null +++ b/internal/domain/main-entities/division copy/dto.go @@ -0,0 +1,68 @@ +package division + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + Parent_Id *int16 `json:"parent_id"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + Parent_Id *int16 `json:"parent_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Parent_Id *int16 `json:"parent_id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + Parent_Id *int16 `json:"parent_id"` +} + +func (d Division) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + Parent_Id: d.Parent_Id, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(users []Division) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/division copy/entity.go b/internal/domain/main-entities/division copy/entity.go new file mode 100644 index 00000000..7d3bc65d --- /dev/null +++ b/internal/domain/main-entities/division copy/entity.go @@ -0,0 +1,12 @@ +package division + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type Division struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:50"` + Parent_Id *int16 `json:"parent_id"` +} diff --git a/internal/domain/main-entities/person-address/dto.go b/internal/domain/main-entities/person-address/dto.go new file mode 100644 index 00000000..7a4ba174 --- /dev/null +++ b/internal/domain/main-entities/person-address/dto.go @@ -0,0 +1,72 @@ +package personaddress + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Person_Id uint `json:"person_id"` + Address string `json:"address"` + Rt string `json:"rt"` + Rw string `json:"rw"` + Village_Code string `json:"village_code"` +} + +type ReadListDto struct { + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` + Person_Id uint `json:"person_id"` + Address string `json:"address"` + Rt string `json:"rt"` + Rw string `json:"rw"` + Village_Code string `json:"village_code"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Person_Id uint `json:"person_id"` + Address string `json:"address"` + Rt string `json:"rt"` + Rw string `json:"rw"` + Village_Code string `json:"village_code"` +} + +func (d PersonAddress) ToResponse() ResponseDto { + resp := ResponseDto{ + Person_Id: d.Person_Id, + Address: d.Address, + Rt: d.Rt, + Rw: d.Rw, + Village_Code: d.Village_Code, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(users []PersonAddress) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/person-address/entity.go b/internal/domain/main-entities/person-address/entity.go new file mode 100644 index 00000000..960b32a9 --- /dev/null +++ b/internal/domain/main-entities/person-address/entity.go @@ -0,0 +1,14 @@ +package personaddress + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type PersonAddress struct { + ecore.Main // adjust this according to the needs + Person_Id uint `json:"person_id"` + Address string `json:"address" gorm:"size:150"` + Rt string `json:"rt" gorm:"size:2"` + Rw string `json:"rw" gorm:"size:2"` + Village_Code string `json:"village_code" gorm:"size:10"` +} diff --git a/internal/domain/main-entities/person-contact/dto.go b/internal/domain/main-entities/person-contact/dto.go new file mode 100644 index 00000000..19104de3 --- /dev/null +++ b/internal/domain/main-entities/person-contact/dto.go @@ -0,0 +1,65 @@ +package personcontact + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erp "simrs-vx/internal/domain/references/person" +) + +type CreateDto struct { + Person_Id uint `json:"person_id"` + Type_Code erp.ContactTypeCode `json:"type_code"` + Value string `json:"value"` +} + +type ReadListDto struct { + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` + Person_Id uint `json:"person_id"` + Type_Code erp.ContactTypeCode `json:"type_code"` + Value string `json:"value"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Person_Id uint `json:"person_id"` + Type_Code erp.ContactTypeCode `json:"type_code"` + Value string `json:"value"` +} + +func (u *PersonContact) ToResponse() ResponseDto { + resp := ResponseDto{ + Person_Id: u.Person_Id, + Type_Code: u.Type_Code, + Value: u.Value, + } + resp.Main = u.Main + return resp +} + +func ToResponseList(users []PersonContact) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/person-contact/entity.go b/internal/domain/main-entities/person-contact/entity.go new file mode 100644 index 00000000..b39aa53e --- /dev/null +++ b/internal/domain/main-entities/person-contact/entity.go @@ -0,0 +1,13 @@ +package personcontact + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erp "simrs-vx/internal/domain/references/person" +) + +type PersonContact struct { + ecore.Main // adjust this according to the needs + Person_Id uint `json:"person_id"` + Type_Code erp.ContactTypeCode `json:"type_code" gorm:"size:15"` + Value string `json:"value" gorm:"size:100"` +} diff --git a/internal/domain/main-entities/person/dto.go b/internal/domain/main-entities/person/dto.go new file mode 100644 index 00000000..061c960b --- /dev/null +++ b/internal/domain/main-entities/person/dto.go @@ -0,0 +1,100 @@ +package person + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + epa "simrs-vx/internal/domain/main-entities/person-address" + epc "simrs-vx/internal/domain/main-entities/person-contact" + erp "simrs-vx/internal/domain/references/person" + "time" +) + +type CreateDto struct { + Name string `json:"name"` + BirthDate *time.Time `json:"birthDate,omitempty"` + BirthRegency_Code *string `json:"birthRegency_code"` + Gender_Code *erp.GenderCode `json:"gender_code"` + ResidentIdentityNumber *string `json:"residentIdentityNumber"` + Religion_Code *erp.ReligionCode `json:"religion_code"` + Education_Code *erp.EducationCode `json:"education_code"` + Ocupation_Code *erp.OcupationCode `json:"occupation_code"` + Ocupation_Name *string `json:"occupation_name"` + Ethnic_Code *erp.EthnicCode `json:"ethnic_code"` +} + +type ReadListDto struct { + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` + Name string `json:"name"` + BirthDate *time.Time `json:"birthDate,omitempty"` + BirthRegency_Code *string `json:"birthRegency_code"` + Gender_Code *erp.GenderCode `json:"gender_code"` + ResidentIdentityNumber *string `json:"residentIdentityNumber"` + Religion_Code *erp.ReligionCode `json:"religion_code"` + Education_Code *erp.EducationCode `json:"education_code"` + Ocupation_Code *erp.OcupationCode `json:"occupation_code"` + Ocupation_Name *string `json:"occupation_name"` + Ethnic_Code *erp.EthnicCode `json:"ethnic_code"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Name string `json:"name"` + BirthDate *time.Time `json:"birthDate,omitempty"` + BirthRegency_Code *string `json:"birthRegency_code"` + Gender_Code *erp.GenderCode `json:"gender_code"` + ResidentIdentityNumber *string `json:"residentIdentityNumber"` + Religion_Code *erp.ReligionCode `json:"religion_code"` + Education_Code *erp.EducationCode `json:"education_code"` + Ocupation_Code *erp.OcupationCode `json:"occupation_code"` + Ocupation_Name *string `json:"occupation_name"` + Ethnic_Code *erp.EthnicCode `json:"ethnic_code"` + Addresses *[]epa.PersonAddress `json:"addresses,omitempty"` + Contacts *[]epc.PersonContact `json:"contacts,omitempty"` +} + +func (u *Person) ToResponse() ResponseDto { + resp := ResponseDto{ + Name: u.Name, + BirthDate: u.BirthDate, + BirthRegency_Code: u.BirthRegency_Code, + Gender_Code: u.Gender_Code, + ResidentIdentityNumber: u.ResidentIdentityNumber, + Religion_Code: u.Religion_Code, + Education_Code: u.Education_Code, + Ocupation_Code: u.Ocupation_Code, + Ocupation_Name: u.Ocupation_Name, + Ethnic_Code: u.Ethnic_Code, + Addresses: u.Addresses, + Contacts: u.Contacts, + } + resp.Main = u.Main + return resp +} + +func ToResponseList(users []Person) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/person/entity.go b/internal/domain/main-entities/person/entity.go new file mode 100644 index 00000000..337b506f --- /dev/null +++ b/internal/domain/main-entities/person/entity.go @@ -0,0 +1,26 @@ +package person + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + epa "simrs-vx/internal/domain/main-entities/person-address" + epc "simrs-vx/internal/domain/main-entities/person-contact" + erp "simrs-vx/internal/domain/references/person" + + "time" +) + +type Person struct { + ecore.Main // adjust this according to the needs + Name string `json:"name" gorm:"not null;size:150"` + BirthDate *time.Time `json:"birthDate,omitempty"` + BirthRegency_Code *string `json:"birthRegency_code" gorm:"size:4"` + Gender_Code *erp.GenderCode `json:"gender_code" gorm:"size:10"` + ResidentIdentityNumber *string `json:"residentIdentityNumber" gorm:"size:16"` + Religion_Code *erp.ReligionCode `json:"religion_code" gorm:"size:10"` + Education_Code *erp.EducationCode `json:"education_code" gorm:"size:10"` + Ocupation_Code *erp.OcupationCode `json:"occupation_code" gorm:"size:15"` + Ocupation_Name *string `json:"occupation_name" gorm:"size:50"` + Ethnic_Code *erp.EthnicCode `json:"ethnic_code" gorm:"size:15"` + Addresses *[]epa.PersonAddress `json:"addresses" gorm:"foreignKey:Person_Id"` + Contacts *[]epc.PersonContact `json:"contacts" gorm:"foreignKey:Person_Id"` +} diff --git a/internal/domain/references/person/person.go b/internal/domain/references/person/person.go index fdd1a30b..0fb3fe27 100644 --- a/internal/domain/references/person/person.go +++ b/internal/domain/references/person/person.go @@ -6,17 +6,19 @@ type ( MaritalStatusCode string ReligionCode string EducationCode string - ProfessionCode string + OcupationCode string AgeGroupCode string AgeGroupForMedicineCode string RelativeCode string + ContactTypeCode string + EthnicCode string ) const ( - GCMale GenderCode = "male" - GCFemale GenderCode = "female" - GCOther GenderCode = "other" - GCUnknown GenderCode = "unknown" + GCMale GenderCode = "male" + GCFemale GenderCode = "female" + GCNotStated GenderCode = "not-stated" + GCUnknown GenderCode = "unknown" ) const ( @@ -44,7 +46,6 @@ const ( RCHindu ReligionCode = "hindu" RCBudha ReligionCode = "budha" RCKonghucu ReligionCode = "konghucu" - RCPenghayat ReligionCode = "penghayat" ) const ( @@ -63,12 +64,14 @@ const ( ) const ( - PCTidakBekerja ProfessionCode = "-" - PCPns ProfessionCode = "pns" - PCTniPolri ProfessionCode = "tni-polri" - PCBumn ProfessionCode = "bumn" - PCWiraswasta ProfessionCode = "wiraswasta" - PCLainlain ProfessionCode = "lainnya" + OCTidakBekerja OcupationCode = "tidak-bekerja" + OCPns OcupationCode = "pns" + OCTniPolisi OcupationCode = "polisi" + OCTni OcupationCode = "tni" + OCGuru OcupationCode = "guru" + OCWiraswasta OcupationCode = "wiraswasta" + OCKarySwasta OcupationCode = "kary-swasta" + OCLainlain OcupationCode = "lainnya" ) const ( @@ -107,12 +110,19 @@ const ( RCMPamanNenek RelativeCode = "nenek" ) +const ( + CTPhone ContactTypeCode = "phone" + CTMPhone ContactTypeCode = "m-phone" + CTEmail ContactTypeCode = "email" + CTFax ContactTypeCode = "fax" +) + func GetGenderCodes() map[GenderCode]string { return map[GenderCode]string{ - GCMale: "Laki-laki", - GCFemale: "Perempuan", - GCOther: "Lainnya", - GCUnknown: "Tidak diketahui", + GCMale: "Laki-laki", + GCFemale: "Perempuan", + GCNotStated: "Tidak disebutkan", + GCUnknown: "Tidak diketahui", } } @@ -146,7 +156,6 @@ func GetReligionCodes() map[ReligionCode]string { RCHindu: "Hindu", RCBudha: "Budha", RCKonghucu: "Konghucu", - RCPenghayat: "Penghayat", } } @@ -167,14 +176,16 @@ func GetEducationCodes() map[EducationCode]string { } } -func GetProfessions() map[ProfessionCode]string { - return map[ProfessionCode]string{ - PCTidakBekerja: "Tidak Bekerja", - PCPns: "PNS", - PCTniPolri: "TNI/POLRI", - PCBumn: "BUMN", - PCWiraswasta: "Pegawai Swasta / Wirausaha", - PCLainlain: "Lain-lain", +func GetProfessions() map[OcupationCode]string { + return map[OcupationCode]string{ + OCTidakBekerja: "Tidak Bekerja", + OCPns: "PNS", + OCTniPolisi: "Polisi", + OCTni: "TNI", + OCGuru: "Guru", + OCWiraswasta: "Wiraswasta", + OCKarySwasta: "Kary Swasta", + OCLainlain: "Lain-lain", } } @@ -220,6 +231,15 @@ func GetRelativeCodes() map[RelativeCode]string { } } +func GetContactTypeCodes() map[ContactTypeCode]string { + return map[ContactTypeCode]string{ + CTPhone: "Telepon", + CTMPhone: "Telepon Seluler", + CTEmail: "Email", + CTFax: "Fax", + } +} + func (obj GenderCode) String() string { return GetGenderCodes()[obj] } @@ -239,7 +259,7 @@ func (obj EducationCode) String() string { return GetEducationCodes()[obj] } -func (obj ProfessionCode) String() string { +func (obj OcupationCode) String() string { return GetProfessions()[obj] } @@ -250,3 +270,7 @@ func (obj AgeGroupCode) String() string { func (obj RelativeCode) String() string { return GetRelativeCodes()[obj] } + +func (obj ContactTypeCode) String() string { + return GetContactTypeCodes()[obj] +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 9d0d549f..c5bc4da1 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -5,6 +5,11 @@ import ( /******************** main / transaction ********************/ auth "simrs-vx/internal/interface/main-handler/authentication" + + /******************** actor ********************/ + person "simrs-vx/internal/interface/main-handler/person" + personaddress "simrs-vx/internal/interface/main-handler/person-address" + personcontact "simrs-vx/internal/interface/main-handler/person-contact" user "simrs-vx/internal/interface/main-handler/user" /******************** external ********************/ @@ -54,6 +59,7 @@ func SetRoutes() http.Handler { // r.HandleFunc("POST /v1/authentication/logout", auth.Logout) hk.Route("POST /v1/authentication/logout", r, auth.GuardMW, auth.Logout) + /******************** actor ********************/ hk.GroupRoutes("/v1/user", r, hk.MapHandlerFunc{ "GET /": user.O.GetList, "GET /{id}": user.O.GetDetail, @@ -63,6 +69,9 @@ func SetRoutes() http.Handler { "PATCH /{id}/block": user.O.Block, "PATCH /{id}/active": user.O.Active, }) + hc.RegCrud(r, "/v1/person", person.O) + hc.RegCrud(r, "/v1/person-address", personaddress.O) + hc.RegCrud(r, "/v1/person-contact", personcontact.O) /******************** sources ********************/ hc.RegCrud(r, "/v1/division", division.O) diff --git a/internal/interface/main-handler/person-address/handler.go b/internal/interface/main-handler/person-address/handler.go new file mode 100644 index 00000000..2b4ed0a8 --- /dev/null +++ b/internal/interface/main-handler/person-address/handler.go @@ -0,0 +1,71 @@ +package personaddress + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/person-address" + u "simrs-vx/internal/use-case/main-use-case/person-address" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(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.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/person-contact/handler.go b/internal/interface/main-handler/person-contact/handler.go new file mode 100644 index 00000000..b2cbb5bb --- /dev/null +++ b/internal/interface/main-handler/person-contact/handler.go @@ -0,0 +1,71 @@ +package personcontact + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/person-contact" + u "simrs-vx/internal/use-case/main-use-case/person-contact" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(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.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/person/handler.go b/internal/interface/main-handler/person/handler.go new file mode 100644 index 00000000..328273ec --- /dev/null +++ b/internal/interface/main-handler/person/handler.go @@ -0,0 +1,71 @@ +package person + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/person" + u "simrs-vx/internal/use-case/main-use-case/person" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(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.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 4f962b4b..5c332caa 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -9,6 +9,9 @@ import ( division "simrs-vx/internal/domain/main-entities/division" divisionposition "simrs-vx/internal/domain/main-entities/division-position" installation "simrs-vx/internal/domain/main-entities/installation" + person "simrs-vx/internal/domain/main-entities/person" + personaddress "simrs-vx/internal/domain/main-entities/person-address" + personcontact "simrs-vx/internal/domain/main-entities/person-contact" province "simrs-vx/internal/domain/main-entities/province" regency "simrs-vx/internal/domain/main-entities/regency" unit "simrs-vx/internal/domain/main-entities/unit" @@ -57,6 +60,9 @@ func GetEntities() []any { &district.District{}, ®ency.Regency{}, &province.Province{}, + &person.Person{}, + &personaddress.PersonAddress{}, + &personcontact.PersonContact{}, } } diff --git a/internal/use-case/main-use-case/district/lib.go b/internal/use-case/main-use-case/district/lib.go index 0f199d86..ba98ad06 100644 --- a/internal/use-case/main-use-case/district/lib.go +++ b/internal/use-case/main-use-case/district/lib.go @@ -63,8 +63,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", + Code: "data-get-fail", + Detail: "Database get failed", Raw: err, } return nil, nil, pl.SetLogError(event, input) diff --git a/internal/use-case/main-use-case/division-position/lib.go b/internal/use-case/main-use-case/division-position/lib.go index 2f0444ae..a09ec618 100644 --- a/internal/use-case/main-use-case/division-position/lib.go +++ b/internal/use-case/main-use-case/division-position/lib.go @@ -65,8 +65,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", + Code: "data-get-fail", + Detail: "Database get failed", Raw: err, } return nil, nil, pl.SetLogError(event, input) diff --git a/internal/use-case/main-use-case/division/lib.go b/internal/use-case/main-use-case/division/lib.go index 0acd085d..ad9de8ef 100644 --- a/internal/use-case/main-use-case/division/lib.go +++ b/internal/use-case/main-use-case/division/lib.go @@ -53,7 +53,6 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di tx = tx. Model(&e.Division{}). - Preload("Installation"). Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). @@ -65,8 +64,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", + Code: "data-get-fail", + Detail: "Database get failed", Raw: err, } return nil, nil, pl.SetLogError(event, input) diff --git a/internal/use-case/main-use-case/installation/lib.go b/internal/use-case/main-use-case/installation/lib.go index 05c8fac3..0cd9a6dc 100644 --- a/internal/use-case/main-use-case/installation/lib.go +++ b/internal/use-case/main-use-case/installation/lib.go @@ -53,7 +53,6 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.In tx = tx. Model(&e.Installation{}). - Preload("Installation"). Scopes(gh.Filter(input)). Count(&count). Scopes(gh.Paginate(input, &pagination)). @@ -65,8 +64,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.In } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", + Code: "data-get-fail", + Detail: "Database get failed", Raw: err, } return nil, nil, pl.SetLogError(event, input) diff --git a/internal/use-case/main-use-case/person-address/case.go b/internal/use-case/main-use-case/person-address/case.go new file mode 100644 index 00000000..1f354661 --- /dev/null +++ b/internal/use-case/main-use-case/person-address/case.go @@ -0,0 +1,275 @@ +package personaddress + +import ( + e "simrs-vx/internal/domain/main-entities/person-address" + "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" +) + +const source = "person-address" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.PersonAddress{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.PersonAddress + var dataList []e.PersonAddress + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.PersonAddress + 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.PersonAddress + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.PersonAddress + 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 + +} diff --git a/internal/use-case/main-use-case/person-address/helper.go b/internal/use-case/main-use-case/person-address/helper.go new file mode 100644 index 00000000..a09c7b57 --- /dev/null +++ b/internal/use-case/main-use-case/person-address/helper.go @@ -0,0 +1,25 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package personaddress + +import ( + e "simrs-vx/internal/domain/main-entities/person-address" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.PersonAddress) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Person_Id = inputSrc.Person_Id + data.Address = inputSrc.Address + data.Rt = inputSrc.Rt + data.Rw = inputSrc.Rw + data.Village_Code = inputSrc.Village_Code +} diff --git a/internal/use-case/main-use-case/person-address/lib.go b/internal/use-case/main-use-case/person-address/lib.go new file mode 100644 index 00000000..804600b1 --- /dev/null +++ b/internal/use-case/main-use-case/person-address/lib.go @@ -0,0 +1,149 @@ +package personaddress + +import ( + e "simrs-vx/internal/domain/main-entities/person-address" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.PersonAddress, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.PersonAddress{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.PersonAddress, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.PersonAddress{} + 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.PersonAddress{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.PersonAddress, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.PersonAddress{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.PersonAddress, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.PersonAddress, 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 +} diff --git a/internal/use-case/main-use-case/person-address/middleware-runner.go b/internal/use-case/main-use-case/person-address/middleware-runner.go new file mode 100644 index 00000000..13956853 --- /dev/null +++ b/internal/use-case/main-use-case/person-address/middleware-runner.go @@ -0,0 +1,103 @@ +package personaddress + +import ( + e "simrs-vx/internal/domain/main-entities/person-address" + 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.PersonAddress) 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.PersonAddress) 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.PersonAddress) 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.PersonAddress) 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.PersonAddress) 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 +} diff --git a/internal/use-case/main-use-case/person-address/middleware.go b/internal/use-case/main-use-case/person-address/middleware.go new file mode 100644 index 00000000..ad616e69 --- /dev/null +++ b/internal/use-case/main-use-case/person-address/middleware.go @@ -0,0 +1,9 @@ +package personaddress + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/person-address/tycovar.go b/internal/use-case/main-use-case/person-address/tycovar.go new file mode 100644 index 00000000..c417a27c --- /dev/null +++ b/internal/use-case/main-use-case/person-address/tycovar.go @@ -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 personaddress + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/person-address" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.PersonAddress, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.PersonAddress, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.PersonAddress, 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 diff --git a/internal/use-case/main-use-case/person-contact/case.go b/internal/use-case/main-use-case/person-contact/case.go new file mode 100644 index 00000000..10bf8408 --- /dev/null +++ b/internal/use-case/main-use-case/person-contact/case.go @@ -0,0 +1,275 @@ +package personcontact + +import ( + e "simrs-vx/internal/domain/main-entities/person-contact" + "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" +) + +const source = "person-contact" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.PersonContact{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.PersonContact + var dataList []e.PersonContact + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.PersonContact + 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.PersonContact + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.PersonContact + 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 + +} diff --git a/internal/use-case/main-use-case/person-contact/helper.go b/internal/use-case/main-use-case/person-contact/helper.go new file mode 100644 index 00000000..8be8f9a8 --- /dev/null +++ b/internal/use-case/main-use-case/person-contact/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package personcontact + +import ( + e "simrs-vx/internal/domain/main-entities/person-contact" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.PersonContact) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Person_Id = inputSrc.Person_Id + data.Type_Code = inputSrc.Type_Code + data.Value = inputSrc.Value +} diff --git a/internal/use-case/main-use-case/person-contact/lib.go b/internal/use-case/main-use-case/person-contact/lib.go new file mode 100644 index 00000000..75ba1110 --- /dev/null +++ b/internal/use-case/main-use-case/person-contact/lib.go @@ -0,0 +1,149 @@ +package personcontact + +import ( + e "simrs-vx/internal/domain/main-entities/person-contact" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.PersonContact, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.PersonContact{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.PersonContact, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.PersonContact{} + 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.PersonContact{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.PersonContact, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.PersonContact{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.PersonContact, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.PersonContact, 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 +} diff --git a/internal/use-case/main-use-case/person-contact/middleware-runner.go b/internal/use-case/main-use-case/person-contact/middleware-runner.go new file mode 100644 index 00000000..bf8b9e08 --- /dev/null +++ b/internal/use-case/main-use-case/person-contact/middleware-runner.go @@ -0,0 +1,103 @@ +package personcontact + +import ( + e "simrs-vx/internal/domain/main-entities/person-contact" + 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.PersonContact) 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.PersonContact) 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.PersonContact) 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.PersonContact) 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.PersonContact) 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 +} diff --git a/internal/use-case/main-use-case/person-contact/middleware.go b/internal/use-case/main-use-case/person-contact/middleware.go new file mode 100644 index 00000000..b246168c --- /dev/null +++ b/internal/use-case/main-use-case/person-contact/middleware.go @@ -0,0 +1,9 @@ +package personcontact + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/person-contact/tycovar.go b/internal/use-case/main-use-case/person-contact/tycovar.go new file mode 100644 index 00000000..09ce009a --- /dev/null +++ b/internal/use-case/main-use-case/person-contact/tycovar.go @@ -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 personcontact + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/person-contact" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.PersonContact, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.PersonContact, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.PersonContact, 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 diff --git a/internal/use-case/main-use-case/person/case.go b/internal/use-case/main-use-case/person/case.go new file mode 100644 index 00000000..a372c34a --- /dev/null +++ b/internal/use-case/main-use-case/person/case.go @@ -0,0 +1,275 @@ +package person + +import ( + e "simrs-vx/internal/domain/main-entities/person" + "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" +) + +const source = "person" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Person{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Person + var dataList []e.Person + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Person + 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.Person + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Person + 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 + +} diff --git a/internal/use-case/main-use-case/person/helper.go b/internal/use-case/main-use-case/person/helper.go new file mode 100644 index 00000000..32b4ff42 --- /dev/null +++ b/internal/use-case/main-use-case/person/helper.go @@ -0,0 +1,30 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package person + +import ( + e "simrs-vx/internal/domain/main-entities/person" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Person) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Name = inputSrc.Name + data.BirthDate = inputSrc.BirthDate + data.BirthRegency_Code = inputSrc.BirthRegency_Code + data.Gender_Code = inputSrc.Gender_Code + data.ResidentIdentityNumber = inputSrc.ResidentIdentityNumber + data.Religion_Code = inputSrc.Religion_Code + data.Education_Code = inputSrc.Education_Code + data.Ocupation_Code = inputSrc.Ocupation_Code + data.Ocupation_Name = inputSrc.Ocupation_Name + data.Ethnic_Code = inputSrc.Ethnic_Code +} diff --git a/internal/use-case/main-use-case/person/lib.go b/internal/use-case/main-use-case/person/lib.go new file mode 100644 index 00000000..430e8b69 --- /dev/null +++ b/internal/use-case/main-use-case/person/lib.go @@ -0,0 +1,151 @@ +package person + +import ( + e "simrs-vx/internal/domain/main-entities/person" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Person, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Person{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Person, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Person{} + 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.Person{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Person, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Person{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx.Preload("Contacts"). + Preload("Addresses") + if err := tx.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(input e.UpdateDto, data *e.Person, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Person, 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 +} diff --git a/internal/use-case/main-use-case/person/middleware-runner.go b/internal/use-case/main-use-case/person/middleware-runner.go new file mode 100644 index 00000000..1915343d --- /dev/null +++ b/internal/use-case/main-use-case/person/middleware-runner.go @@ -0,0 +1,103 @@ +package person + +import ( + e "simrs-vx/internal/domain/main-entities/person" + 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.Person) 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.Person) 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.Person) 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.Person) 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.Person) 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 +} diff --git a/internal/use-case/main-use-case/person/middleware.go b/internal/use-case/main-use-case/person/middleware.go new file mode 100644 index 00000000..301406e7 --- /dev/null +++ b/internal/use-case/main-use-case/person/middleware.go @@ -0,0 +1,9 @@ +package person + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/person/tycovar.go b/internal/use-case/main-use-case/person/tycovar.go new file mode 100644 index 00000000..6c59b858 --- /dev/null +++ b/internal/use-case/main-use-case/person/tycovar.go @@ -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 person + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/person" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Person, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Person, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Person, 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 diff --git a/internal/use-case/main-use-case/province/lib.go b/internal/use-case/main-use-case/province/lib.go index aaa53faa..b84db301 100644 --- a/internal/use-case/main-use-case/province/lib.go +++ b/internal/use-case/main-use-case/province/lib.go @@ -63,8 +63,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pr } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", + Code: "data-get-fail", + Detail: "Database get failed", Raw: err, } return nil, nil, pl.SetLogError(event, input) diff --git a/internal/use-case/main-use-case/regency/lib.go b/internal/use-case/main-use-case/regency/lib.go index 61577d9c..c098aabd 100644 --- a/internal/use-case/main-use-case/regency/lib.go +++ b/internal/use-case/main-use-case/regency/lib.go @@ -63,8 +63,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Re } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", + Code: "data-get-fail", + Detail: "Database get failed", Raw: err, } return nil, nil, pl.SetLogError(event, input) diff --git a/internal/use-case/main-use-case/unit/lib.go b/internal/use-case/main-use-case/unit/lib.go index 5a1776e6..d7aebcaf 100644 --- a/internal/use-case/main-use-case/unit/lib.go +++ b/internal/use-case/main-use-case/unit/lib.go @@ -65,8 +65,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Un } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", + Code: "data-get-fail", + Detail: "Database get failed", Raw: err, } return nil, nil, pl.SetLogError(event, input) diff --git a/internal/use-case/main-use-case/user/lib.go b/internal/use-case/main-use-case/user/lib.go index 40ad6e17..0af63c75 100644 --- a/internal/use-case/main-use-case/user/lib.go +++ b/internal/use-case/main-use-case/user/lib.go @@ -64,8 +64,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Us } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", + Code: "data-get-fail", + Detail: "Database get failed", Raw: err, } return nil, nil, pl.SetLogError(event, input) diff --git a/internal/use-case/main-use-case/village/lib.go b/internal/use-case/main-use-case/village/lib.go index 154f1fb9..c67f3ac4 100644 --- a/internal/use-case/main-use-case/village/lib.go +++ b/internal/use-case/main-use-case/village/lib.go @@ -63,8 +63,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Vi } event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "Database insert failed", + Code: "data-get-fail", + Detail: "Database get failed", Raw: err, } return nil, nil, pl.SetLogError(event, input) From f06286cbc6a8c721f21a4a7eb74bae258f8b0674 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 25 Aug 2025 17:28:14 +0700 Subject: [PATCH 20/40] diagnosesrc, proseduresrc, pharmacycompany --- .../{division copy => diagnose-src}/dto.go | 42 ++++++------ .../main-entities/diagnose-src/entity.go | 12 ++++ .../main-entities/division copy/entity.go | 12 ---- .../main-entities/pharmacy-company/dto.go | 68 +++++++++++++++++++ .../main-entities/pharmacy-company/entity.go | 12 ++++ .../domain/main-entities/procedure-src/dto.go | 68 +++++++++++++++++++ .../main-entities/procedure-src/entity.go | 12 ++++ internal/interface/migration/migration.go | 2 + 8 files changed, 195 insertions(+), 33 deletions(-) rename internal/domain/main-entities/{division copy => diagnose-src}/dto.go (50%) create mode 100644 internal/domain/main-entities/diagnose-src/entity.go delete mode 100644 internal/domain/main-entities/division copy/entity.go create mode 100644 internal/domain/main-entities/pharmacy-company/dto.go create mode 100644 internal/domain/main-entities/pharmacy-company/entity.go create mode 100644 internal/domain/main-entities/procedure-src/dto.go create mode 100644 internal/domain/main-entities/procedure-src/entity.go diff --git a/internal/domain/main-entities/division copy/dto.go b/internal/domain/main-entities/diagnose-src/dto.go similarity index 50% rename from internal/domain/main-entities/division copy/dto.go rename to internal/domain/main-entities/diagnose-src/dto.go index 3d369cdf..42db5c5d 100644 --- a/internal/domain/main-entities/division copy/dto.go +++ b/internal/domain/main-entities/diagnose-src/dto.go @@ -1,19 +1,19 @@ -package division +package diagnosesrc import ( ecore "simrs-vx/internal/domain/base-entities/core" ) type CreateDto struct { - Code string `json:"code"` - Name string `json:"name"` - Parent_Id *int16 `json:"parent_id"` + Code string `json:"code"` + Name string `json:"name"` + IndName string `json:"indName"` } type ReadListDto struct { - Code string `json:"code"` - Name string `json:"name"` - Parent_Id *int16 `json:"parent_id"` + Code string `json:"code"` + Name string `json:"name"` + IndName string `json:"indName"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -21,10 +21,10 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Parent_Id *int16 `json:"parent_id"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + IndName string `json:"indName"` } type UpdateDto struct { @@ -43,23 +43,23 @@ type MetaDto struct { } type ResponseDto struct { - ecore.SmallMain - Code string `json:"code"` - Name string `json:"name"` - Parent_Id *int16 `json:"parent_id"` + ecore.Main + Code string `json:"code"` + Name string `json:"name"` + IndName string `json:"indName"` } -func (d Division) ToResponse() ResponseDto { +func (d DiagnoseSrc) ToResponse() ResponseDto { resp := ResponseDto{ - Code: d.Code, - Name: d.Name, - Parent_Id: d.Parent_Id, + Code: d.Code, + Name: d.Name, + IndName: d.IndName, } - resp.SmallMain = d.SmallMain + resp.Main = d.Main return resp } -func ToResponseList(users []Division) []ResponseDto { +func ToResponseList(users []DiagnoseSrc) []ResponseDto { resp := make([]ResponseDto, len(users)) for i, u := range users { resp[i] = u.ToResponse() diff --git a/internal/domain/main-entities/diagnose-src/entity.go b/internal/domain/main-entities/diagnose-src/entity.go new file mode 100644 index 00000000..82d55bb5 --- /dev/null +++ b/internal/domain/main-entities/diagnose-src/entity.go @@ -0,0 +1,12 @@ +package diagnosesrc + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type DiagnoseSrc struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:2048"` + IndName string `json:"indName" gorm:"size:2048"` +} diff --git a/internal/domain/main-entities/division copy/entity.go b/internal/domain/main-entities/division copy/entity.go deleted file mode 100644 index 7d3bc65d..00000000 --- a/internal/domain/main-entities/division copy/entity.go +++ /dev/null @@ -1,12 +0,0 @@ -package division - -import ( - ecore "simrs-vx/internal/domain/base-entities/core" -) - -type Division struct { - ecore.SmallMain // adjust this according to the needs - Code string `json:"code" gorm:"unique;size:10"` - Name string `json:"name" gorm:"size:50"` - Parent_Id *int16 `json:"parent_id"` -} diff --git a/internal/domain/main-entities/pharmacy-company/dto.go b/internal/domain/main-entities/pharmacy-company/dto.go new file mode 100644 index 00000000..afd671ab --- /dev/null +++ b/internal/domain/main-entities/pharmacy-company/dto.go @@ -0,0 +1,68 @@ +package pharmacycompany + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + Regency_Code string `json:"regency_code"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + Regency_Code string `json:"regency_code"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Regency_Code string `json:"regency_code"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Code string `json:"code"` + Name string `json:"name"` + Regency_Code string `json:"regency_code"` +} + +func (d PharmacyCompany) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + Regency_Code: d.Regency_Code, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(users []PharmacyCompany) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/pharmacy-company/entity.go b/internal/domain/main-entities/pharmacy-company/entity.go new file mode 100644 index 00000000..ffd1495e --- /dev/null +++ b/internal/domain/main-entities/pharmacy-company/entity.go @@ -0,0 +1,12 @@ +package pharmacycompany + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type PharmacyCompany struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:20"` + Name string `json:"name" gorm:"size:100"` + Regency_Code string `json:"regency_code" gorm:"size:4"` +} diff --git a/internal/domain/main-entities/procedure-src/dto.go b/internal/domain/main-entities/procedure-src/dto.go new file mode 100644 index 00000000..05333300 --- /dev/null +++ b/internal/domain/main-entities/procedure-src/dto.go @@ -0,0 +1,68 @@ +package proceduresrc + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + IndName string `json:"indName"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + IndName string `json:"indName"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + IndName string `json:"indName"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Code string `json:"code"` + Name string `json:"name"` + IndName string `json:"indName"` +} + +func (d ProcedureSrc) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + IndName: d.IndName, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(users []ProcedureSrc) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/procedure-src/entity.go b/internal/domain/main-entities/procedure-src/entity.go new file mode 100644 index 00000000..2090a42d --- /dev/null +++ b/internal/domain/main-entities/procedure-src/entity.go @@ -0,0 +1,12 @@ +package proceduresrc + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type ProcedureSrc struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:2048"` + IndName string `json:"indName" gorm:"size:2048"` +} diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 5c332caa..9a56490a 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -12,6 +12,7 @@ import ( person "simrs-vx/internal/domain/main-entities/person" personaddress "simrs-vx/internal/domain/main-entities/person-address" personcontact "simrs-vx/internal/domain/main-entities/person-contact" + pharmacycompany "simrs-vx/internal/domain/main-entities/pharmacy-company" province "simrs-vx/internal/domain/main-entities/province" regency "simrs-vx/internal/domain/main-entities/regency" unit "simrs-vx/internal/domain/main-entities/unit" @@ -63,6 +64,7 @@ func GetEntities() []any { &person.Person{}, &personaddress.PersonAddress{}, &personcontact.PersonContact{}, + &pharmacycompany.PharmacyCompany{}, } } From d76c5de6dfd88bdd8f87eb84061d4efd5765cf33 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 25 Aug 2025 17:31:16 +0700 Subject: [PATCH 21/40] add sql script for diagnose and procedure src --- cmd/migration/migrations/20250825102900.sql | 12 +++++++++++ cmd/migration/migrations/20250825103029.sql | 24 +++++++++++++++++++++ cmd/migration/migrations/atlas.sum | 4 +++- internal/interface/migration/migration.go | 4 ++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 cmd/migration/migrations/20250825102900.sql create mode 100644 cmd/migration/migrations/20250825103029.sql diff --git a/cmd/migration/migrations/20250825102900.sql b/cmd/migration/migrations/20250825102900.sql new file mode 100644 index 00000000..766aca3d --- /dev/null +++ b/cmd/migration/migrations/20250825102900.sql @@ -0,0 +1,12 @@ +-- Create "PharmacyCompany" table +CREATE TABLE "public"."PharmacyCompany" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(100) NULL, + "Regency_Code" character varying(4) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_PharmacyCompany_Code" UNIQUE ("Code") +); diff --git a/cmd/migration/migrations/20250825103029.sql b/cmd/migration/migrations/20250825103029.sql new file mode 100644 index 00000000..9c3613c7 --- /dev/null +++ b/cmd/migration/migrations/20250825103029.sql @@ -0,0 +1,24 @@ +-- Create "DiagnoseSrc" table +CREATE TABLE "public"."DiagnoseSrc" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(2048) NULL, + "IndName" character varying(2048) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_DiagnoseSrc_Code" UNIQUE ("Code") +); +-- Create "ProcedureSrc" table +CREATE TABLE "public"."ProcedureSrc" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(2048) NULL, + "IndName" character varying(2048) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_ProcedureSrc_Code" UNIQUE ("Code") +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index 7cb26096..e9c29361 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,3 +1,5 @@ -h1:0EV4fJWckR7Ma3cBvARIaNvZvwO/9rXVWEknYQ5KuS8= +h1:kmaYH5ZWV4XqRaVulfE4cDvHlo2ANjTsI8kr9EIqJ7I= 20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= 20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= +20250825102900.sql h1:Xaz9cAKDx6ZjDByRBSNrX/d2/s8Xid2zhirWk62xKjQ= +20250825103029.sql h1:YkM0KTRRawcObTUOG3epXzBOW4wFyHIOlnh99FaVgPk= diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 9a56490a..beeb666e 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -5,6 +5,7 @@ import ( "io" "os" "os/exec" + diagnosesrc "simrs-vx/internal/domain/main-entities/diagnose-src" district "simrs-vx/internal/domain/main-entities/district" division "simrs-vx/internal/domain/main-entities/division" divisionposition "simrs-vx/internal/domain/main-entities/division-position" @@ -13,6 +14,7 @@ import ( personaddress "simrs-vx/internal/domain/main-entities/person-address" personcontact "simrs-vx/internal/domain/main-entities/person-contact" pharmacycompany "simrs-vx/internal/domain/main-entities/pharmacy-company" + proceduresrc "simrs-vx/internal/domain/main-entities/procedure-src" province "simrs-vx/internal/domain/main-entities/province" regency "simrs-vx/internal/domain/main-entities/regency" unit "simrs-vx/internal/domain/main-entities/unit" @@ -65,6 +67,8 @@ func GetEntities() []any { &personaddress.PersonAddress{}, &personcontact.PersonContact{}, &pharmacycompany.PharmacyCompany{}, + &diagnosesrc.DiagnoseSrc{}, + &proceduresrc.ProcedureSrc{}, } } From 3d22e8b7205e6ee52023ba366a0c565b0bdd4de1 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 09:20:16 +0700 Subject: [PATCH 22/40] add infragroup, employee, itemgroup, doctor, nurse, nutritionist, pharmacist, counter, practiceschedule --- cmd/migration/migrations/20250827015551.sql | 37 ++++++++ cmd/migration/migrations/20250827021904.sql | 77 ++++++++++++++++ cmd/migration/migrations/atlas.sum | 4 +- internal/domain/main-entities/counter/dto.go | 83 ++++++++++++++++++ .../domain/main-entities/counter/entity.go | 15 ++++ .../domain/main-entities/diagnose-src/dto.go | 6 +- internal/domain/main-entities/district/dto.go | 6 +- .../main-entities/division-position/dto.go | 6 +- internal/domain/main-entities/division/dto.go | 6 +- internal/domain/main-entities/doctor/dto.go | 79 +++++++++++++++++ .../domain/main-entities/doctor/entity.go | 17 ++++ internal/domain/main-entities/employee/dto.go | 87 +++++++++++++++++++ .../domain/main-entities/employee/entity.go | 18 ++++ .../domain/main-entities/infra-group/dto.go | 63 ++++++++++++++ .../main-entities/infra-group/entity.go | 11 +++ .../domain/main-entities/installation/dto.go | 16 ++-- .../domain/main-entities/item-group/dto.go | 63 ++++++++++++++ .../domain/main-entities/item-group/entity.go | 11 +++ internal/domain/main-entities/nurse/dto.go | 66 ++++++++++++++ internal/domain/main-entities/nurse/entity.go | 13 +++ .../domain/main-entities/nutritionist/dto.go | 66 ++++++++++++++ .../main-entities/nutritionist/entity.go | 13 +++ .../main-entities/person-address/dto.go | 6 +- .../main-entities/person-contact/dto.go | 16 ++-- internal/domain/main-entities/person/dto.go | 34 ++++---- .../domain/main-entities/pharmacist/dto.go | 66 ++++++++++++++ .../domain/main-entities/pharmacist/entity.go | 13 +++ .../main-entities/pharmacy-company/dto.go | 6 +- .../main-entities/practice-schedule/dto.go | 79 +++++++++++++++++ .../main-entities/practice-schedule/entity.go | 19 ++++ .../domain/main-entities/procedure-src/dto.go | 6 +- internal/domain/main-entities/province/dto.go | 6 +- internal/domain/main-entities/regency/dto.go | 10 +-- internal/domain/main-entities/unit/dto.go | 20 ++--- internal/domain/main-entities/user/dto.go | 20 ++--- internal/domain/main-entities/village/dto.go | 10 +-- internal/domain/references/common/common.go | 24 +++-- internal/interface/migration/migration.go | 18 ++++ 38 files changed, 1022 insertions(+), 94 deletions(-) create mode 100644 cmd/migration/migrations/20250827015551.sql create mode 100644 cmd/migration/migrations/20250827021904.sql create mode 100644 internal/domain/main-entities/counter/dto.go create mode 100644 internal/domain/main-entities/counter/entity.go create mode 100644 internal/domain/main-entities/doctor/dto.go create mode 100644 internal/domain/main-entities/doctor/entity.go create mode 100644 internal/domain/main-entities/employee/dto.go create mode 100644 internal/domain/main-entities/employee/entity.go create mode 100644 internal/domain/main-entities/infra-group/dto.go create mode 100644 internal/domain/main-entities/infra-group/entity.go create mode 100644 internal/domain/main-entities/item-group/dto.go create mode 100644 internal/domain/main-entities/item-group/entity.go create mode 100644 internal/domain/main-entities/nurse/dto.go create mode 100644 internal/domain/main-entities/nurse/entity.go create mode 100644 internal/domain/main-entities/nutritionist/dto.go create mode 100644 internal/domain/main-entities/nutritionist/entity.go create mode 100644 internal/domain/main-entities/pharmacist/dto.go create mode 100644 internal/domain/main-entities/pharmacist/entity.go create mode 100644 internal/domain/main-entities/practice-schedule/dto.go create mode 100644 internal/domain/main-entities/practice-schedule/entity.go diff --git a/cmd/migration/migrations/20250827015551.sql b/cmd/migration/migrations/20250827015551.sql new file mode 100644 index 00000000..7d9745db --- /dev/null +++ b/cmd/migration/migrations/20250827015551.sql @@ -0,0 +1,37 @@ +-- Create "InfraGroup" table +CREATE TABLE "public"."InfraGroup" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(50) NULL, + "Name" character varying(100) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_InfraGroup_Code" UNIQUE ("Code") +); +-- Create "ItemGroup" table +CREATE TABLE "public"."ItemGroup" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(50) NULL, + "Name" character varying(100) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_ItemGroup_Code" UNIQUE ("Code") +); +-- Create "Employee" table +CREATE TABLE "public"."Employee" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "User_Id" bigint NULL, + "Person_Id" bigint NULL, + "Position_Code" character varying(20) NOT NULL, + "Division_Code" character varying(10) NULL, + "Number" character varying(20) NULL, + "Status_Code" character varying(10) NOT NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Employee_Division" FOREIGN KEY ("Division_Code") REFERENCES "public"."Division" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/20250827021904.sql b/cmd/migration/migrations/20250827021904.sql new file mode 100644 index 00000000..cf990cc5 --- /dev/null +++ b/cmd/migration/migrations/20250827021904.sql @@ -0,0 +1,77 @@ +-- Create "Counter" table +CREATE TABLE "public"."Counter" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(30) NULL, + "Number" smallint NULL, + "Parent_Id" integer NULL, + "Type_Code" text NULL, + "Queue_Code" character varying(5) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Counter_Code" UNIQUE ("Code") +); +-- Create "Doctor" table +CREATE TABLE "public"."Doctor" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "IHS_Number" character varying(20) NULL, + "SIP_Number" character varying(20) NULL, + "Unit_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Doctor_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Doctor_Unit" FOREIGN KEY ("Unit_Id") REFERENCES "public"."Unit" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Nurse" table +CREATE TABLE "public"."Nurse" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "IHS_Number" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Nurse_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Nutritionist" table +CREATE TABLE "public"."Nutritionist" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "IHS_Number" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Nutritionist_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Pharmacist" table +CREATE TABLE "public"."Pharmacist" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "IHS_Number" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Pharmacist_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "PracticeSchedule" table +CREATE TABLE "public"."PracticeSchedule" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Doctor_Id" bigint NULL, + "Unit_Code" character varying(10) NULL, + "Day_Code" smallint NULL, + "StartTime" character varying(5) NULL, + "EndTime" character varying(5) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_PracticeSchedule_Doctor" FOREIGN KEY ("Doctor_Id") REFERENCES "public"."Doctor" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_PracticeSchedule_Unit" FOREIGN KEY ("Unit_Code") REFERENCES "public"."Unit" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index e9c29361..1d5fbd8b 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,5 +1,7 @@ -h1:kmaYH5ZWV4XqRaVulfE4cDvHlo2ANjTsI8kr9EIqJ7I= +h1:aACpl+MgcGmQ5IgTQGQ4o6+1pT9L8KphrWlGlKBguHc= 20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= 20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= 20250825102900.sql h1:Xaz9cAKDx6ZjDByRBSNrX/d2/s8Xid2zhirWk62xKjQ= 20250825103029.sql h1:YkM0KTRRawcObTUOG3epXzBOW4wFyHIOlnh99FaVgPk= +20250827015551.sql h1:iaN+FNEPyYn8pbc16yt1Jwo1Bf6jRePhKvoZht+RxdI= +20250827021904.sql h1:jxCNgxPGAHqU3z/tQBww7/9PnJQYl2Is2NFV5ZEeHIU= diff --git a/internal/domain/main-entities/counter/dto.go b/internal/domain/main-entities/counter/dto.go new file mode 100644 index 00000000..58e1a1d0 --- /dev/null +++ b/internal/domain/main-entities/counter/dto.go @@ -0,0 +1,83 @@ +package counter + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + Number uint8 `json:"number"` + Parent_Id *uint16 `json:"parent_id"` + Type_Code string `json:"type_code"` + Queue_Code string `json:"queue_code"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + Number uint8 `json:"number"` + Parent_Id *uint16 `json:"parent_id"` + Type_Code string `json:"type_code"` + Queue_Code string `json:"queue_code"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Number uint8 `json:"number"` + Parent_Id *uint16 `json:"parent_id"` + Type_Code string `json:"type_code"` + Queue_Code string `json:"queue_code"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + Number uint8 `json:"number"` + Parent_Id *uint16 `json:"parent_id"` + Type_Code string `json:"type_code"` + Queue_Code string `json:"queue_code"` +} + +func (d Counter) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + Number: d.Number, + Parent_Id: d.Parent_Id, + Type_Code: d.Type_Code, + Queue_Code: d.Queue_Code, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []Counter) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/counter/entity.go b/internal/domain/main-entities/counter/entity.go new file mode 100644 index 00000000..9c05c0fc --- /dev/null +++ b/internal/domain/main-entities/counter/entity.go @@ -0,0 +1,15 @@ +package counter + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type Counter struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:30"` + Number uint8 `json:"number" gorm:"size:10"` + Parent_Id *uint16 `json:"parent_id"` + Type_Code string `json:"type_code"` + Queue_Code string `json:"queue_code" gorm:"size:5"` +} diff --git a/internal/domain/main-entities/diagnose-src/dto.go b/internal/domain/main-entities/diagnose-src/dto.go index 42db5c5d..9e8736a1 100644 --- a/internal/domain/main-entities/diagnose-src/dto.go +++ b/internal/domain/main-entities/diagnose-src/dto.go @@ -59,9 +59,9 @@ func (d DiagnoseSrc) ToResponse() ResponseDto { return resp } -func ToResponseList(users []DiagnoseSrc) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []DiagnoseSrc) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/district/dto.go b/internal/domain/main-entities/district/dto.go index 156d97b3..850d4649 100644 --- a/internal/domain/main-entities/district/dto.go +++ b/internal/domain/main-entities/district/dto.go @@ -53,9 +53,9 @@ func (d District) ToResponse() ResponseDto { return resp } -func ToResponseList(users []District) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []District) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/division-position/dto.go b/internal/domain/main-entities/division-position/dto.go index fd9446fc..8dd18d0b 100644 --- a/internal/domain/main-entities/division-position/dto.go +++ b/internal/domain/main-entities/division-position/dto.go @@ -64,9 +64,9 @@ func (d DivisionPosition) ToResponse() ResponseDto { return resp } -func ToResponseList(users []DivisionPosition) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []DivisionPosition) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/division/dto.go b/internal/domain/main-entities/division/dto.go index 3d369cdf..d9d7b606 100644 --- a/internal/domain/main-entities/division/dto.go +++ b/internal/domain/main-entities/division/dto.go @@ -59,9 +59,9 @@ func (d Division) ToResponse() ResponseDto { return resp } -func ToResponseList(users []Division) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []Division) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/doctor/dto.go b/internal/domain/main-entities/doctor/dto.go new file mode 100644 index 00000000..f251fe59 --- /dev/null +++ b/internal/domain/main-entities/doctor/dto.go @@ -0,0 +1,79 @@ +package doctor + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" + eu "simrs-vx/internal/domain/main-entities/unit" +) + +type CreateDto struct { + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` + SIP_Number *string `json:"sip_number"` + Unit_Id *uint `json:"unit_id"` +} + +type ReadListDto struct { + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` + SIP_Number *string `json:"sip_number"` + Unit_Id *uint `json:"unit_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` + SIP_Number *string `json:"sip_number"` + Unit_Id *uint `json:"unit_id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty"` + IHS_Number *string `json:"ihs_number"` + SIP_Number *string `json:"sip_number"` + Unit_Id *uint `json:"unit_id"` + Unit *eu.Unit `json:"unit,omitempty"` +} + +func (d Doctor) ToResponse() ResponseDto { + resp := ResponseDto{ + Employee_Id: d.Employee_Id, + Employee: d.Employee, + IHS_Number: d.IHS_Number, + SIP_Number: d.SIP_Number, + Unit_Id: d.Unit_Id, + Unit: d.Unit, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Doctor) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/doctor/entity.go b/internal/domain/main-entities/doctor/entity.go new file mode 100644 index 00000000..f73356ea --- /dev/null +++ b/internal/domain/main-entities/doctor/entity.go @@ -0,0 +1,17 @@ +package doctor + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" + eu "simrs-vx/internal/domain/main-entities/unit" +) + +type Doctor struct { + ecore.Main // adjust this according to the needs + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` + IHS_Number *string `json:"ihs_number" gorm:"size:20"` + SIP_Number *string `json:"sip_number" gorm:"size:20"` + Unit_Id *uint `json:"unit_id"` + Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Id;references:Id"` +} diff --git a/internal/domain/main-entities/employee/dto.go b/internal/domain/main-entities/employee/dto.go new file mode 100644 index 00000000..8aa9402d --- /dev/null +++ b/internal/domain/main-entities/employee/dto.go @@ -0,0 +1,87 @@ +package employee + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/division" + erc "simrs-vx/internal/domain/references/common" +) + +type CreateDto struct { + User_Id *uint `json:"user_id"` + Person_Id *uint `json:"person_id"` + Position_Code erc.EmployeePosisitionCode `json:"position_code"` + Division_Code *string `json:"division_code"` + Number *string `json:"number"` + Status_Code erc.StatusCode `json:"status_code"` +} + +type ReadListDto struct { + User_Id *uint `json:"user_id"` + Person_Id *uint `json:"person_id"` + Position_Code erc.EmployeePosisitionCode `json:"position_code"` + Division_Code *string `json:"division_code"` + Number *string `json:"number"` + Status_Code erc.StatusCode `json:"status_code"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + User_Id *uint `json:"user_id"` + Person_Id *uint `json:"person_id"` + Position_Code erc.EmployeePosisitionCode `json:"position_code"` + Division_Code *string `json:"division_code"` + Number *string `json:"number"` + Status_Code erc.StatusCode `json:"status_code"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + User_Id *uint `json:"user_id"` + Person_Id *uint `json:"person_id"` + Position_Code erc.EmployeePosisitionCode `json:"position_code"` + Division_Code *string `json:"division_code"` + Division *ed.Division `json:"division,omitempty"` + Number *string `json:"number"` + Status_Code erc.StatusCode `json:"status_code"` +} + +func (d Employee) ToResponse() ResponseDto { + resp := ResponseDto{ + User_Id: d.User_Id, + Person_Id: d.Person_Id, + Position_Code: d.Position_Code, + Division_Code: d.Division_Code, + Division: d.Division, + Number: d.Number, + Status_Code: d.Status_Code, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Employee) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/employee/entity.go b/internal/domain/main-entities/employee/entity.go new file mode 100644 index 00000000..8d6df9fd --- /dev/null +++ b/internal/domain/main-entities/employee/entity.go @@ -0,0 +1,18 @@ +package employee + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/division" + erc "simrs-vx/internal/domain/references/common" +) + +type Employee struct { + ecore.Main // adjust this according to the needs + User_Id *uint `json:"user_id"` + Person_Id *uint `json:"person_id"` + Position_Code erc.EmployeePosisitionCode `json:"position_code" gorm:"not null;size:20"` + Division_Code *string `json:"division_code"` + Division *ed.Division `json:"division,omitempty" gorm:"foreignKey:Division_Code;references:Code"` + Number *string `json:"number" gorm:"size:20"` + Status_Code erc.StatusCode `json:"status_code" gorm:"not null;size:10"` +} diff --git a/internal/domain/main-entities/infra-group/dto.go b/internal/domain/main-entities/infra-group/dto.go new file mode 100644 index 00000000..9b10d189 --- /dev/null +++ b/internal/domain/main-entities/infra-group/dto.go @@ -0,0 +1,63 @@ +package infragroup + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Code string `json:"code"` + Name string `json:"name"` +} + +func (d InfraGroup) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []InfraGroup) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/infra-group/entity.go b/internal/domain/main-entities/infra-group/entity.go new file mode 100644 index 00000000..f749030a --- /dev/null +++ b/internal/domain/main-entities/infra-group/entity.go @@ -0,0 +1,11 @@ +package infragroup + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type InfraGroup struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:50"` + Name string `json:"name" gorm:"size:100"` +} diff --git a/internal/domain/main-entities/installation/dto.go b/internal/domain/main-entities/installation/dto.go index e4f806b1..66ce57ff 100644 --- a/internal/domain/main-entities/installation/dto.go +++ b/internal/domain/main-entities/installation/dto.go @@ -50,19 +50,19 @@ type ResponseDto struct { EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` } -func (i Installation) ToResponse() ResponseDto { +func (d Installation) ToResponse() ResponseDto { resp := ResponseDto{ - Code: i.Code, - Name: i.Name, - EncounterClass_Code: i.EncounterClass_Code, + Code: d.Code, + Name: d.Name, + EncounterClass_Code: d.EncounterClass_Code, } - resp.SmallMain = i.SmallMain + resp.SmallMain = d.SmallMain return resp } -func ToResponseList(users []Installation) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []Installation) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/item-group/dto.go b/internal/domain/main-entities/item-group/dto.go new file mode 100644 index 00000000..99681811 --- /dev/null +++ b/internal/domain/main-entities/item-group/dto.go @@ -0,0 +1,63 @@ +package itemgroup + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Code string `json:"code"` + Name string `json:"name"` +} + +func (d ItemGroup) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []ItemGroup) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/item-group/entity.go b/internal/domain/main-entities/item-group/entity.go new file mode 100644 index 00000000..24ee3331 --- /dev/null +++ b/internal/domain/main-entities/item-group/entity.go @@ -0,0 +1,11 @@ +package itemgroup + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type ItemGroup struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:50"` + Name string `json:"name" gorm:"size:100"` +} diff --git a/internal/domain/main-entities/nurse/dto.go b/internal/domain/main-entities/nurse/dto.go new file mode 100644 index 00000000..3feaa041 --- /dev/null +++ b/internal/domain/main-entities/nurse/dto.go @@ -0,0 +1,66 @@ +package nurse + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" +) + +type CreateDto struct { + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` +} + +type ReadListDto struct { + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty"` + IHS_Number *string `json:"ihs_number"` +} + +func (d Nurse) ToResponse() ResponseDto { + resp := ResponseDto{ + Employee_Id: d.Employee_Id, + Employee: d.Employee, + IHS_Number: d.IHS_Number, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Nurse) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/nurse/entity.go b/internal/domain/main-entities/nurse/entity.go new file mode 100644 index 00000000..4b497574 --- /dev/null +++ b/internal/domain/main-entities/nurse/entity.go @@ -0,0 +1,13 @@ +package nurse + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" +) + +type Nurse struct { + ecore.Main // adjust this according to the needs + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` + IHS_Number *string `json:"ihs_number" gorm:"size:20"` +} diff --git a/internal/domain/main-entities/nutritionist/dto.go b/internal/domain/main-entities/nutritionist/dto.go new file mode 100644 index 00000000..c5bc7003 --- /dev/null +++ b/internal/domain/main-entities/nutritionist/dto.go @@ -0,0 +1,66 @@ +package nutritionist + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" +) + +type CreateDto struct { + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` +} + +type ReadListDto struct { + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty"` + IHS_Number *string `json:"ihs_number"` +} + +func (d Nutritionist) ToResponse() ResponseDto { + resp := ResponseDto{ + Employee_Id: d.Employee_Id, + Employee: d.Employee, + IHS_Number: d.IHS_Number, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Nutritionist) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/nutritionist/entity.go b/internal/domain/main-entities/nutritionist/entity.go new file mode 100644 index 00000000..8956b8b4 --- /dev/null +++ b/internal/domain/main-entities/nutritionist/entity.go @@ -0,0 +1,13 @@ +package nutritionist + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" +) + +type Nutritionist struct { + ecore.Main // adjust this according to the needs + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` + IHS_Number *string `json:"ihs_number" gorm:"size:20"` +} diff --git a/internal/domain/main-entities/person-address/dto.go b/internal/domain/main-entities/person-address/dto.go index 7a4ba174..73ae88ce 100644 --- a/internal/domain/main-entities/person-address/dto.go +++ b/internal/domain/main-entities/person-address/dto.go @@ -63,9 +63,9 @@ func (d PersonAddress) ToResponse() ResponseDto { return resp } -func ToResponseList(users []PersonAddress) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []PersonAddress) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/person-contact/dto.go b/internal/domain/main-entities/person-contact/dto.go index 19104de3..e6865191 100644 --- a/internal/domain/main-entities/person-contact/dto.go +++ b/internal/domain/main-entities/person-contact/dto.go @@ -46,19 +46,19 @@ type ResponseDto struct { Value string `json:"value"` } -func (u *PersonContact) ToResponse() ResponseDto { +func (d *PersonContact) ToResponse() ResponseDto { resp := ResponseDto{ - Person_Id: u.Person_Id, - Type_Code: u.Type_Code, - Value: u.Value, + Person_Id: d.Person_Id, + Type_Code: d.Type_Code, + Value: d.Value, } - resp.Main = u.Main + resp.Main = d.Main return resp } -func ToResponseList(users []PersonContact) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []PersonContact) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/person/dto.go b/internal/domain/main-entities/person/dto.go index 061c960b..dcead8c8 100644 --- a/internal/domain/main-entities/person/dto.go +++ b/internal/domain/main-entities/person/dto.go @@ -72,28 +72,28 @@ type ResponseDto struct { Contacts *[]epc.PersonContact `json:"contacts,omitempty"` } -func (u *Person) ToResponse() ResponseDto { +func (d *Person) ToResponse() ResponseDto { resp := ResponseDto{ - Name: u.Name, - BirthDate: u.BirthDate, - BirthRegency_Code: u.BirthRegency_Code, - Gender_Code: u.Gender_Code, - ResidentIdentityNumber: u.ResidentIdentityNumber, - Religion_Code: u.Religion_Code, - Education_Code: u.Education_Code, - Ocupation_Code: u.Ocupation_Code, - Ocupation_Name: u.Ocupation_Name, - Ethnic_Code: u.Ethnic_Code, - Addresses: u.Addresses, - Contacts: u.Contacts, + Name: d.Name, + BirthDate: d.BirthDate, + BirthRegency_Code: d.BirthRegency_Code, + Gender_Code: d.Gender_Code, + ResidentIdentityNumber: d.ResidentIdentityNumber, + Religion_Code: d.Religion_Code, + Education_Code: d.Education_Code, + Ocupation_Code: d.Ocupation_Code, + Ocupation_Name: d.Ocupation_Name, + Ethnic_Code: d.Ethnic_Code, + Addresses: d.Addresses, + Contacts: d.Contacts, } - resp.Main = u.Main + resp.Main = d.Main return resp } -func ToResponseList(users []Person) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []Person) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/pharmacist/dto.go b/internal/domain/main-entities/pharmacist/dto.go new file mode 100644 index 00000000..07bcd1f7 --- /dev/null +++ b/internal/domain/main-entities/pharmacist/dto.go @@ -0,0 +1,66 @@ +package pharmacist + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" +) + +type CreateDto struct { + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` +} + +type ReadListDto struct { + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Employee_Id *uint `json:"employee_id"` + IHS_Number *string `json:"ihs_number"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty"` + IHS_Number *string `json:"ihs_number"` +} + +func (d Pharmacist) ToResponse() ResponseDto { + resp := ResponseDto{ + Employee_Id: d.Employee_Id, + Employee: d.Employee, + IHS_Number: d.IHS_Number, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Pharmacist) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/pharmacist/entity.go b/internal/domain/main-entities/pharmacist/entity.go new file mode 100644 index 00000000..352fa9ba --- /dev/null +++ b/internal/domain/main-entities/pharmacist/entity.go @@ -0,0 +1,13 @@ +package pharmacist + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" +) + +type Pharmacist struct { + ecore.Main // adjust this according to the needs + Employee_Id *uint `json:"employee_id"` + Employee *ee.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` + IHS_Number *string `json:"ihs_number" gorm:"size:20"` +} diff --git a/internal/domain/main-entities/pharmacy-company/dto.go b/internal/domain/main-entities/pharmacy-company/dto.go index afd671ab..d8f4dd27 100644 --- a/internal/domain/main-entities/pharmacy-company/dto.go +++ b/internal/domain/main-entities/pharmacy-company/dto.go @@ -59,9 +59,9 @@ func (d PharmacyCompany) ToResponse() ResponseDto { return resp } -func ToResponseList(users []PharmacyCompany) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []PharmacyCompany) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/practice-schedule/dto.go b/internal/domain/main-entities/practice-schedule/dto.go new file mode 100644 index 00000000..5a74137e --- /dev/null +++ b/internal/domain/main-entities/practice-schedule/dto.go @@ -0,0 +1,79 @@ +package practiceschedule + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erx "simrs-vx/internal/domain/references/xtime" +) + +type CreateDto struct { + Doctor_Id *uint `json:"doctor_id"` + Unit_Code *string `json:"unit_code"` + Day_Code *erx.DayCode `json:"day_code"` + StartTime *string `json:"start_time"` + EndTime *string `json:"end_time"` +} + +type ReadListDto struct { + Doctor_Id *uint `json:"doctor_id"` + Unit_Code *string `json:"unit_code"` + Day_Code *erx.DayCode `json:"day_code"` + StartTime *string `json:"start_time"` + EndTime *string `json:"end_time"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Doctor_Id *uint `json:"doctor_id"` + Unit_Code *string `json:"unit_code"` + Day_Code *erx.DayCode `json:"day_code"` + StartTime *string `json:"start_time"` + EndTime *string `json:"end_time"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Doctor_Id *uint `json:"doctor_id"` + Unit_Code *string `json:"unit_code"` + Day_Code *erx.DayCode `json:"day_code"` + StartTime *string `json:"start_time"` + EndTime *string `json:"end_time"` +} + +func (d PracticeSchedule) ToResponse() ResponseDto { + resp := ResponseDto{ + Doctor_Id: d.Doctor_Id, + Unit_Code: d.Unit_Code, + Day_Code: d.Day_Code, + StartTime: d.StartTime, + EndTime: d.EndTime, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []PracticeSchedule) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/practice-schedule/entity.go b/internal/domain/main-entities/practice-schedule/entity.go new file mode 100644 index 00000000..e24e8584 --- /dev/null +++ b/internal/domain/main-entities/practice-schedule/entity.go @@ -0,0 +1,19 @@ +package practiceschedule + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" + eu "simrs-vx/internal/domain/main-entities/unit" + erx "simrs-vx/internal/domain/references/xtime" +) + +type PracticeSchedule struct { + ecore.Main // adjust this according to the needs + Doctor_Id *uint `json:"doctor_id"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Id;references:Id"` + Unit_Code *string `json:"unit_code"` + Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` + Day_Code *erx.DayCode `json:"day_code"` + StartTime *string `json:"start_time" gorm:"size:5"` + EndTime *string `json:"end_time" gorm:"size:5"` +} diff --git a/internal/domain/main-entities/procedure-src/dto.go b/internal/domain/main-entities/procedure-src/dto.go index 05333300..c0ba8c30 100644 --- a/internal/domain/main-entities/procedure-src/dto.go +++ b/internal/domain/main-entities/procedure-src/dto.go @@ -59,9 +59,9 @@ func (d ProcedureSrc) ToResponse() ResponseDto { return resp } -func ToResponseList(users []ProcedureSrc) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []ProcedureSrc) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/province/dto.go b/internal/domain/main-entities/province/dto.go index c1b771fa..bc1461e0 100644 --- a/internal/domain/main-entities/province/dto.go +++ b/internal/domain/main-entities/province/dto.go @@ -50,9 +50,9 @@ func (d Province) ToResponse() ResponseDto { return resp } -func ToResponseList(users []Province) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []Province) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/regency/dto.go b/internal/domain/main-entities/regency/dto.go index 56cc0a76..6cb850de 100644 --- a/internal/domain/main-entities/regency/dto.go +++ b/internal/domain/main-entities/regency/dto.go @@ -48,14 +48,14 @@ type ResponseDto struct { Districts []*ed.District `json:"districts,omitempty"` } -func (r Regency) ToResponse() ResponseDto { - resp := ResponseDto(r) +func (d Regency) ToResponse() ResponseDto { + resp := ResponseDto(d) return resp } -func ToResponseList(users []Regency) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []Regency) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/unit/dto.go b/internal/domain/main-entities/unit/dto.go index 5b0c3aef..448d16ec 100644 --- a/internal/domain/main-entities/unit/dto.go +++ b/internal/domain/main-entities/unit/dto.go @@ -51,22 +51,22 @@ type ResponseDto struct { Name string `json:"name"` } -func (u Unit) ToResponse() ResponseDto { +func (d Unit) ToResponse() ResponseDto { resp := ResponseDto{ - Installation_Id: u.Installation_Id, - Code: u.Code, - Name: u.Name, + Installation_Id: d.Installation_Id, + Code: d.Code, + Name: d.Name, } - resp.SmallMain = u.SmallMain - if u.Installation != nil { - resp.Installation = u.Installation + resp.SmallMain = d.SmallMain + if d.Installation != nil { + resp.Installation = d.Installation } return resp } -func ToResponseList(users []Unit) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []Unit) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index b3c2cac8..98c3a2d1 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -56,21 +56,21 @@ type ResponseDto struct { LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` } -func (u *User) ToResponse() ResponseDto { +func (d *User) ToResponse() ResponseDto { resp := ResponseDto{ - Name: u.Name, - Status_Code: u.Status_Code, - FailedLoginCount: u.FailedLoginCount, - LastSuccessLogin: u.LastSuccessLogin, - LastAllowdLogin: u.LastAllowdLogin, + Name: d.Name, + Status_Code: d.Status_Code, + FailedLoginCount: d.FailedLoginCount, + LastSuccessLogin: d.LastSuccessLogin, + LastAllowdLogin: d.LastAllowdLogin, } - resp.Main = u.Main + resp.Main = d.Main return resp } -func ToResponseList(users []User) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []User) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/main-entities/village/dto.go b/internal/domain/main-entities/village/dto.go index 750a382c..bdd1a323 100644 --- a/internal/domain/main-entities/village/dto.go +++ b/internal/domain/main-entities/village/dto.go @@ -45,14 +45,14 @@ type ResponseDto struct { Name string `json:"name"` } -func (v Village) ToResponse() ResponseDto { - resp := ResponseDto(v) +func (d Village) ToResponse() ResponseDto { + resp := ResponseDto(d) return resp } -func ToResponseList(users []Village) []ResponseDto { - resp := make([]ResponseDto, len(users)) - for i, u := range users { +func ToResponseList(data []Village) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { resp[i] = u.ToResponse() } return resp diff --git a/internal/domain/references/common/common.go b/internal/domain/references/common/common.go index 7f6fed2b..dfd44baf 100644 --- a/internal/domain/references/common/common.go +++ b/internal/domain/references/common/common.go @@ -1,12 +1,13 @@ package common type ( - YaTidakCode byte - SudahBelumCode byte - AktifSimpelCode byte - AktifAdvanceCode byte - TersediaCode byte - StatusCode string + YaTidakCode byte + SudahBelumCode byte + AktifSimpelCode byte + AktifAdvanceCode byte + TersediaCode byte + StatusCode string + EmployeePosisitionCode string ) const ( @@ -41,3 +42,14 @@ const ( SCBlocked StatusCode = "blocked" SCSuspended StatusCode = "suspended" ) + +const ( + EPCDoc EmployeePosisitionCode = "doctor" + EPCNur EmployeePosisitionCode = "nurse" + EPCNut EmployeePosisitionCode = "nutritionist" + EPCLab EmployeePosisitionCode = "laborant" + EPCPha EmployeePosisitionCode = "pharmacy" + EPCPay EmployeePosisitionCode = "payment" + EPCPav EmployeePosisitionCode = "payment-verificator" + EPCMan EmployeePosisitionCode = "management" +) diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index beeb666e..3acc76cd 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -5,15 +5,24 @@ import ( "io" "os" "os/exec" + counter "simrs-vx/internal/domain/main-entities/counter" diagnosesrc "simrs-vx/internal/domain/main-entities/diagnose-src" district "simrs-vx/internal/domain/main-entities/district" division "simrs-vx/internal/domain/main-entities/division" divisionposition "simrs-vx/internal/domain/main-entities/division-position" + doctor "simrs-vx/internal/domain/main-entities/doctor" + employee "simrs-vx/internal/domain/main-entities/employee" + infragroup "simrs-vx/internal/domain/main-entities/infra-group" installation "simrs-vx/internal/domain/main-entities/installation" + itemgroup "simrs-vx/internal/domain/main-entities/item-group" + nurse "simrs-vx/internal/domain/main-entities/nurse" + nutritionist "simrs-vx/internal/domain/main-entities/nutritionist" person "simrs-vx/internal/domain/main-entities/person" personaddress "simrs-vx/internal/domain/main-entities/person-address" personcontact "simrs-vx/internal/domain/main-entities/person-contact" + pharmacist "simrs-vx/internal/domain/main-entities/pharmacist" pharmacycompany "simrs-vx/internal/domain/main-entities/pharmacy-company" + practiceschedule "simrs-vx/internal/domain/main-entities/practice-schedule" proceduresrc "simrs-vx/internal/domain/main-entities/procedure-src" province "simrs-vx/internal/domain/main-entities/province" regency "simrs-vx/internal/domain/main-entities/regency" @@ -69,6 +78,15 @@ func GetEntities() []any { &pharmacycompany.PharmacyCompany{}, &diagnosesrc.DiagnoseSrc{}, &proceduresrc.ProcedureSrc{}, + &infragroup.InfraGroup{}, + &employee.Employee{}, + &itemgroup.ItemGroup{}, + &doctor.Doctor{}, + &nurse.Nurse{}, + &nutritionist.Nutritionist{}, + &pharmacist.Pharmacist{}, + &counter.Counter{}, + &practiceschedule.PracticeSchedule{}, } } From 99fa735eed1bda51100a958f8350f0020530e7c4 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 09:40:21 +0700 Subject: [PATCH 23/40] add use case pharmacycompany, diagnosesrc, proceduresrc, infragroup --- .../main-use-case/diagnose-src/case.go | 275 ++++++++++++++++++ .../main-use-case/diagnose-src/helper.go | 23 ++ .../main-use-case/diagnose-src/lib.go | 149 ++++++++++ .../diagnose-src/middleware-runner.go | 103 +++++++ .../main-use-case/diagnose-src/middleware.go | 9 + .../main-use-case/diagnose-src/tycovar.go | 44 +++ .../main-use-case/infra-group/case.go | 275 ++++++++++++++++++ .../main-use-case/infra-group/helper.go | 22 ++ .../use-case/main-use-case/infra-group/lib.go | 149 ++++++++++ .../infra-group/middleware-runner.go | 103 +++++++ .../main-use-case/infra-group/middleware.go | 9 + .../main-use-case/infra-group/tycovar.go | 44 +++ .../main-use-case/pharmacy-company/case.go | 275 ++++++++++++++++++ .../main-use-case/pharmacy-company/helper.go | 23 ++ .../main-use-case/pharmacy-company/lib.go | 149 ++++++++++ .../pharmacy-company/middleware-runner.go | 103 +++++++ .../pharmacy-company/middleware.go | 9 + .../main-use-case/pharmacy-company/tycovar.go | 44 +++ .../main-use-case/procedure-src/case.go | 275 ++++++++++++++++++ .../main-use-case/procedure-src/helper.go | 23 ++ .../main-use-case/procedure-src/lib.go | 149 ++++++++++ .../procedure-src/middleware-runner.go | 103 +++++++ .../main-use-case/procedure-src/middleware.go | 9 + .../main-use-case/procedure-src/tycovar.go | 44 +++ 24 files changed, 2411 insertions(+) create mode 100644 internal/use-case/main-use-case/diagnose-src/case.go create mode 100644 internal/use-case/main-use-case/diagnose-src/helper.go create mode 100644 internal/use-case/main-use-case/diagnose-src/lib.go create mode 100644 internal/use-case/main-use-case/diagnose-src/middleware-runner.go create mode 100644 internal/use-case/main-use-case/diagnose-src/middleware.go create mode 100644 internal/use-case/main-use-case/diagnose-src/tycovar.go create mode 100644 internal/use-case/main-use-case/infra-group/case.go create mode 100644 internal/use-case/main-use-case/infra-group/helper.go create mode 100644 internal/use-case/main-use-case/infra-group/lib.go create mode 100644 internal/use-case/main-use-case/infra-group/middleware-runner.go create mode 100644 internal/use-case/main-use-case/infra-group/middleware.go create mode 100644 internal/use-case/main-use-case/infra-group/tycovar.go create mode 100644 internal/use-case/main-use-case/pharmacy-company/case.go create mode 100644 internal/use-case/main-use-case/pharmacy-company/helper.go create mode 100644 internal/use-case/main-use-case/pharmacy-company/lib.go create mode 100644 internal/use-case/main-use-case/pharmacy-company/middleware-runner.go create mode 100644 internal/use-case/main-use-case/pharmacy-company/middleware.go create mode 100644 internal/use-case/main-use-case/pharmacy-company/tycovar.go create mode 100644 internal/use-case/main-use-case/procedure-src/case.go create mode 100644 internal/use-case/main-use-case/procedure-src/helper.go create mode 100644 internal/use-case/main-use-case/procedure-src/lib.go create mode 100644 internal/use-case/main-use-case/procedure-src/middleware-runner.go create mode 100644 internal/use-case/main-use-case/procedure-src/middleware.go create mode 100644 internal/use-case/main-use-case/procedure-src/tycovar.go diff --git a/internal/use-case/main-use-case/diagnose-src/case.go b/internal/use-case/main-use-case/diagnose-src/case.go new file mode 100644 index 00000000..6fc921e4 --- /dev/null +++ b/internal/use-case/main-use-case/diagnose-src/case.go @@ -0,0 +1,275 @@ +package diagnosesrc + +import ( + e "simrs-vx/internal/domain/main-entities/diagnose-src" + "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" +) + +const source = "diagnose-src" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.DiagnoseSrc{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.DiagnoseSrc + var dataList []e.DiagnoseSrc + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.DiagnoseSrc + 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.DiagnoseSrc + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.DiagnoseSrc + 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 + +} diff --git a/internal/use-case/main-use-case/diagnose-src/helper.go b/internal/use-case/main-use-case/diagnose-src/helper.go new file mode 100644 index 00000000..29622782 --- /dev/null +++ b/internal/use-case/main-use-case/diagnose-src/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package diagnosesrc + +import ( + e "simrs-vx/internal/domain/main-entities/diagnose-src" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.DiagnoseSrc) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.IndName = inputSrc.IndName +} diff --git a/internal/use-case/main-use-case/diagnose-src/lib.go b/internal/use-case/main-use-case/diagnose-src/lib.go new file mode 100644 index 00000000..344e36ef --- /dev/null +++ b/internal/use-case/main-use-case/diagnose-src/lib.go @@ -0,0 +1,149 @@ +package diagnosesrc + +import ( + e "simrs-vx/internal/domain/main-entities/diagnose-src" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.DiagnoseSrc, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.DiagnoseSrc{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.DiagnoseSrc, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.DiagnoseSrc{} + 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.DiagnoseSrc{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.DiagnoseSrc, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.DiagnoseSrc{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.DiagnoseSrc, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.DiagnoseSrc, 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 +} diff --git a/internal/use-case/main-use-case/diagnose-src/middleware-runner.go b/internal/use-case/main-use-case/diagnose-src/middleware-runner.go new file mode 100644 index 00000000..59c67d11 --- /dev/null +++ b/internal/use-case/main-use-case/diagnose-src/middleware-runner.go @@ -0,0 +1,103 @@ +package diagnosesrc + +import ( + e "simrs-vx/internal/domain/main-entities/diagnose-src" + 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.DiagnoseSrc) 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.DiagnoseSrc) 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.DiagnoseSrc) 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.DiagnoseSrc) 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.DiagnoseSrc) 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 +} diff --git a/internal/use-case/main-use-case/diagnose-src/middleware.go b/internal/use-case/main-use-case/diagnose-src/middleware.go new file mode 100644 index 00000000..c6e01a1e --- /dev/null +++ b/internal/use-case/main-use-case/diagnose-src/middleware.go @@ -0,0 +1,9 @@ +package diagnosesrc + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/diagnose-src/tycovar.go b/internal/use-case/main-use-case/diagnose-src/tycovar.go new file mode 100644 index 00000000..4599de91 --- /dev/null +++ b/internal/use-case/main-use-case/diagnose-src/tycovar.go @@ -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 diagnosesrc + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/diagnose-src" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.DiagnoseSrc, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.DiagnoseSrc, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.DiagnoseSrc, 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 diff --git a/internal/use-case/main-use-case/infra-group/case.go b/internal/use-case/main-use-case/infra-group/case.go new file mode 100644 index 00000000..9366114b --- /dev/null +++ b/internal/use-case/main-use-case/infra-group/case.go @@ -0,0 +1,275 @@ +package infragroup + +import ( + e "simrs-vx/internal/domain/main-entities/infra-group" + "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" +) + +const source = "infra-group" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.InfraGroup{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.InfraGroup + var dataList []e.InfraGroup + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.InfraGroup + 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: uint16(input.Id)} + var data *e.InfraGroup + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.InfraGroup + 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 + +} diff --git a/internal/use-case/main-use-case/infra-group/helper.go b/internal/use-case/main-use-case/infra-group/helper.go new file mode 100644 index 00000000..ab02742d --- /dev/null +++ b/internal/use-case/main-use-case/infra-group/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package infragroup + +import ( + e "simrs-vx/internal/domain/main-entities/infra-group" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.InfraGroup) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + data.Code = inputSrc.Code + data.Name = inputSrc.Name + +} diff --git a/internal/use-case/main-use-case/infra-group/lib.go b/internal/use-case/main-use-case/infra-group/lib.go new file mode 100644 index 00000000..ba738d71 --- /dev/null +++ b/internal/use-case/main-use-case/infra-group/lib.go @@ -0,0 +1,149 @@ +package infragroup + +import ( + e "simrs-vx/internal/domain/main-entities/infra-group" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.InfraGroup, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.InfraGroup{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.InfraGroup, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.InfraGroup{} + 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.InfraGroup{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.InfraGroup, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.InfraGroup{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.InfraGroup, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.InfraGroup, 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 +} diff --git a/internal/use-case/main-use-case/infra-group/middleware-runner.go b/internal/use-case/main-use-case/infra-group/middleware-runner.go new file mode 100644 index 00000000..50b8fb7a --- /dev/null +++ b/internal/use-case/main-use-case/infra-group/middleware-runner.go @@ -0,0 +1,103 @@ +package infragroup + +import ( + e "simrs-vx/internal/domain/main-entities/infra-group" + 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.InfraGroup) 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.InfraGroup) 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.InfraGroup) 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.InfraGroup) 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.InfraGroup) 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 +} diff --git a/internal/use-case/main-use-case/infra-group/middleware.go b/internal/use-case/main-use-case/infra-group/middleware.go new file mode 100644 index 00000000..b811bbe8 --- /dev/null +++ b/internal/use-case/main-use-case/infra-group/middleware.go @@ -0,0 +1,9 @@ +package infragroup + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/infra-group/tycovar.go b/internal/use-case/main-use-case/infra-group/tycovar.go new file mode 100644 index 00000000..cd5a9925 --- /dev/null +++ b/internal/use-case/main-use-case/infra-group/tycovar.go @@ -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 infragroup + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/infra-group" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.InfraGroup, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.InfraGroup, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.InfraGroup, 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 diff --git a/internal/use-case/main-use-case/pharmacy-company/case.go b/internal/use-case/main-use-case/pharmacy-company/case.go new file mode 100644 index 00000000..bf22d56d --- /dev/null +++ b/internal/use-case/main-use-case/pharmacy-company/case.go @@ -0,0 +1,275 @@ +package pharmacycompany + +import ( + e "simrs-vx/internal/domain/main-entities/pharmacy-company" + "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" +) + +const source = "pharmacy-company" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.PharmacyCompany{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.PharmacyCompany + var dataList []e.PharmacyCompany + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.PharmacyCompany + 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.PharmacyCompany + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.PharmacyCompany + 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 + +} diff --git a/internal/use-case/main-use-case/pharmacy-company/helper.go b/internal/use-case/main-use-case/pharmacy-company/helper.go new file mode 100644 index 00000000..d712a9ff --- /dev/null +++ b/internal/use-case/main-use-case/pharmacy-company/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package pharmacycompany + +import ( + e "simrs-vx/internal/domain/main-entities/pharmacy-company" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.PharmacyCompany) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Regency_Code = inputSrc.Regency_Code +} diff --git a/internal/use-case/main-use-case/pharmacy-company/lib.go b/internal/use-case/main-use-case/pharmacy-company/lib.go new file mode 100644 index 00000000..f4eca38e --- /dev/null +++ b/internal/use-case/main-use-case/pharmacy-company/lib.go @@ -0,0 +1,149 @@ +package pharmacycompany + +import ( + e "simrs-vx/internal/domain/main-entities/pharmacy-company" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.PharmacyCompany, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.PharmacyCompany{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.PharmacyCompany, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.PharmacyCompany{} + 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.PharmacyCompany{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.PharmacyCompany, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.PharmacyCompany{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.PharmacyCompany, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.PharmacyCompany, 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 +} diff --git a/internal/use-case/main-use-case/pharmacy-company/middleware-runner.go b/internal/use-case/main-use-case/pharmacy-company/middleware-runner.go new file mode 100644 index 00000000..eb4ea473 --- /dev/null +++ b/internal/use-case/main-use-case/pharmacy-company/middleware-runner.go @@ -0,0 +1,103 @@ +package pharmacycompany + +import ( + e "simrs-vx/internal/domain/main-entities/pharmacy-company" + 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.PharmacyCompany) 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.PharmacyCompany) 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.PharmacyCompany) 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.PharmacyCompany) 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.PharmacyCompany) 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 +} diff --git a/internal/use-case/main-use-case/pharmacy-company/middleware.go b/internal/use-case/main-use-case/pharmacy-company/middleware.go new file mode 100644 index 00000000..8aca7b26 --- /dev/null +++ b/internal/use-case/main-use-case/pharmacy-company/middleware.go @@ -0,0 +1,9 @@ +package pharmacycompany + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/pharmacy-company/tycovar.go b/internal/use-case/main-use-case/pharmacy-company/tycovar.go new file mode 100644 index 00000000..72afff04 --- /dev/null +++ b/internal/use-case/main-use-case/pharmacy-company/tycovar.go @@ -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 pharmacycompany + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/pharmacy-company" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.PharmacyCompany, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.PharmacyCompany, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.PharmacyCompany, 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 diff --git a/internal/use-case/main-use-case/procedure-src/case.go b/internal/use-case/main-use-case/procedure-src/case.go new file mode 100644 index 00000000..d7b116c0 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-src/case.go @@ -0,0 +1,275 @@ +package proceduresrc + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-src" + "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" +) + +const source = "procedure-src" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.ProcedureSrc{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.ProcedureSrc + var dataList []e.ProcedureSrc + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ProcedureSrc + 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.ProcedureSrc + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.ProcedureSrc + 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 + +} diff --git a/internal/use-case/main-use-case/procedure-src/helper.go b/internal/use-case/main-use-case/procedure-src/helper.go new file mode 100644 index 00000000..2832fd49 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-src/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package proceduresrc + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-src" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ProcedureSrc) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.IndName = inputSrc.IndName +} diff --git a/internal/use-case/main-use-case/procedure-src/lib.go b/internal/use-case/main-use-case/procedure-src/lib.go new file mode 100644 index 00000000..b1b1b01f --- /dev/null +++ b/internal/use-case/main-use-case/procedure-src/lib.go @@ -0,0 +1,149 @@ +package proceduresrc + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-src" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.ProcedureSrc, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.ProcedureSrc{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ProcedureSrc, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ProcedureSrc{} + 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.ProcedureSrc{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.ProcedureSrc, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ProcedureSrc{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.ProcedureSrc, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.ProcedureSrc, 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 +} diff --git a/internal/use-case/main-use-case/procedure-src/middleware-runner.go b/internal/use-case/main-use-case/procedure-src/middleware-runner.go new file mode 100644 index 00000000..66b2dc59 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-src/middleware-runner.go @@ -0,0 +1,103 @@ +package proceduresrc + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-src" + 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.ProcedureSrc) 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.ProcedureSrc) 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.ProcedureSrc) 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.ProcedureSrc) 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.ProcedureSrc) 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 +} diff --git a/internal/use-case/main-use-case/procedure-src/middleware.go b/internal/use-case/main-use-case/procedure-src/middleware.go new file mode 100644 index 00000000..6832f6c1 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-src/middleware.go @@ -0,0 +1,9 @@ +package proceduresrc + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/procedure-src/tycovar.go b/internal/use-case/main-use-case/procedure-src/tycovar.go new file mode 100644 index 00000000..3a48d20c --- /dev/null +++ b/internal/use-case/main-use-case/procedure-src/tycovar.go @@ -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 proceduresrc + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/procedure-src" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ProcedureSrc, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ProcedureSrc, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ProcedureSrc, 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 From 0d62b3f72515bbfa81ed75878157bc757addac9e Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 10:20:40 +0700 Subject: [PATCH 24/40] update infragroup --- cmd/migration/migrations/20250827024311.sql | 2 ++ cmd/migration/migrations/atlas.sum | 11 ++++---- .../domain/main-entities/infra-group/dto.go | 27 +++++++++++-------- .../main-entities/infra-group/entity.go | 5 ++-- 4 files changed, 27 insertions(+), 18 deletions(-) create mode 100644 cmd/migration/migrations/20250827024311.sql diff --git a/cmd/migration/migrations/20250827024311.sql b/cmd/migration/migrations/20250827024311.sql new file mode 100644 index 00000000..8ac1d2a6 --- /dev/null +++ b/cmd/migration/migrations/20250827024311.sql @@ -0,0 +1,2 @@ +-- Modify "InfraGroup" table +ALTER TABLE "public"."InfraGroup" ALTER COLUMN "Code" TYPE character varying(10), ALTER COLUMN "Name" TYPE character varying(50), ADD COLUMN "Level" smallint NULL; diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index 1d5fbd8b..46aee6d6 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,7 +1,8 @@ -h1:aACpl+MgcGmQ5IgTQGQ4o6+1pT9L8KphrWlGlKBguHc= +h1:4uryCUq0L2CJ7E8H5cdmioR5WZgsBsOYyeEo78COgs0= 20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= 20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= -20250825102900.sql h1:Xaz9cAKDx6ZjDByRBSNrX/d2/s8Xid2zhirWk62xKjQ= -20250825103029.sql h1:YkM0KTRRawcObTUOG3epXzBOW4wFyHIOlnh99FaVgPk= -20250827015551.sql h1:iaN+FNEPyYn8pbc16yt1Jwo1Bf6jRePhKvoZht+RxdI= -20250827021904.sql h1:jxCNgxPGAHqU3z/tQBww7/9PnJQYl2Is2NFV5ZEeHIU= +20250825102900.sql h1:OAUnj87Wz7mrHykX14idePckUmRYa5UH0LylYDL76RI= +20250825103029.sql h1:iuZFrfUjNQM5kRpEwdYR8qinSp8SIkoJc3Dr8rD8BuI= +20250827015551.sql h1:Jq/RkXSWHEWuNigLunLzIrYgiyroSVD7J0waDMvdzvg= +20250827021904.sql h1:pgjwmQS1TxZ977a1tIXKq6pZnGauPrOUxLUTclV+fE4= +20250827024311.sql h1:6Wt8nK7R2qaTUvP8dZFwwqxAMdAhHAChxFRiI8BlzQo= diff --git a/internal/domain/main-entities/infra-group/dto.go b/internal/domain/main-entities/infra-group/dto.go index 9b10d189..e33e92b1 100644 --- a/internal/domain/main-entities/infra-group/dto.go +++ b/internal/domain/main-entities/infra-group/dto.go @@ -5,13 +5,15 @@ import ( ) type CreateDto struct { - Code string `json:"code"` - Name string `json:"name"` + Code string `json:"code"` + Name string `json:"name"` + Level uint8 `json:"level"` } type ReadListDto struct { - Code string `json:"code"` - Name string `json:"name"` + Code string `json:"code"` + Name string `json:"name"` + Level uint8 `json:"level"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -19,9 +21,10 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Level uint8 `json:"level"` } type UpdateDto struct { @@ -41,14 +44,16 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Code string `json:"code"` - Name string `json:"name"` + Code string `json:"code"` + Name string `json:"name"` + Level uint8 `json:"level"` } func (d InfraGroup) ToResponse() ResponseDto { resp := ResponseDto{ - Code: d.Code, - Name: d.Name, + Code: d.Code, + Name: d.Name, + Level: d.Level, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/infra-group/entity.go b/internal/domain/main-entities/infra-group/entity.go index f749030a..812c27f1 100644 --- a/internal/domain/main-entities/infra-group/entity.go +++ b/internal/domain/main-entities/infra-group/entity.go @@ -6,6 +6,7 @@ import ( type InfraGroup struct { ecore.Main // adjust this according to the needs - Code string `json:"code" gorm:"unique;size:50"` - Name string `json:"name" gorm:"size:100"` + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:50"` + Level uint8 `json:"level"` } From cbd836a68194bc9db4c02fd65269e5eff041aa4c Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 10:40:26 +0700 Subject: [PATCH 25/40] add use case for employee, itemgroup, doctor, nurse, nutritionist, pharmacist, counter, practiceschedule --- .../use-case/main-use-case/counter/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/counter/helper.go | 26 ++ .../use-case/main-use-case/counter/lib.go | 149 ++++++++++ .../counter/middleware-runner.go | 103 +++++++ .../main-use-case/counter/middleware.go | 9 + .../use-case/main-use-case/counter/tycovar.go | 44 +++ .../use-case/main-use-case/doctor/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/doctor/helper.go | 24 ++ internal/use-case/main-use-case/doctor/lib.go | 149 ++++++++++ .../main-use-case/doctor/middleware-runner.go | 103 +++++++ .../main-use-case/doctor/middleware.go | 9 + .../use-case/main-use-case/doctor/tycovar.go | 44 +++ .../use-case/main-use-case/employee/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/employee/helper.go | 26 ++ .../use-case/main-use-case/employee/lib.go | 149 ++++++++++ .../employee/middleware-runner.go | 103 +++++++ .../main-use-case/employee/middleware.go | 9 + .../main-use-case/employee/tycovar.go | 44 +++ .../main-use-case/infra-group/helper.go | 2 +- .../use-case/main-use-case/item-group/case.go | 275 ++++++++++++++++++ .../main-use-case/item-group/helper.go | 22 ++ .../use-case/main-use-case/item-group/lib.go | 149 ++++++++++ .../item-group/middleware-runner.go | 103 +++++++ .../main-use-case/item-group/middleware.go | 9 + .../main-use-case/item-group/tycovar.go | 44 +++ internal/use-case/main-use-case/nurse/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/nurse/helper.go | 22 ++ internal/use-case/main-use-case/nurse/lib.go | 149 ++++++++++ .../main-use-case/nurse/middleware-runner.go | 103 +++++++ .../main-use-case/nurse/middleware.go | 9 + .../use-case/main-use-case/nurse/tycovar.go | 44 +++ .../main-use-case/nutritionist/case.go | 275 ++++++++++++++++++ .../main-use-case/nutritionist/helper.go | 22 ++ .../main-use-case/nutritionist/lib.go | 149 ++++++++++ .../nutritionist/middleware-runner.go | 103 +++++++ .../main-use-case/nutritionist/middleware.go | 9 + .../main-use-case/nutritionist/tycovar.go | 44 +++ .../use-case/main-use-case/pharmacist/case.go | 275 ++++++++++++++++++ .../main-use-case/pharmacist/helper.go | 22 ++ .../use-case/main-use-case/pharmacist/lib.go | 149 ++++++++++ .../pharmacist/middleware-runner.go | 103 +++++++ .../main-use-case/pharmacist/middleware.go | 9 + .../main-use-case/pharmacist/tycovar.go | 44 +++ .../main-use-case/practice-schedule/case.go | 275 ++++++++++++++++++ .../main-use-case/practice-schedule/helper.go | 25 ++ .../main-use-case/practice-schedule/lib.go | 149 ++++++++++ .../practice-schedule/middleware-runner.go | 103 +++++++ .../practice-schedule/middleware.go | 9 + .../practice-schedule/tycovar.go | 44 +++ 49 files changed, 4830 insertions(+), 1 deletion(-) create mode 100644 internal/use-case/main-use-case/counter/case.go create mode 100644 internal/use-case/main-use-case/counter/helper.go create mode 100644 internal/use-case/main-use-case/counter/lib.go create mode 100644 internal/use-case/main-use-case/counter/middleware-runner.go create mode 100644 internal/use-case/main-use-case/counter/middleware.go create mode 100644 internal/use-case/main-use-case/counter/tycovar.go create mode 100644 internal/use-case/main-use-case/doctor/case.go create mode 100644 internal/use-case/main-use-case/doctor/helper.go create mode 100644 internal/use-case/main-use-case/doctor/lib.go create mode 100644 internal/use-case/main-use-case/doctor/middleware-runner.go create mode 100644 internal/use-case/main-use-case/doctor/middleware.go create mode 100644 internal/use-case/main-use-case/doctor/tycovar.go create mode 100644 internal/use-case/main-use-case/employee/case.go create mode 100644 internal/use-case/main-use-case/employee/helper.go create mode 100644 internal/use-case/main-use-case/employee/lib.go create mode 100644 internal/use-case/main-use-case/employee/middleware-runner.go create mode 100644 internal/use-case/main-use-case/employee/middleware.go create mode 100644 internal/use-case/main-use-case/employee/tycovar.go create mode 100644 internal/use-case/main-use-case/item-group/case.go create mode 100644 internal/use-case/main-use-case/item-group/helper.go create mode 100644 internal/use-case/main-use-case/item-group/lib.go create mode 100644 internal/use-case/main-use-case/item-group/middleware-runner.go create mode 100644 internal/use-case/main-use-case/item-group/middleware.go create mode 100644 internal/use-case/main-use-case/item-group/tycovar.go create mode 100644 internal/use-case/main-use-case/nurse/case.go create mode 100644 internal/use-case/main-use-case/nurse/helper.go create mode 100644 internal/use-case/main-use-case/nurse/lib.go create mode 100644 internal/use-case/main-use-case/nurse/middleware-runner.go create mode 100644 internal/use-case/main-use-case/nurse/middleware.go create mode 100644 internal/use-case/main-use-case/nurse/tycovar.go create mode 100644 internal/use-case/main-use-case/nutritionist/case.go create mode 100644 internal/use-case/main-use-case/nutritionist/helper.go create mode 100644 internal/use-case/main-use-case/nutritionist/lib.go create mode 100644 internal/use-case/main-use-case/nutritionist/middleware-runner.go create mode 100644 internal/use-case/main-use-case/nutritionist/middleware.go create mode 100644 internal/use-case/main-use-case/nutritionist/tycovar.go create mode 100644 internal/use-case/main-use-case/pharmacist/case.go create mode 100644 internal/use-case/main-use-case/pharmacist/helper.go create mode 100644 internal/use-case/main-use-case/pharmacist/lib.go create mode 100644 internal/use-case/main-use-case/pharmacist/middleware-runner.go create mode 100644 internal/use-case/main-use-case/pharmacist/middleware.go create mode 100644 internal/use-case/main-use-case/pharmacist/tycovar.go create mode 100644 internal/use-case/main-use-case/practice-schedule/case.go create mode 100644 internal/use-case/main-use-case/practice-schedule/helper.go create mode 100644 internal/use-case/main-use-case/practice-schedule/lib.go create mode 100644 internal/use-case/main-use-case/practice-schedule/middleware-runner.go create mode 100644 internal/use-case/main-use-case/practice-schedule/middleware.go create mode 100644 internal/use-case/main-use-case/practice-schedule/tycovar.go diff --git a/internal/use-case/main-use-case/counter/case.go b/internal/use-case/main-use-case/counter/case.go new file mode 100644 index 00000000..bfc24194 --- /dev/null +++ b/internal/use-case/main-use-case/counter/case.go @@ -0,0 +1,275 @@ +package counter + +import ( + e "simrs-vx/internal/domain/main-entities/counter" + "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" +) + +const source = "counter" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Counter{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Counter + var dataList []e.Counter + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Counter + 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.Counter + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Counter + 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 + +} diff --git a/internal/use-case/main-use-case/counter/helper.go b/internal/use-case/main-use-case/counter/helper.go new file mode 100644 index 00000000..6fe92af4 --- /dev/null +++ b/internal/use-case/main-use-case/counter/helper.go @@ -0,0 +1,26 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package counter + +import ( + e "simrs-vx/internal/domain/main-entities/counter" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Counter) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Number = inputSrc.Number + data.Parent_Id = inputSrc.Parent_Id + data.Type_Code = inputSrc.Type_Code + data.Queue_Code = inputSrc.Queue_Code +} diff --git a/internal/use-case/main-use-case/counter/lib.go b/internal/use-case/main-use-case/counter/lib.go new file mode 100644 index 00000000..64b22b0f --- /dev/null +++ b/internal/use-case/main-use-case/counter/lib.go @@ -0,0 +1,149 @@ +package counter + +import ( + e "simrs-vx/internal/domain/main-entities/counter" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Counter, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Counter{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Counter, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Counter{} + 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.Counter{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Counter, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Counter{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Counter, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Counter, 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 +} diff --git a/internal/use-case/main-use-case/counter/middleware-runner.go b/internal/use-case/main-use-case/counter/middleware-runner.go new file mode 100644 index 00000000..1d51cb04 --- /dev/null +++ b/internal/use-case/main-use-case/counter/middleware-runner.go @@ -0,0 +1,103 @@ +package counter + +import ( + e "simrs-vx/internal/domain/main-entities/counter" + 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.Counter) 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.Counter) 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.Counter) 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.Counter) 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.Counter) 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 +} diff --git a/internal/use-case/main-use-case/counter/middleware.go b/internal/use-case/main-use-case/counter/middleware.go new file mode 100644 index 00000000..07374add --- /dev/null +++ b/internal/use-case/main-use-case/counter/middleware.go @@ -0,0 +1,9 @@ +package counter + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/counter/tycovar.go b/internal/use-case/main-use-case/counter/tycovar.go new file mode 100644 index 00000000..4308a841 --- /dev/null +++ b/internal/use-case/main-use-case/counter/tycovar.go @@ -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 counter + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/counter" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Counter, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Counter, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Counter, 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 diff --git a/internal/use-case/main-use-case/doctor/case.go b/internal/use-case/main-use-case/doctor/case.go new file mode 100644 index 00000000..72a60279 --- /dev/null +++ b/internal/use-case/main-use-case/doctor/case.go @@ -0,0 +1,275 @@ +package doctor + +import ( + e "simrs-vx/internal/domain/main-entities/doctor" + "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" +) + +const source = "doctor" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Doctor{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Doctor + var dataList []e.Doctor + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Doctor + 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: uint16(input.Id)} + var data *e.Doctor + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Doctor + 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 + +} diff --git a/internal/use-case/main-use-case/doctor/helper.go b/internal/use-case/main-use-case/doctor/helper.go new file mode 100644 index 00000000..c6898db6 --- /dev/null +++ b/internal/use-case/main-use-case/doctor/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package doctor + +import ( + e "simrs-vx/internal/domain/main-entities/doctor" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Doctor) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Employee_Id = inputSrc.Employee_Id + data.IHS_Number = inputSrc.IHS_Number + data.SIP_Number = inputSrc.SIP_Number + data.Unit_Id = inputSrc.Unit_Id +} diff --git a/internal/use-case/main-use-case/doctor/lib.go b/internal/use-case/main-use-case/doctor/lib.go new file mode 100644 index 00000000..b75d9bb1 --- /dev/null +++ b/internal/use-case/main-use-case/doctor/lib.go @@ -0,0 +1,149 @@ +package doctor + +import ( + e "simrs-vx/internal/domain/main-entities/doctor" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Doctor, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Doctor{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Doctor, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Doctor{} + 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.Doctor{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Doctor, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Doctor{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Doctor, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Doctor, 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 +} diff --git a/internal/use-case/main-use-case/doctor/middleware-runner.go b/internal/use-case/main-use-case/doctor/middleware-runner.go new file mode 100644 index 00000000..fe6d6f4e --- /dev/null +++ b/internal/use-case/main-use-case/doctor/middleware-runner.go @@ -0,0 +1,103 @@ +package doctor + +import ( + e "simrs-vx/internal/domain/main-entities/doctor" + 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.Doctor) 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.Doctor) 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.Doctor) 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.Doctor) 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.Doctor) 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 +} diff --git a/internal/use-case/main-use-case/doctor/middleware.go b/internal/use-case/main-use-case/doctor/middleware.go new file mode 100644 index 00000000..b6bfc120 --- /dev/null +++ b/internal/use-case/main-use-case/doctor/middleware.go @@ -0,0 +1,9 @@ +package doctor + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/doctor/tycovar.go b/internal/use-case/main-use-case/doctor/tycovar.go new file mode 100644 index 00000000..605a74d9 --- /dev/null +++ b/internal/use-case/main-use-case/doctor/tycovar.go @@ -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 doctor + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/doctor" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Doctor, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Doctor, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Doctor, 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 diff --git a/internal/use-case/main-use-case/employee/case.go b/internal/use-case/main-use-case/employee/case.go new file mode 100644 index 00000000..68476e13 --- /dev/null +++ b/internal/use-case/main-use-case/employee/case.go @@ -0,0 +1,275 @@ +package employee + +import ( + e "simrs-vx/internal/domain/main-entities/employee" + "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" +) + +const source = "employee" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Employee{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Employee + var dataList []e.Employee + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Employee + 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: uint16(input.Id)} + var data *e.Employee + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Employee + 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 + +} diff --git a/internal/use-case/main-use-case/employee/helper.go b/internal/use-case/main-use-case/employee/helper.go new file mode 100644 index 00000000..1660048f --- /dev/null +++ b/internal/use-case/main-use-case/employee/helper.go @@ -0,0 +1,26 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package employee + +import ( + e "simrs-vx/internal/domain/main-entities/employee" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Employee) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.User_Id = inputSrc.User_Id + data.Person_Id = inputSrc.Person_Id + data.Position_Code = inputSrc.Position_Code + data.Division_Code = inputSrc.Division_Code + data.Number = inputSrc.Number + data.Status_Code = inputSrc.Status_Code +} diff --git a/internal/use-case/main-use-case/employee/lib.go b/internal/use-case/main-use-case/employee/lib.go new file mode 100644 index 00000000..261acb56 --- /dev/null +++ b/internal/use-case/main-use-case/employee/lib.go @@ -0,0 +1,149 @@ +package employee + +import ( + e "simrs-vx/internal/domain/main-entities/employee" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Employee, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Employee{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Employee, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Employee{} + 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.Employee{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Employee, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Employee{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Employee, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Employee, 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 +} diff --git a/internal/use-case/main-use-case/employee/middleware-runner.go b/internal/use-case/main-use-case/employee/middleware-runner.go new file mode 100644 index 00000000..8d7f3846 --- /dev/null +++ b/internal/use-case/main-use-case/employee/middleware-runner.go @@ -0,0 +1,103 @@ +package employee + +import ( + e "simrs-vx/internal/domain/main-entities/employee" + 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.Employee) 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.Employee) 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.Employee) 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.Employee) 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.Employee) 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 +} diff --git a/internal/use-case/main-use-case/employee/middleware.go b/internal/use-case/main-use-case/employee/middleware.go new file mode 100644 index 00000000..b567b6e3 --- /dev/null +++ b/internal/use-case/main-use-case/employee/middleware.go @@ -0,0 +1,9 @@ +package employee + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/employee/tycovar.go b/internal/use-case/main-use-case/employee/tycovar.go new file mode 100644 index 00000000..dbc22ea6 --- /dev/null +++ b/internal/use-case/main-use-case/employee/tycovar.go @@ -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 employee + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/employee" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Employee, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Employee, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Employee, 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 diff --git a/internal/use-case/main-use-case/infra-group/helper.go b/internal/use-case/main-use-case/infra-group/helper.go index ab02742d..653c0c36 100644 --- a/internal/use-case/main-use-case/infra-group/helper.go +++ b/internal/use-case/main-use-case/infra-group/helper.go @@ -18,5 +18,5 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.InfraGroup) { } data.Code = inputSrc.Code data.Name = inputSrc.Name - + data.Level = inputSrc.Level } diff --git a/internal/use-case/main-use-case/item-group/case.go b/internal/use-case/main-use-case/item-group/case.go new file mode 100644 index 00000000..91cd05c7 --- /dev/null +++ b/internal/use-case/main-use-case/item-group/case.go @@ -0,0 +1,275 @@ +package itemgroup + +import ( + e "simrs-vx/internal/domain/main-entities/item-group" + "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" +) + +const source = "item-group" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.ItemGroup{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.ItemGroup + var dataList []e.ItemGroup + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ItemGroup + 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: uint16(input.Id)} + var data *e.ItemGroup + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.ItemGroup + 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 + +} diff --git a/internal/use-case/main-use-case/item-group/helper.go b/internal/use-case/main-use-case/item-group/helper.go new file mode 100644 index 00000000..98af4a89 --- /dev/null +++ b/internal/use-case/main-use-case/item-group/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package itemgroup + +import ( + e "simrs-vx/internal/domain/main-entities/item-group" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ItemGroup) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/item-group/lib.go b/internal/use-case/main-use-case/item-group/lib.go new file mode 100644 index 00000000..9e86970a --- /dev/null +++ b/internal/use-case/main-use-case/item-group/lib.go @@ -0,0 +1,149 @@ +package itemgroup + +import ( + e "simrs-vx/internal/domain/main-entities/item-group" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.ItemGroup, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.ItemGroup{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ItemGroup, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ItemGroup{} + 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.ItemGroup{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.ItemGroup, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ItemGroup{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.ItemGroup, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.ItemGroup, 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 +} diff --git a/internal/use-case/main-use-case/item-group/middleware-runner.go b/internal/use-case/main-use-case/item-group/middleware-runner.go new file mode 100644 index 00000000..0fa678be --- /dev/null +++ b/internal/use-case/main-use-case/item-group/middleware-runner.go @@ -0,0 +1,103 @@ +package itemgroup + +import ( + e "simrs-vx/internal/domain/main-entities/item-group" + 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.ItemGroup) 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.ItemGroup) 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.ItemGroup) 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.ItemGroup) 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.ItemGroup) 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 +} diff --git a/internal/use-case/main-use-case/item-group/middleware.go b/internal/use-case/main-use-case/item-group/middleware.go new file mode 100644 index 00000000..ab8a3227 --- /dev/null +++ b/internal/use-case/main-use-case/item-group/middleware.go @@ -0,0 +1,9 @@ +package itemgroup + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/item-group/tycovar.go b/internal/use-case/main-use-case/item-group/tycovar.go new file mode 100644 index 00000000..17ad5bc0 --- /dev/null +++ b/internal/use-case/main-use-case/item-group/tycovar.go @@ -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 itemgroup + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/item-group" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ItemGroup, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ItemGroup, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ItemGroup, 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 diff --git a/internal/use-case/main-use-case/nurse/case.go b/internal/use-case/main-use-case/nurse/case.go new file mode 100644 index 00000000..9bb32296 --- /dev/null +++ b/internal/use-case/main-use-case/nurse/case.go @@ -0,0 +1,275 @@ +package nurse + +import ( + e "simrs-vx/internal/domain/main-entities/nurse" + "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" +) + +const source = "nurse" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Nurse{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Nurse + var dataList []e.Nurse + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Nurse + 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: uint16(input.Id)} + var data *e.Nurse + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Nurse + 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 + +} diff --git a/internal/use-case/main-use-case/nurse/helper.go b/internal/use-case/main-use-case/nurse/helper.go new file mode 100644 index 00000000..15278d1e --- /dev/null +++ b/internal/use-case/main-use-case/nurse/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package nurse + +import ( + e "simrs-vx/internal/domain/main-entities/nurse" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Nurse) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Employee_Id = inputSrc.Employee_Id + data.IHS_Number = inputSrc.IHS_Number +} diff --git a/internal/use-case/main-use-case/nurse/lib.go b/internal/use-case/main-use-case/nurse/lib.go new file mode 100644 index 00000000..263888e7 --- /dev/null +++ b/internal/use-case/main-use-case/nurse/lib.go @@ -0,0 +1,149 @@ +package nurse + +import ( + e "simrs-vx/internal/domain/main-entities/nurse" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Nurse, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Nurse{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Nurse, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Nurse{} + 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.Nurse{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Nurse, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Nurse{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Nurse, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Nurse, 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 +} diff --git a/internal/use-case/main-use-case/nurse/middleware-runner.go b/internal/use-case/main-use-case/nurse/middleware-runner.go new file mode 100644 index 00000000..94d530f3 --- /dev/null +++ b/internal/use-case/main-use-case/nurse/middleware-runner.go @@ -0,0 +1,103 @@ +package nurse + +import ( + e "simrs-vx/internal/domain/main-entities/nurse" + 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.Nurse) 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.Nurse) 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.Nurse) 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.Nurse) 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.Nurse) 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 +} diff --git a/internal/use-case/main-use-case/nurse/middleware.go b/internal/use-case/main-use-case/nurse/middleware.go new file mode 100644 index 00000000..95f23d24 --- /dev/null +++ b/internal/use-case/main-use-case/nurse/middleware.go @@ -0,0 +1,9 @@ +package nurse + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/nurse/tycovar.go b/internal/use-case/main-use-case/nurse/tycovar.go new file mode 100644 index 00000000..0754e03c --- /dev/null +++ b/internal/use-case/main-use-case/nurse/tycovar.go @@ -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 nurse + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/nurse" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Nurse, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Nurse, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Nurse, 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 diff --git a/internal/use-case/main-use-case/nutritionist/case.go b/internal/use-case/main-use-case/nutritionist/case.go new file mode 100644 index 00000000..b7cad178 --- /dev/null +++ b/internal/use-case/main-use-case/nutritionist/case.go @@ -0,0 +1,275 @@ +package nutritionist + +import ( + e "simrs-vx/internal/domain/main-entities/nutritionist" + "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" +) + +const source = "nutritionist" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Nutritionist{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Nutritionist + var dataList []e.Nutritionist + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Nutritionist + 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: uint16(input.Id)} + var data *e.Nutritionist + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Nutritionist + 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 + +} diff --git a/internal/use-case/main-use-case/nutritionist/helper.go b/internal/use-case/main-use-case/nutritionist/helper.go new file mode 100644 index 00000000..4ff20809 --- /dev/null +++ b/internal/use-case/main-use-case/nutritionist/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package nutritionist + +import ( + e "simrs-vx/internal/domain/main-entities/nutritionist" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Nutritionist) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Employee_Id = inputSrc.Employee_Id + data.IHS_Number = inputSrc.IHS_Number +} diff --git a/internal/use-case/main-use-case/nutritionist/lib.go b/internal/use-case/main-use-case/nutritionist/lib.go new file mode 100644 index 00000000..263c4231 --- /dev/null +++ b/internal/use-case/main-use-case/nutritionist/lib.go @@ -0,0 +1,149 @@ +package nutritionist + +import ( + e "simrs-vx/internal/domain/main-entities/nutritionist" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Nutritionist, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Nutritionist{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Nutritionist, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Nutritionist{} + 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.Nutritionist{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Nutritionist, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Nutritionist{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Nutritionist, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Nutritionist, 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 +} diff --git a/internal/use-case/main-use-case/nutritionist/middleware-runner.go b/internal/use-case/main-use-case/nutritionist/middleware-runner.go new file mode 100644 index 00000000..57b7857e --- /dev/null +++ b/internal/use-case/main-use-case/nutritionist/middleware-runner.go @@ -0,0 +1,103 @@ +package nutritionist + +import ( + e "simrs-vx/internal/domain/main-entities/nutritionist" + 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.Nutritionist) 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.Nutritionist) 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.Nutritionist) 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.Nutritionist) 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.Nutritionist) 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 +} diff --git a/internal/use-case/main-use-case/nutritionist/middleware.go b/internal/use-case/main-use-case/nutritionist/middleware.go new file mode 100644 index 00000000..d4e0d4a9 --- /dev/null +++ b/internal/use-case/main-use-case/nutritionist/middleware.go @@ -0,0 +1,9 @@ +package nutritionist + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/nutritionist/tycovar.go b/internal/use-case/main-use-case/nutritionist/tycovar.go new file mode 100644 index 00000000..f4deb766 --- /dev/null +++ b/internal/use-case/main-use-case/nutritionist/tycovar.go @@ -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 nutritionist + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/nutritionist" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Nutritionist, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Nutritionist, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Nutritionist, 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 diff --git a/internal/use-case/main-use-case/pharmacist/case.go b/internal/use-case/main-use-case/pharmacist/case.go new file mode 100644 index 00000000..a2e7aecc --- /dev/null +++ b/internal/use-case/main-use-case/pharmacist/case.go @@ -0,0 +1,275 @@ +package pharmacist + +import ( + e "simrs-vx/internal/domain/main-entities/pharmacist" + "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" +) + +const source = "pharmacist" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Pharmacist{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Pharmacist + var dataList []e.Pharmacist + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Pharmacist + 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: uint16(input.Id)} + var data *e.Pharmacist + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Pharmacist + 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 + +} diff --git a/internal/use-case/main-use-case/pharmacist/helper.go b/internal/use-case/main-use-case/pharmacist/helper.go new file mode 100644 index 00000000..deb230cf --- /dev/null +++ b/internal/use-case/main-use-case/pharmacist/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package pharmacist + +import ( + e "simrs-vx/internal/domain/main-entities/pharmacist" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Pharmacist) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Employee_Id = inputSrc.Employee_Id + data.IHS_Number = inputSrc.IHS_Number +} diff --git a/internal/use-case/main-use-case/pharmacist/lib.go b/internal/use-case/main-use-case/pharmacist/lib.go new file mode 100644 index 00000000..18d41f26 --- /dev/null +++ b/internal/use-case/main-use-case/pharmacist/lib.go @@ -0,0 +1,149 @@ +package pharmacist + +import ( + e "simrs-vx/internal/domain/main-entities/pharmacist" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Pharmacist, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Pharmacist{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pharmacist, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Pharmacist{} + 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.Pharmacist{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Pharmacist, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Pharmacist{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Pharmacist, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Pharmacist, 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 +} diff --git a/internal/use-case/main-use-case/pharmacist/middleware-runner.go b/internal/use-case/main-use-case/pharmacist/middleware-runner.go new file mode 100644 index 00000000..86837f3f --- /dev/null +++ b/internal/use-case/main-use-case/pharmacist/middleware-runner.go @@ -0,0 +1,103 @@ +package pharmacist + +import ( + e "simrs-vx/internal/domain/main-entities/pharmacist" + 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.Pharmacist) 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.Pharmacist) 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.Pharmacist) 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.Pharmacist) 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.Pharmacist) 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 +} diff --git a/internal/use-case/main-use-case/pharmacist/middleware.go b/internal/use-case/main-use-case/pharmacist/middleware.go new file mode 100644 index 00000000..57fc7a33 --- /dev/null +++ b/internal/use-case/main-use-case/pharmacist/middleware.go @@ -0,0 +1,9 @@ +package pharmacist + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/pharmacist/tycovar.go b/internal/use-case/main-use-case/pharmacist/tycovar.go new file mode 100644 index 00000000..83e2c894 --- /dev/null +++ b/internal/use-case/main-use-case/pharmacist/tycovar.go @@ -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 pharmacist + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/pharmacist" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Pharmacist, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Pharmacist, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Pharmacist, 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 diff --git a/internal/use-case/main-use-case/practice-schedule/case.go b/internal/use-case/main-use-case/practice-schedule/case.go new file mode 100644 index 00000000..82ef0c8b --- /dev/null +++ b/internal/use-case/main-use-case/practice-schedule/case.go @@ -0,0 +1,275 @@ +package practiceschedule + +import ( + e "simrs-vx/internal/domain/main-entities/practice-schedule" + "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" +) + +const source = "practice-schedule" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.PracticeSchedule{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.PracticeSchedule + var dataList []e.PracticeSchedule + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.PracticeSchedule + 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.PracticeSchedule + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.PracticeSchedule + 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 + +} diff --git a/internal/use-case/main-use-case/practice-schedule/helper.go b/internal/use-case/main-use-case/practice-schedule/helper.go new file mode 100644 index 00000000..5c9f7815 --- /dev/null +++ b/internal/use-case/main-use-case/practice-schedule/helper.go @@ -0,0 +1,25 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package practiceschedule + +import ( + e "simrs-vx/internal/domain/main-entities/practice-schedule" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.PracticeSchedule) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Doctor_Id = inputSrc.Doctor_Id + data.Unit_Code = inputSrc.Unit_Code + data.Day_Code = inputSrc.Day_Code + data.StartTime = inputSrc.StartTime + data.EndTime = inputSrc.EndTime +} diff --git a/internal/use-case/main-use-case/practice-schedule/lib.go b/internal/use-case/main-use-case/practice-schedule/lib.go new file mode 100644 index 00000000..a926e984 --- /dev/null +++ b/internal/use-case/main-use-case/practice-schedule/lib.go @@ -0,0 +1,149 @@ +package practiceschedule + +import ( + e "simrs-vx/internal/domain/main-entities/practice-schedule" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.PracticeSchedule, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.PracticeSchedule{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.PracticeSchedule, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.PracticeSchedule{} + 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.PracticeSchedule{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.PracticeSchedule, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.PracticeSchedule{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.PracticeSchedule, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.PracticeSchedule, 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 +} diff --git a/internal/use-case/main-use-case/practice-schedule/middleware-runner.go b/internal/use-case/main-use-case/practice-schedule/middleware-runner.go new file mode 100644 index 00000000..1b4b9a28 --- /dev/null +++ b/internal/use-case/main-use-case/practice-schedule/middleware-runner.go @@ -0,0 +1,103 @@ +package practiceschedule + +import ( + e "simrs-vx/internal/domain/main-entities/practice-schedule" + 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.PracticeSchedule) 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.PracticeSchedule) 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.PracticeSchedule) 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.PracticeSchedule) 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.PracticeSchedule) 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 +} diff --git a/internal/use-case/main-use-case/practice-schedule/middleware.go b/internal/use-case/main-use-case/practice-schedule/middleware.go new file mode 100644 index 00000000..b8902351 --- /dev/null +++ b/internal/use-case/main-use-case/practice-schedule/middleware.go @@ -0,0 +1,9 @@ +package practiceschedule + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/practice-schedule/tycovar.go b/internal/use-case/main-use-case/practice-schedule/tycovar.go new file mode 100644 index 00000000..ffcd1e15 --- /dev/null +++ b/internal/use-case/main-use-case/practice-schedule/tycovar.go @@ -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 practiceschedule + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/practice-schedule" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.PracticeSchedule, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.PracticeSchedule, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.PracticeSchedule, 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 From 4e3330da23610c2a914a828045bfaa0b7d4dface Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 13:45:04 +0700 Subject: [PATCH 26/40] feat (crud): regis handler --- .../interface/main-handler/counter/handler.go | 71 +++++++++++++++++++ .../main-handler/diagnose-src/handler.go | 71 +++++++++++++++++++ .../interface/main-handler/doctor/handler.go | 71 +++++++++++++++++++ .../main-handler/employee/handler.go | 70 ++++++++++++++++++ .../main-handler/infra-group/handler.go | 71 +++++++++++++++++++ .../main-handler/item-group/handler.go | 71 +++++++++++++++++++ .../interface/main-handler/main-handler.go | 24 +++++++ .../interface/main-handler/nurse/handler.go | 71 +++++++++++++++++++ .../main-handler/nutritionist/handler.go | 71 +++++++++++++++++++ .../main-handler/pharmacist/handler.go | 71 +++++++++++++++++++ .../main-handler/pharmacy-company/handler.go | 71 +++++++++++++++++++ .../main-handler/practice-schedule/handler.go | 71 +++++++++++++++++++ .../main-handler/procedure-src/handler.go | 71 +++++++++++++++++++ 13 files changed, 875 insertions(+) create mode 100644 internal/interface/main-handler/counter/handler.go create mode 100644 internal/interface/main-handler/diagnose-src/handler.go create mode 100644 internal/interface/main-handler/doctor/handler.go create mode 100644 internal/interface/main-handler/employee/handler.go create mode 100644 internal/interface/main-handler/infra-group/handler.go create mode 100644 internal/interface/main-handler/item-group/handler.go create mode 100644 internal/interface/main-handler/nurse/handler.go create mode 100644 internal/interface/main-handler/nutritionist/handler.go create mode 100644 internal/interface/main-handler/pharmacist/handler.go create mode 100644 internal/interface/main-handler/pharmacy-company/handler.go create mode 100644 internal/interface/main-handler/practice-schedule/handler.go create mode 100644 internal/interface/main-handler/procedure-src/handler.go diff --git a/internal/interface/main-handler/counter/handler.go b/internal/interface/main-handler/counter/handler.go new file mode 100644 index 00000000..e02398b9 --- /dev/null +++ b/internal/interface/main-handler/counter/handler.go @@ -0,0 +1,71 @@ +package counter + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/counter" + u "simrs-vx/internal/use-case/main-use-case/counter" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/diagnose-src/handler.go b/internal/interface/main-handler/diagnose-src/handler.go new file mode 100644 index 00000000..6c2e9faf --- /dev/null +++ b/internal/interface/main-handler/diagnose-src/handler.go @@ -0,0 +1,71 @@ +package diagnosesrc + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/diagnose-src" + u "simrs-vx/internal/use-case/main-use-case/diagnose-src" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/doctor/handler.go b/internal/interface/main-handler/doctor/handler.go new file mode 100644 index 00000000..27281884 --- /dev/null +++ b/internal/interface/main-handler/doctor/handler.go @@ -0,0 +1,71 @@ +package doctor + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/doctor" + u "simrs-vx/internal/use-case/main-use-case/doctor" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/employee/handler.go b/internal/interface/main-handler/employee/handler.go new file mode 100644 index 00000000..da859e96 --- /dev/null +++ b/internal/interface/main-handler/employee/handler.go @@ -0,0 +1,70 @@ +package employee + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auemployee + e "simrs-vx/internal/domain/main-entities/employee" + u "simrs-vx/internal/use-case/main-use-case/employee" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/infra-group/handler.go b/internal/interface/main-handler/infra-group/handler.go new file mode 100644 index 00000000..9b3c090a --- /dev/null +++ b/internal/interface/main-handler/infra-group/handler.go @@ -0,0 +1,71 @@ +package infragroup + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/infra-group" + u "simrs-vx/internal/use-case/main-use-case/infra-group" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/item-group/handler.go b/internal/interface/main-handler/item-group/handler.go new file mode 100644 index 00000000..71eb8b60 --- /dev/null +++ b/internal/interface/main-handler/item-group/handler.go @@ -0,0 +1,71 @@ +package itemgroup + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/item-group" + u "simrs-vx/internal/use-case/main-use-case/item-group" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index c5bc4da1..acbd4b61 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -5,11 +5,18 @@ import ( /******************** main / transaction ********************/ auth "simrs-vx/internal/interface/main-handler/authentication" + counter "simrs-vx/internal/interface/main-handler/counter" + practiceschedule "simrs-vx/internal/interface/main-handler/practice-schedule" /******************** actor ********************/ + doctor "simrs-vx/internal/interface/main-handler/doctor" + employee "simrs-vx/internal/interface/main-handler/employee" + nurse "simrs-vx/internal/interface/main-handler/nurse" + nutritionist "simrs-vx/internal/interface/main-handler/nutritionist" person "simrs-vx/internal/interface/main-handler/person" personaddress "simrs-vx/internal/interface/main-handler/person-address" personcontact "simrs-vx/internal/interface/main-handler/person-contact" + pharmacist "simrs-vx/internal/interface/main-handler/pharmacist" user "simrs-vx/internal/interface/main-handler/user" /******************** external ********************/ @@ -28,9 +35,14 @@ import ( zlc "simrs-vx/pkg/zerolog-ctx" /******************** sources ********************/ + diagnosesrc "simrs-vx/internal/interface/main-handler/diagnose-src" division "simrs-vx/internal/interface/main-handler/division" divisionposition "simrs-vx/internal/interface/main-handler/division-position" + infragroup "simrs-vx/internal/interface/main-handler/infra-group" installation "simrs-vx/internal/interface/main-handler/installation" + itemgroup "simrs-vx/internal/interface/main-handler/item-group" + pharmacycompany "simrs-vx/internal/interface/main-handler/pharmacy-company" + proceduresrc "simrs-vx/internal/interface/main-handler/procedure-src" unit "simrs-vx/internal/interface/main-handler/unit" district "simrs-vx/internal/interface/main-handler/district" @@ -58,6 +70,8 @@ func SetRoutes() http.Handler { r.HandleFunc("POST /v1/authentication/login", auth.Login) // r.HandleFunc("POST /v1/authentication/logout", auth.Logout) hk.Route("POST /v1/authentication/logout", r, auth.GuardMW, auth.Logout) + hc.RegCrud(r, "/v1/practice-schedule", practiceschedule.O) + hc.RegCrud(r, "/v1/counter", counter.O) /******************** actor ********************/ hk.GroupRoutes("/v1/user", r, hk.MapHandlerFunc{ @@ -72,12 +86,22 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/person", person.O) hc.RegCrud(r, "/v1/person-address", personaddress.O) hc.RegCrud(r, "/v1/person-contact", personcontact.O) + hc.RegCrud(r, "/v1/employee", employee.O) + hc.RegCrud(r, "/v1/doctor", doctor.O) + hc.RegCrud(r, "/v1/nurse", nurse.O) + hc.RegCrud(r, "/v1/nutritionist", nutritionist.O) + hc.RegCrud(r, "/v1/pharmacist", pharmacist.O) /******************** sources ********************/ hc.RegCrud(r, "/v1/division", division.O) hc.RegCrud(r, "/v1/division-position", divisionposition.O) hc.RegCrud(r, "/v1/installation", installation.O) hc.RegCrud(r, "/v1/unit", unit.O) + hc.RegCrud(r, "/v1/pharmacy-company", pharmacycompany.O) + hc.RegCrud(r, "/v1/diagnose-src", diagnosesrc.O) + hc.RegCrud(r, "/v1/procedure-src", proceduresrc.O) + hc.RegCrud(r, "/v1/infra-group", infragroup.O) + hc.RegCrud(r, "/v1/item-group", itemgroup.O) hc.RegCrud(r, "/v1/village", village.O) hc.RegCrud(r, "/v1/district", district.O) diff --git a/internal/interface/main-handler/nurse/handler.go b/internal/interface/main-handler/nurse/handler.go new file mode 100644 index 00000000..6df7a18e --- /dev/null +++ b/internal/interface/main-handler/nurse/handler.go @@ -0,0 +1,71 @@ +package nurse + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/nurse" + u "simrs-vx/internal/use-case/main-use-case/nurse" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/nutritionist/handler.go b/internal/interface/main-handler/nutritionist/handler.go new file mode 100644 index 00000000..708a8b52 --- /dev/null +++ b/internal/interface/main-handler/nutritionist/handler.go @@ -0,0 +1,71 @@ +package nutritionist + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/nutritionist" + u "simrs-vx/internal/use-case/main-use-case/nutritionist" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/pharmacist/handler.go b/internal/interface/main-handler/pharmacist/handler.go new file mode 100644 index 00000000..fd0746e7 --- /dev/null +++ b/internal/interface/main-handler/pharmacist/handler.go @@ -0,0 +1,71 @@ +package pharmacist + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/pharmacist" + u "simrs-vx/internal/use-case/main-use-case/pharmacist" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/pharmacy-company/handler.go b/internal/interface/main-handler/pharmacy-company/handler.go new file mode 100644 index 00000000..2f0584ba --- /dev/null +++ b/internal/interface/main-handler/pharmacy-company/handler.go @@ -0,0 +1,71 @@ +package pharmacycompany + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/pharmacy-company" + u "simrs-vx/internal/use-case/main-use-case/pharmacy-company" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/practice-schedule/handler.go b/internal/interface/main-handler/practice-schedule/handler.go new file mode 100644 index 00000000..e2bc3c84 --- /dev/null +++ b/internal/interface/main-handler/practice-schedule/handler.go @@ -0,0 +1,71 @@ +package practiceschedule + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/practice-schedule" + u "simrs-vx/internal/use-case/main-use-case/practice-schedule" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/procedure-src/handler.go b/internal/interface/main-handler/procedure-src/handler.go new file mode 100644 index 00000000..ade14b42 --- /dev/null +++ b/internal/interface/main-handler/procedure-src/handler.go @@ -0,0 +1,71 @@ +package proceduresrc + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/procedure-src" + u "simrs-vx/internal/use-case/main-use-case/procedure-src" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} From ad41ac0bd8b36a6283d7c1d8ffe8a1d0f8c5d2bf Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 13:46:04 +0700 Subject: [PATCH 27/40] feat (practice-schedule): fix json convention --- .../main-entities/practice-schedule/dto.go | 16 ++++++++-------- .../main-entities/practice-schedule/entity.go | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/domain/main-entities/practice-schedule/dto.go b/internal/domain/main-entities/practice-schedule/dto.go index 5a74137e..2f6cda94 100644 --- a/internal/domain/main-entities/practice-schedule/dto.go +++ b/internal/domain/main-entities/practice-schedule/dto.go @@ -9,16 +9,16 @@ type CreateDto struct { Doctor_Id *uint `json:"doctor_id"` Unit_Code *string `json:"unit_code"` Day_Code *erx.DayCode `json:"day_code"` - StartTime *string `json:"start_time"` - EndTime *string `json:"end_time"` + StartTime *string `json:"startTime"` + EndTime *string `json:"endTime"` } type ReadListDto struct { Doctor_Id *uint `json:"doctor_id"` Unit_Code *string `json:"unit_code"` Day_Code *erx.DayCode `json:"day_code"` - StartTime *string `json:"start_time"` - EndTime *string `json:"end_time"` + StartTime *string `json:"startTime"` + EndTime *string `json:"endTime"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -30,8 +30,8 @@ type ReadDetailDto struct { Doctor_Id *uint `json:"doctor_id"` Unit_Code *string `json:"unit_code"` Day_Code *erx.DayCode `json:"day_code"` - StartTime *string `json:"start_time"` - EndTime *string `json:"end_time"` + StartTime *string `json:"startTime"` + EndTime *string `json:"endTime"` } type UpdateDto struct { @@ -54,8 +54,8 @@ type ResponseDto struct { Doctor_Id *uint `json:"doctor_id"` Unit_Code *string `json:"unit_code"` Day_Code *erx.DayCode `json:"day_code"` - StartTime *string `json:"start_time"` - EndTime *string `json:"end_time"` + StartTime *string `json:"startTime"` + EndTime *string `json:"endTime"` } func (d PracticeSchedule) ToResponse() ResponseDto { diff --git a/internal/domain/main-entities/practice-schedule/entity.go b/internal/domain/main-entities/practice-schedule/entity.go index e24e8584..5bd1c006 100644 --- a/internal/domain/main-entities/practice-schedule/entity.go +++ b/internal/domain/main-entities/practice-schedule/entity.go @@ -14,6 +14,6 @@ type PracticeSchedule struct { Unit_Code *string `json:"unit_code"` Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` Day_Code *erx.DayCode `json:"day_code"` - StartTime *string `json:"start_time" gorm:"size:5"` - EndTime *string `json:"end_time" gorm:"size:5"` + StartTime *string `json:"startTime" gorm:"size:5"` + EndTime *string `json:"endTime" gorm:"size:5"` } From c1d14f3770ea9531fe0bcce6622c4edb1db8d64c Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 14:40:56 +0700 Subject: [PATCH 28/40] add uom, item, itemprice, infra, medicinegroup, medicinemethod, mscusrccategory, mcusrc --- cmd/migration/migrations/20250827072230.sql | 101 ++++++++++++++++++ cmd/migration/migrations/atlas.sum | 5 +- .../main-entities/employee copy/entity.go | 19 ++++ internal/domain/main-entities/employee/dto.go | 9 +- .../domain/main-entities/employee/entity.go | 3 +- internal/domain/main-entities/infra/dto.go | 84 +++++++++++++++ internal/domain/main-entities/infra/entity.go | 18 ++++ .../domain/main-entities/item-price/dto.go | 65 +++++++++++ .../domain/main-entities/item-price/entity.go | 13 +++ internal/domain/main-entities/item/dto.go | 89 +++++++++++++++ internal/domain/main-entities/item/entity.go | 19 ++++ .../main-entities/mcu-src-category/dto.go | 69 ++++++++++++ .../main-entities/mcu-src-category/entity.go | 13 +++ internal/domain/main-entities/mcu-src/dto.go | 68 ++++++++++++ .../domain/main-entities/mcu-src/entity.go | 12 +++ .../main-entities/medicine-group/dto.go | 63 +++++++++++ .../main-entities/medicine-group/entity.go | 11 ++ .../main-entities/medicine-method/dto.go | 63 +++++++++++ .../main-entities/medicine-method/entity.go | 11 ++ internal/domain/main-entities/uom/dto.go | 63 +++++++++++ internal/domain/main-entities/uom/entity.go | 11 ++ .../domain/references/clinical/clinical.go | 12 +++ internal/domain/references/common/common.go | 24 ++--- .../references/organization/organization.go | 48 ++------- internal/interface/migration/migration.go | 16 +++ 25 files changed, 845 insertions(+), 64 deletions(-) create mode 100644 cmd/migration/migrations/20250827072230.sql create mode 100644 internal/domain/main-entities/employee copy/entity.go create mode 100644 internal/domain/main-entities/infra/dto.go create mode 100644 internal/domain/main-entities/infra/entity.go create mode 100644 internal/domain/main-entities/item-price/dto.go create mode 100644 internal/domain/main-entities/item-price/entity.go create mode 100644 internal/domain/main-entities/item/dto.go create mode 100644 internal/domain/main-entities/item/entity.go create mode 100644 internal/domain/main-entities/mcu-src-category/dto.go create mode 100644 internal/domain/main-entities/mcu-src-category/entity.go create mode 100644 internal/domain/main-entities/mcu-src/dto.go create mode 100644 internal/domain/main-entities/mcu-src/entity.go create mode 100644 internal/domain/main-entities/medicine-group/dto.go create mode 100644 internal/domain/main-entities/medicine-group/entity.go create mode 100644 internal/domain/main-entities/medicine-method/dto.go create mode 100644 internal/domain/main-entities/medicine-method/entity.go create mode 100644 internal/domain/main-entities/uom/dto.go create mode 100644 internal/domain/main-entities/uom/entity.go create mode 100644 internal/domain/references/clinical/clinical.go diff --git a/cmd/migration/migrations/20250827072230.sql b/cmd/migration/migrations/20250827072230.sql new file mode 100644 index 00000000..b2968446 --- /dev/null +++ b/cmd/migration/migrations/20250827072230.sql @@ -0,0 +1,101 @@ +-- Create "McuSrc" table +CREATE TABLE "public"."McuSrc" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + "CheckupCategory_Code" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_McuSrc_Code" UNIQUE ("Code") +); +-- Create "McuSrcCategory" table +CREATE TABLE "public"."McuSrcCategory" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + "Scope_Code" character varying(10) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_McuSrcCategory_Code" UNIQUE ("Code") +); +-- Create "MedicineGroup" table +CREATE TABLE "public"."MedicineGroup" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(50) NULL, + "Name" character varying(100) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_MedicineGroup_Code" UNIQUE ("Code") +); +-- Create "MedicineMethod" table +CREATE TABLE "public"."MedicineMethod" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(50) NULL, + "Name" character varying(100) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_MedicineMethod_Code" UNIQUE ("Code") +); +-- Create "Uom" table +CREATE TABLE "public"."Uom" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Uom_Code" UNIQUE ("Code") +); +-- Create "Item" table +CREATE TABLE "public"."Item" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(50) NULL, + "Name" character varying(100) NULL, + "ItemGroup_Code" character varying(10) NULL, + "Uom_Code" character varying(10) NULL, + "Infra_Id" smallint NULL, + "Stock" numeric NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Item_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Item_ItemGroup" FOREIGN KEY ("ItemGroup_Code") REFERENCES "public"."ItemGroup" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Item_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Infra" table +CREATE TABLE "public"."Infra" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "InfraGroup_Code" character varying(10) NULL, + "Parent_Id" smallint NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Infra_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Infra_InfraGroup" FOREIGN KEY ("InfraGroup_Code") REFERENCES "public"."InfraGroup" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Infra_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "ItemPrice" table +CREATE TABLE "public"."ItemPrice" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Item_Id" bigint NULL, + "Price" numeric NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_ItemPrice_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index 46aee6d6..47331906 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,8 +1,9 @@ -h1:4uryCUq0L2CJ7E8H5cdmioR5WZgsBsOYyeEo78COgs0= +h1:qhTYEMOwm8TQ+FgXjr/nbT0/T/oRb7pvnXTcQSa/V7w= 20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= 20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= 20250825102900.sql h1:OAUnj87Wz7mrHykX14idePckUmRYa5UH0LylYDL76RI= 20250825103029.sql h1:iuZFrfUjNQM5kRpEwdYR8qinSp8SIkoJc3Dr8rD8BuI= 20250827015551.sql h1:Jq/RkXSWHEWuNigLunLzIrYgiyroSVD7J0waDMvdzvg= 20250827021904.sql h1:pgjwmQS1TxZ977a1tIXKq6pZnGauPrOUxLUTclV+fE4= -20250827024311.sql h1:6Wt8nK7R2qaTUvP8dZFwwqxAMdAhHAChxFRiI8BlzQo= +20250827024311.sql h1:eTlrQYcHa/jmb3qSZxgTB+7S4IXJ8B4yklUB36iZaDw= +20250827072230.sql h1:R5H47ODPcZeINYfzLE+VMQ+l000fLwXe70MQ4BxouGw= diff --git a/internal/domain/main-entities/employee copy/entity.go b/internal/domain/main-entities/employee copy/entity.go new file mode 100644 index 00000000..55b829fa --- /dev/null +++ b/internal/domain/main-entities/employee copy/entity.go @@ -0,0 +1,19 @@ +package employee + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/division" + erc "simrs-vx/internal/domain/references/common" + ero "simrs-vx/internal/domain/references/organization" +) + +type Employee struct { + ecore.Main // adjust this according to the needs + User_Id *uint `json:"user_id"` + Person_Id *uint `json:"person_id"` + Position_Code ero.EmployeePosisitionCode `json:"position_code" gorm:"not null;size:20"` + Division_Code *string `json:"division_code"` + Division *ed.Division `json:"division,omitempty" gorm:"foreignKey:Division_Code;references:Code"` + Number *string `json:"number" gorm:"size:20"` + Status_Code erc.StatusCode `json:"status_code" gorm:"not null;size:10"` +} diff --git a/internal/domain/main-entities/employee/dto.go b/internal/domain/main-entities/employee/dto.go index 8aa9402d..ff650793 100644 --- a/internal/domain/main-entities/employee/dto.go +++ b/internal/domain/main-entities/employee/dto.go @@ -4,12 +4,13 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/division" erc "simrs-vx/internal/domain/references/common" + ero "simrs-vx/internal/domain/references/organization" ) type CreateDto struct { User_Id *uint `json:"user_id"` Person_Id *uint `json:"person_id"` - Position_Code erc.EmployeePosisitionCode `json:"position_code"` + Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Number *string `json:"number"` Status_Code erc.StatusCode `json:"status_code"` @@ -18,7 +19,7 @@ type CreateDto struct { type ReadListDto struct { User_Id *uint `json:"user_id"` Person_Id *uint `json:"person_id"` - Position_Code erc.EmployeePosisitionCode `json:"position_code"` + Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Number *string `json:"number"` Status_Code erc.StatusCode `json:"status_code"` @@ -32,7 +33,7 @@ type ReadDetailDto struct { Id uint16 `json:"id"` User_Id *uint `json:"user_id"` Person_Id *uint `json:"person_id"` - Position_Code erc.EmployeePosisitionCode `json:"position_code"` + Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Number *string `json:"number"` Status_Code erc.StatusCode `json:"status_code"` @@ -57,7 +58,7 @@ type ResponseDto struct { ecore.Main User_Id *uint `json:"user_id"` Person_Id *uint `json:"person_id"` - Position_Code erc.EmployeePosisitionCode `json:"position_code"` + Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Division *ed.Division `json:"division,omitempty"` Number *string `json:"number"` diff --git a/internal/domain/main-entities/employee/entity.go b/internal/domain/main-entities/employee/entity.go index 8d6df9fd..55b829fa 100644 --- a/internal/domain/main-entities/employee/entity.go +++ b/internal/domain/main-entities/employee/entity.go @@ -4,13 +4,14 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/division" erc "simrs-vx/internal/domain/references/common" + ero "simrs-vx/internal/domain/references/organization" ) type Employee struct { ecore.Main // adjust this according to the needs User_Id *uint `json:"user_id"` Person_Id *uint `json:"person_id"` - Position_Code erc.EmployeePosisitionCode `json:"position_code" gorm:"not null;size:20"` + Position_Code ero.EmployeePosisitionCode `json:"position_code" gorm:"not null;size:20"` Division_Code *string `json:"division_code"` Division *ed.Division `json:"division,omitempty" gorm:"foreignKey:Division_Code;references:Code"` Number *string `json:"number" gorm:"size:20"` diff --git a/internal/domain/main-entities/infra/dto.go b/internal/domain/main-entities/infra/dto.go new file mode 100644 index 00000000..801883d1 --- /dev/null +++ b/internal/domain/main-entities/infra/dto.go @@ -0,0 +1,84 @@ +package infra + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eig "simrs-vx/internal/domain/main-entities/infra-group" + ei "simrs-vx/internal/domain/main-entities/item" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code *string `json:"infraGroup_code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code *string `json:"infraGroup_code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code *string `json:"infraGroup_code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code *string `json:"infraGroup_code"` + InfraGroup *eig.InfraGroup `json:"infraGroup,omitempty"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` +} + +func (d Infra) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + InfraGroup_Code: d.InfraGroup_Code, + InfraGroup: d.InfraGroup, + Parent_Id: d.Parent_Id, + Item_Id: d.Item_Id, + Item: d.Item, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []Infra) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/infra/entity.go b/internal/domain/main-entities/infra/entity.go new file mode 100644 index 00000000..7cb2001e --- /dev/null +++ b/internal/domain/main-entities/infra/entity.go @@ -0,0 +1,18 @@ +package infra + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eig "simrs-vx/internal/domain/main-entities/infra-group" + ei "simrs-vx/internal/domain/main-entities/item" +) + +type Infra struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:50"` + InfraGroup_Code *string `json:"infraGroup_code" gorm:"size:10"` + InfraGroup *eig.InfraGroup `json:"infraGroup,omitempty" gorm:"foreignKey:InfraGroup_Code;references:Code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` +} diff --git a/internal/domain/main-entities/item-price/dto.go b/internal/domain/main-entities/item-price/dto.go new file mode 100644 index 00000000..d048012b --- /dev/null +++ b/internal/domain/main-entities/item-price/dto.go @@ -0,0 +1,65 @@ +package itemprice + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" +) + +type CreateDto struct { + Item_Id *uint `json:"item_id"` + Price float64 `json:"price"` +} + +type ReadListDto struct { + Item_Id *uint `json:"item_id"` + Price float64 `json:"price"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Item_Id *uint `json:"item_id"` + Price float64 `json:"price"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` + Price float64 `json:"price"` +} + +func (d ItemPrice) ToResponse() ResponseDto { + resp := ResponseDto{ + Item_Id: d.Item_Id, + Price: d.Price, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []ItemPrice) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/item-price/entity.go b/internal/domain/main-entities/item-price/entity.go new file mode 100644 index 00000000..f1bf072f --- /dev/null +++ b/internal/domain/main-entities/item-price/entity.go @@ -0,0 +1,13 @@ +package itemprice + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" +) + +type ItemPrice struct { + ecore.Main // adjust this according to the needs + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` + Price float64 `json:"price"` +} diff --git a/internal/domain/main-entities/item/dto.go b/internal/domain/main-entities/item/dto.go new file mode 100644 index 00000000..5094e971 --- /dev/null +++ b/internal/domain/main-entities/item/dto.go @@ -0,0 +1,89 @@ +package item + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eig "simrs-vx/internal/domain/main-entities/item-group" + eu "simrs-vx/internal/domain/main-entities/uom" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *string `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *int16 `json:"infra_id"` + Stock *float64 `json:"stock"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *string `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *int16 `json:"infra_id"` + Stock *float64 `json:"stock"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *string `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *int16 `json:"infra_id"` + Stock *float64 `json:"stock"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *string `json:"itemGroup_code"` + ItemGroup *eig.ItemGroup `json:"itemGroup,omitempty"` + Uom_Code *string `json:"uom_code"` + Uom *eu.Uom `json:"uom,omitempty"` + Infra_Id *int16 `json:"infra_id"` + Stock *float64 `json:"stock"` +} + +func (d Item) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + ItemGroup_Code: d.ItemGroup_Code, + ItemGroup: d.ItemGroup, + Uom_Code: d.Uom_Code, + Uom: d.Uom, + Infra_Id: d.Infra_Id, + Stock: d.Stock, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Item) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/item/entity.go b/internal/domain/main-entities/item/entity.go new file mode 100644 index 00000000..561da2b2 --- /dev/null +++ b/internal/domain/main-entities/item/entity.go @@ -0,0 +1,19 @@ +package item + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eig "simrs-vx/internal/domain/main-entities/item-group" + eu "simrs-vx/internal/domain/main-entities/uom" +) + +type Item struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:50"` + Name string `json:"name" gorm:"size:100"` + ItemGroup_Code *string `json:"itemGroup_code" gorm:"size:10"` + ItemGroup *eig.ItemGroup `json:"itemGroup,omitempty" gorm:"foreignKey:ItemGroup_Code;references:Code"` + Uom_Code *string `json:"uom_code" gorm:"size:10"` + Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` + Infra_Id *int16 `json:"infra_id"` + Stock *float64 `json:"stock"` +} diff --git a/internal/domain/main-entities/mcu-src-category/dto.go b/internal/domain/main-entities/mcu-src-category/dto.go new file mode 100644 index 00000000..f78eb6a9 --- /dev/null +++ b/internal/domain/main-entities/mcu-src-category/dto.go @@ -0,0 +1,69 @@ +package division + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/clinical" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + Scope_Code *erc.CheckupScopeCode `json:"scope_code"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + Scope_Code *erc.CheckupScopeCode `json:"scope_code"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Scope_Code *erc.CheckupScopeCode `json:"scope_code"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + Scope_Code *erc.CheckupScopeCode `json:"scope_code"` +} + +func (d McuSrcCategory) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + Scope_Code: d.Scope_Code, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []McuSrcCategory) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/mcu-src-category/entity.go b/internal/domain/main-entities/mcu-src-category/entity.go new file mode 100644 index 00000000..61921168 --- /dev/null +++ b/internal/domain/main-entities/mcu-src-category/entity.go @@ -0,0 +1,13 @@ +package division + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/clinical" +) + +type McuSrcCategory struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:20"` + Name string `json:"name" gorm:"size:50"` + Scope_Code *erc.CheckupScopeCode `json:"scope_code" gorm:"size:10"` +} diff --git a/internal/domain/main-entities/mcu-src/dto.go b/internal/domain/main-entities/mcu-src/dto.go new file mode 100644 index 00000000..f0c06a51 --- /dev/null +++ b/internal/domain/main-entities/mcu-src/dto.go @@ -0,0 +1,68 @@ +package mcusrc + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + CheckupCategory_Code *string `json:"checkupCategory_code"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + CheckupCategory_Code *string `json:"checkupCategory_code"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + CheckupCategory_Code *string `json:"checkupCategory_code"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + CheckupCategory_Code *string `json:"checkupCategory_code"` +} + +func (d McuSrc) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + CheckupCategory_Code: d.CheckupCategory_Code, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []McuSrc) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/mcu-src/entity.go b/internal/domain/main-entities/mcu-src/entity.go new file mode 100644 index 00000000..bec60ac0 --- /dev/null +++ b/internal/domain/main-entities/mcu-src/entity.go @@ -0,0 +1,12 @@ +package mcusrc + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type McuSrc struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:20"` + Name string `json:"name" gorm:"size:50"` + CheckupCategory_Code *string `json:"checkupCategory_code" gorm:"size:20"` +} diff --git a/internal/domain/main-entities/medicine-group/dto.go b/internal/domain/main-entities/medicine-group/dto.go new file mode 100644 index 00000000..3ae439a3 --- /dev/null +++ b/internal/domain/main-entities/medicine-group/dto.go @@ -0,0 +1,63 @@ +package medicinegroup + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` +} + +func (d MedicineGroup) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []MedicineGroup) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/medicine-group/entity.go b/internal/domain/main-entities/medicine-group/entity.go new file mode 100644 index 00000000..612ab3b3 --- /dev/null +++ b/internal/domain/main-entities/medicine-group/entity.go @@ -0,0 +1,11 @@ +package medicinegroup + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type MedicineGroup struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:50"` + Name string `json:"name" gorm:"size:100"` +} diff --git a/internal/domain/main-entities/medicine-method/dto.go b/internal/domain/main-entities/medicine-method/dto.go new file mode 100644 index 00000000..074f8caa --- /dev/null +++ b/internal/domain/main-entities/medicine-method/dto.go @@ -0,0 +1,63 @@ +package medicinemethod + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` +} + +func (d MedicineMethod) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []MedicineMethod) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/medicine-method/entity.go b/internal/domain/main-entities/medicine-method/entity.go new file mode 100644 index 00000000..dde7c578 --- /dev/null +++ b/internal/domain/main-entities/medicine-method/entity.go @@ -0,0 +1,11 @@ +package medicinemethod + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type MedicineMethod struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:50"` + Name string `json:"name" gorm:"size:100"` +} diff --git a/internal/domain/main-entities/uom/dto.go b/internal/domain/main-entities/uom/dto.go new file mode 100644 index 00000000..08055c12 --- /dev/null +++ b/internal/domain/main-entities/uom/dto.go @@ -0,0 +1,63 @@ +package uom + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` +} + +func (d Uom) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []Uom) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/uom/entity.go b/internal/domain/main-entities/uom/entity.go new file mode 100644 index 00000000..6584311c --- /dev/null +++ b/internal/domain/main-entities/uom/entity.go @@ -0,0 +1,11 @@ +package uom + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type Uom struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/domain/references/clinical/clinical.go b/internal/domain/references/clinical/clinical.go new file mode 100644 index 00000000..13e95581 --- /dev/null +++ b/internal/domain/references/clinical/clinical.go @@ -0,0 +1,12 @@ +package clinical + +type ( + CheckupScopeCode string +) + +const ( + CSCLab CheckupScopeCode = "lab" // Laboratorium + CSCMLab CheckupScopeCode = "mic-lab" // Microbacterial Laboratorium + CSCPLab CheckupScopeCode = "pa-lab" // Patology Anatomy Laboratorium + CSCRad CheckupScopeCode = "radiology" // Radiology +) diff --git a/internal/domain/references/common/common.go b/internal/domain/references/common/common.go index dfd44baf..7f6fed2b 100644 --- a/internal/domain/references/common/common.go +++ b/internal/domain/references/common/common.go @@ -1,13 +1,12 @@ package common type ( - YaTidakCode byte - SudahBelumCode byte - AktifSimpelCode byte - AktifAdvanceCode byte - TersediaCode byte - StatusCode string - EmployeePosisitionCode string + YaTidakCode byte + SudahBelumCode byte + AktifSimpelCode byte + AktifAdvanceCode byte + TersediaCode byte + StatusCode string ) const ( @@ -42,14 +41,3 @@ const ( SCBlocked StatusCode = "blocked" SCSuspended StatusCode = "suspended" ) - -const ( - EPCDoc EmployeePosisitionCode = "doctor" - EPCNur EmployeePosisitionCode = "nurse" - EPCNut EmployeePosisitionCode = "nutritionist" - EPCLab EmployeePosisitionCode = "laborant" - EPCPha EmployeePosisitionCode = "pharmacy" - EPCPay EmployeePosisitionCode = "payment" - EPCPav EmployeePosisitionCode = "payment-verificator" - EPCMan EmployeePosisitionCode = "management" -) diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index f8c7879e..bad128d6 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -1,46 +1,16 @@ package organization type ( - PositionCode string - QueuePositionCode string + EmployeePosisitionCode string ) const ( - PosReg PositionCode = "reg" - PosDoctor PositionCode = "doc" - PosNurse PositionCode = "nur" // DEPRECATED - PosAmbulatory PositionCode = "amb" // rawat jalan - PosEmergency PositionCode = "emg" // gawat darurat - PosNEC PositionCode = "eon" // ponek, cEONc - PosInpatient PositionCode = "inp" // rawat inap - PosICU PositionCode = "icu" - PosVK PositionCode = "vlk" - PosNeonatus PositionCode = "neo" - PosMidwife PositionCode = "mwf" - PosNutrition PositionCode = "nut" - PosAnesthesia PositionCode = "ans" - PosSurgery PositionCode = "sur" - - PosPharmacy PositionCode = "pha" - PosRadiology PositionCode = "rad" - PosLab PositionCode = "lab" - PosFinance PositionCode = "fin" - PosHRD PositionCode = "hrd" - PosOperator PositionCode = "opr" - PosAdmin PositionCode = "adm" - PosSystem PositionCode = "sys" -) - -const ( - CQPCRegistration QueuePositionCode = "reg" - CQPCPayment QueuePositionCode = "pay" - CQPCExamination QueuePositionCode = "exa" - CQPCMedicine QueuePositionCode = "med" - CQPCProcedure QueuePositionCode = "pro" - CQPCFinish QueuePositionCode = "fin" - CQPCRegSkip QueuePositionCode = "reg-ski" - CQPCPaySkip QueuePositionCode = "pay-ski" - CQPCExaSkip QueuePositionCode = "exa-ski" - CQPCMedSkip QueuePositionCode = "med-ski" - CQPCReschedule QueuePositionCode = "rse" + EPCDoc EmployeePosisitionCode = "doctor" + EPCNur EmployeePosisitionCode = "nurse" + EPCNut EmployeePosisitionCode = "nutritionist" + EPCLab EmployeePosisitionCode = "laborant" + EPCPha EmployeePosisitionCode = "pharmacy" + EPCPay EmployeePosisitionCode = "payment" + EPCPav EmployeePosisitionCode = "payment-verificator" + EPCMan EmployeePosisitionCode = "management" ) diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 3acc76cd..ed6692b2 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -12,9 +12,16 @@ import ( divisionposition "simrs-vx/internal/domain/main-entities/division-position" doctor "simrs-vx/internal/domain/main-entities/doctor" employee "simrs-vx/internal/domain/main-entities/employee" + infra "simrs-vx/internal/domain/main-entities/infra" infragroup "simrs-vx/internal/domain/main-entities/infra-group" installation "simrs-vx/internal/domain/main-entities/installation" + item "simrs-vx/internal/domain/main-entities/item" itemgroup "simrs-vx/internal/domain/main-entities/item-group" + itemprice "simrs-vx/internal/domain/main-entities/item-price" + mcusrc "simrs-vx/internal/domain/main-entities/mcu-src" + mcusrccategory "simrs-vx/internal/domain/main-entities/mcu-src-category" + medicinegroup "simrs-vx/internal/domain/main-entities/medicine-group" + medicinemethod "simrs-vx/internal/domain/main-entities/medicine-method" nurse "simrs-vx/internal/domain/main-entities/nurse" nutritionist "simrs-vx/internal/domain/main-entities/nutritionist" person "simrs-vx/internal/domain/main-entities/person" @@ -27,6 +34,7 @@ import ( province "simrs-vx/internal/domain/main-entities/province" regency "simrs-vx/internal/domain/main-entities/regency" unit "simrs-vx/internal/domain/main-entities/unit" + uom "simrs-vx/internal/domain/main-entities/uom" user "simrs-vx/internal/domain/main-entities/user" village "simrs-vx/internal/domain/main-entities/village" @@ -87,6 +95,14 @@ func GetEntities() []any { &pharmacist.Pharmacist{}, &counter.Counter{}, &practiceschedule.PracticeSchedule{}, + &uom.Uom{}, + &item.Item{}, + &itemprice.ItemPrice{}, + &infra.Infra{}, + &medicinegroup.MedicineGroup{}, + &medicinemethod.MedicineMethod{}, + &mcusrccategory.McuSrcCategory{}, + &mcusrc.McuSrc{}, } } From f1e528b20ead6249bd13708d3385d418fbfe728c Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 15:22:17 +0700 Subject: [PATCH 29/40] add crud for uom, item, itemprice, infra, medicinegroup, medicinemethod, mcusrccategory, mcusrc --- .../interface/main-handler/infra/handler.go | 71 +++++ .../main-handler/item-price/handler.go | 71 +++++ .../interface/main-handler/item/handler.go | 71 +++++ .../interface/main-handler/main-handler.go | 16 + .../main-handler/mcu-src-category/handler.go | 71 +++++ .../interface/main-handler/mcu-src/handler.go | 71 +++++ .../main-handler/medicine-group/handler.go | 71 +++++ .../main-handler/medicine-method/handler.go | 71 +++++ .../interface/main-handler/uom/handler.go | 71 +++++ internal/use-case/main-use-case/infra/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/infra/helper.go | 25 ++ internal/use-case/main-use-case/infra/lib.go | 149 ++++++++++ .../main-use-case/infra/middleware-runner.go | 103 +++++++ .../main-use-case/infra/middleware.go | 9 + .../use-case/main-use-case/infra/tycovar.go | 44 +++ .../use-case/main-use-case/item-price/case.go | 275 ++++++++++++++++++ .../main-use-case/item-price/helper.go | 22 ++ .../use-case/main-use-case/item-price/lib.go | 149 ++++++++++ .../item-price/middleware-runner.go | 103 +++++++ .../main-use-case/item-price/middleware.go | 9 + .../main-use-case/item-price/tycovar.go | 44 +++ internal/use-case/main-use-case/item/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/item/helper.go | 26 ++ internal/use-case/main-use-case/item/lib.go | 149 ++++++++++ .../main-use-case/item/middleware-runner.go | 103 +++++++ .../use-case/main-use-case/item/middleware.go | 9 + .../use-case/main-use-case/item/tycovar.go | 44 +++ .../main-use-case/mcu-src-category/case.go | 275 ++++++++++++++++++ .../main-use-case/mcu-src-category/helper.go | 23 ++ .../main-use-case/mcu-src-category/lib.go | 149 ++++++++++ .../mcu-src-category/middleware-runner.go | 103 +++++++ .../mcu-src-category/middleware.go | 9 + .../main-use-case/mcu-src-category/tycovar.go | 44 +++ .../use-case/main-use-case/mcu-src/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/mcu-src/helper.go | 23 ++ .../use-case/main-use-case/mcu-src/lib.go | 149 ++++++++++ .../mcu-src/middleware-runner.go | 103 +++++++ .../main-use-case/mcu-src/middleware.go | 9 + .../use-case/main-use-case/mcu-src/tycovar.go | 44 +++ .../main-use-case/medicine-group/case.go | 275 ++++++++++++++++++ .../main-use-case/medicine-group/helper.go | 22 ++ .../main-use-case/medicine-group/lib.go | 149 ++++++++++ .../medicine-group/middleware-runner.go | 103 +++++++ .../medicine-group/middleware.go | 9 + .../main-use-case/medicine-group/tycovar.go | 44 +++ .../main-use-case/medicine-method/case.go | 275 ++++++++++++++++++ .../main-use-case/medicine-method/helper.go | 22 ++ .../main-use-case/medicine-method/lib.go | 149 ++++++++++ .../medicine-method/middleware-runner.go | 103 +++++++ .../medicine-method/middleware.go | 9 + .../main-use-case/medicine-method/tycovar.go | 44 +++ internal/use-case/main-use-case/uom/case.go | 275 ++++++++++++++++++ internal/use-case/main-use-case/uom/helper.go | 22 ++ internal/use-case/main-use-case/uom/lib.go | 149 ++++++++++ .../main-use-case/uom/middleware-runner.go | 103 +++++++ .../use-case/main-use-case/uom/middleware.go | 9 + .../use-case/main-use-case/uom/tycovar.go | 44 +++ 57 files changed, 5409 insertions(+) create mode 100644 internal/interface/main-handler/infra/handler.go create mode 100644 internal/interface/main-handler/item-price/handler.go create mode 100644 internal/interface/main-handler/item/handler.go create mode 100644 internal/interface/main-handler/mcu-src-category/handler.go create mode 100644 internal/interface/main-handler/mcu-src/handler.go create mode 100644 internal/interface/main-handler/medicine-group/handler.go create mode 100644 internal/interface/main-handler/medicine-method/handler.go create mode 100644 internal/interface/main-handler/uom/handler.go create mode 100644 internal/use-case/main-use-case/infra/case.go create mode 100644 internal/use-case/main-use-case/infra/helper.go create mode 100644 internal/use-case/main-use-case/infra/lib.go create mode 100644 internal/use-case/main-use-case/infra/middleware-runner.go create mode 100644 internal/use-case/main-use-case/infra/middleware.go create mode 100644 internal/use-case/main-use-case/infra/tycovar.go create mode 100644 internal/use-case/main-use-case/item-price/case.go create mode 100644 internal/use-case/main-use-case/item-price/helper.go create mode 100644 internal/use-case/main-use-case/item-price/lib.go create mode 100644 internal/use-case/main-use-case/item-price/middleware-runner.go create mode 100644 internal/use-case/main-use-case/item-price/middleware.go create mode 100644 internal/use-case/main-use-case/item-price/tycovar.go create mode 100644 internal/use-case/main-use-case/item/case.go create mode 100644 internal/use-case/main-use-case/item/helper.go create mode 100644 internal/use-case/main-use-case/item/lib.go create mode 100644 internal/use-case/main-use-case/item/middleware-runner.go create mode 100644 internal/use-case/main-use-case/item/middleware.go create mode 100644 internal/use-case/main-use-case/item/tycovar.go create mode 100644 internal/use-case/main-use-case/mcu-src-category/case.go create mode 100644 internal/use-case/main-use-case/mcu-src-category/helper.go create mode 100644 internal/use-case/main-use-case/mcu-src-category/lib.go create mode 100644 internal/use-case/main-use-case/mcu-src-category/middleware-runner.go create mode 100644 internal/use-case/main-use-case/mcu-src-category/middleware.go create mode 100644 internal/use-case/main-use-case/mcu-src-category/tycovar.go create mode 100644 internal/use-case/main-use-case/mcu-src/case.go create mode 100644 internal/use-case/main-use-case/mcu-src/helper.go create mode 100644 internal/use-case/main-use-case/mcu-src/lib.go create mode 100644 internal/use-case/main-use-case/mcu-src/middleware-runner.go create mode 100644 internal/use-case/main-use-case/mcu-src/middleware.go create mode 100644 internal/use-case/main-use-case/mcu-src/tycovar.go create mode 100644 internal/use-case/main-use-case/medicine-group/case.go create mode 100644 internal/use-case/main-use-case/medicine-group/helper.go create mode 100644 internal/use-case/main-use-case/medicine-group/lib.go create mode 100644 internal/use-case/main-use-case/medicine-group/middleware-runner.go create mode 100644 internal/use-case/main-use-case/medicine-group/middleware.go create mode 100644 internal/use-case/main-use-case/medicine-group/tycovar.go create mode 100644 internal/use-case/main-use-case/medicine-method/case.go create mode 100644 internal/use-case/main-use-case/medicine-method/helper.go create mode 100644 internal/use-case/main-use-case/medicine-method/lib.go create mode 100644 internal/use-case/main-use-case/medicine-method/middleware-runner.go create mode 100644 internal/use-case/main-use-case/medicine-method/middleware.go create mode 100644 internal/use-case/main-use-case/medicine-method/tycovar.go create mode 100644 internal/use-case/main-use-case/uom/case.go create mode 100644 internal/use-case/main-use-case/uom/helper.go create mode 100644 internal/use-case/main-use-case/uom/lib.go create mode 100644 internal/use-case/main-use-case/uom/middleware-runner.go create mode 100644 internal/use-case/main-use-case/uom/middleware.go create mode 100644 internal/use-case/main-use-case/uom/tycovar.go diff --git a/internal/interface/main-handler/infra/handler.go b/internal/interface/main-handler/infra/handler.go new file mode 100644 index 00000000..71a8f1ec --- /dev/null +++ b/internal/interface/main-handler/infra/handler.go @@ -0,0 +1,71 @@ +package infra + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/infra" + u "simrs-vx/internal/use-case/main-use-case/infra" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/item-price/handler.go b/internal/interface/main-handler/item-price/handler.go new file mode 100644 index 00000000..59586aac --- /dev/null +++ b/internal/interface/main-handler/item-price/handler.go @@ -0,0 +1,71 @@ +package itemprice + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/item-price" + u "simrs-vx/internal/use-case/main-use-case/item-price" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/item/handler.go b/internal/interface/main-handler/item/handler.go new file mode 100644 index 00000000..124be7ef --- /dev/null +++ b/internal/interface/main-handler/item/handler.go @@ -0,0 +1,71 @@ +package item + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/item" + u "simrs-vx/internal/use-case/main-use-case/item" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index acbd4b61..4fbc704f 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -38,12 +38,20 @@ import ( diagnosesrc "simrs-vx/internal/interface/main-handler/diagnose-src" division "simrs-vx/internal/interface/main-handler/division" divisionposition "simrs-vx/internal/interface/main-handler/division-position" + infra "simrs-vx/internal/interface/main-handler/infra" infragroup "simrs-vx/internal/interface/main-handler/infra-group" installation "simrs-vx/internal/interface/main-handler/installation" + item "simrs-vx/internal/interface/main-handler/item" itemgroup "simrs-vx/internal/interface/main-handler/item-group" + itemprice "simrs-vx/internal/interface/main-handler/item-price" + mcusrc "simrs-vx/internal/interface/main-handler/mcu-src" + mcusrccategory "simrs-vx/internal/interface/main-handler/mcu-src-category" + medicinegroup "simrs-vx/internal/interface/main-handler/medicine-group" + medicinemethod "simrs-vx/internal/interface/main-handler/medicine-method" pharmacycompany "simrs-vx/internal/interface/main-handler/pharmacy-company" proceduresrc "simrs-vx/internal/interface/main-handler/procedure-src" unit "simrs-vx/internal/interface/main-handler/unit" + uom "simrs-vx/internal/interface/main-handler/uom" district "simrs-vx/internal/interface/main-handler/district" province "simrs-vx/internal/interface/main-handler/province" @@ -102,6 +110,14 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/procedure-src", proceduresrc.O) hc.RegCrud(r, "/v1/infra-group", infragroup.O) hc.RegCrud(r, "/v1/item-group", itemgroup.O) + hc.RegCrud(r, "/v1/uom", uom.O) + hc.RegCrud(r, "/v1/item", item.O) + hc.RegCrud(r, "/v1/item-price", itemprice.O) + hc.RegCrud(r, "/v1/infra", infra.O) + hc.RegCrud(r, "/v1/medicine-group", medicinegroup.O) + hc.RegCrud(r, "/v1/medicine-method", medicinemethod.O) + hc.RegCrud(r, "/v1/mcu-src-category", mcusrccategory.O) + hc.RegCrud(r, "/v1/mcu-src", mcusrc.O) hc.RegCrud(r, "/v1/village", village.O) hc.RegCrud(r, "/v1/district", district.O) diff --git a/internal/interface/main-handler/mcu-src-category/handler.go b/internal/interface/main-handler/mcu-src-category/handler.go new file mode 100644 index 00000000..7dde9c66 --- /dev/null +++ b/internal/interface/main-handler/mcu-src-category/handler.go @@ -0,0 +1,71 @@ +package mcusrccategory + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/mcu-src-category" + u "simrs-vx/internal/use-case/main-use-case/mcu-src-category" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/mcu-src/handler.go b/internal/interface/main-handler/mcu-src/handler.go new file mode 100644 index 00000000..c607017d --- /dev/null +++ b/internal/interface/main-handler/mcu-src/handler.go @@ -0,0 +1,71 @@ +package mcusrc + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/mcu-src" + u "simrs-vx/internal/use-case/main-use-case/mcu-src" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/medicine-group/handler.go b/internal/interface/main-handler/medicine-group/handler.go new file mode 100644 index 00000000..26818135 --- /dev/null +++ b/internal/interface/main-handler/medicine-group/handler.go @@ -0,0 +1,71 @@ +package medicinegroup + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/medicine-group" + u "simrs-vx/internal/use-case/main-use-case/medicine-group" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/medicine-method/handler.go b/internal/interface/main-handler/medicine-method/handler.go new file mode 100644 index 00000000..cab79d7c --- /dev/null +++ b/internal/interface/main-handler/medicine-method/handler.go @@ -0,0 +1,71 @@ +package medicinemethod + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/medicine-method" + u "simrs-vx/internal/use-case/main-use-case/medicine-method" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/uom/handler.go b/internal/interface/main-handler/uom/handler.go new file mode 100644 index 00000000..b75a4ae0 --- /dev/null +++ b/internal/interface/main-handler/uom/handler.go @@ -0,0 +1,71 @@ +package uom + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/uom" + u "simrs-vx/internal/use-case/main-use-case/uom" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/main-use-case/infra/case.go b/internal/use-case/main-use-case/infra/case.go new file mode 100644 index 00000000..afa0ec6a --- /dev/null +++ b/internal/use-case/main-use-case/infra/case.go @@ -0,0 +1,275 @@ +package infra + +import ( + e "simrs-vx/internal/domain/main-entities/infra" + "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" +) + +const source = "infra" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Infra{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Infra + var dataList []e.Infra + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Infra + 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.Infra + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Infra + 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 + +} diff --git a/internal/use-case/main-use-case/infra/helper.go b/internal/use-case/main-use-case/infra/helper.go new file mode 100644 index 00000000..93730033 --- /dev/null +++ b/internal/use-case/main-use-case/infra/helper.go @@ -0,0 +1,25 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package infra + +import ( + e "simrs-vx/internal/domain/main-entities/infra" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Infra) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.InfraGroup_Code = inputSrc.InfraGroup_Code + data.Parent_Id = inputSrc.Parent_Id + data.Item_Id = inputSrc.Item_Id +} diff --git a/internal/use-case/main-use-case/infra/lib.go b/internal/use-case/main-use-case/infra/lib.go new file mode 100644 index 00000000..23c745db --- /dev/null +++ b/internal/use-case/main-use-case/infra/lib.go @@ -0,0 +1,149 @@ +package infra + +import ( + e "simrs-vx/internal/domain/main-entities/infra" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Infra, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Infra{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Infra, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Infra{} + 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.Infra{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Infra, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Infra{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Infra, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Infra, 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 +} diff --git a/internal/use-case/main-use-case/infra/middleware-runner.go b/internal/use-case/main-use-case/infra/middleware-runner.go new file mode 100644 index 00000000..eed26dcf --- /dev/null +++ b/internal/use-case/main-use-case/infra/middleware-runner.go @@ -0,0 +1,103 @@ +package infra + +import ( + e "simrs-vx/internal/domain/main-entities/infra" + 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.Infra) 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.Infra) 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.Infra) 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.Infra) 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.Infra) 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 +} diff --git a/internal/use-case/main-use-case/infra/middleware.go b/internal/use-case/main-use-case/infra/middleware.go new file mode 100644 index 00000000..9e98b5fa --- /dev/null +++ b/internal/use-case/main-use-case/infra/middleware.go @@ -0,0 +1,9 @@ +package infra + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/infra/tycovar.go b/internal/use-case/main-use-case/infra/tycovar.go new file mode 100644 index 00000000..fe5cdf4d --- /dev/null +++ b/internal/use-case/main-use-case/infra/tycovar.go @@ -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 infra + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/infra" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Infra, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Infra, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Infra, 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 diff --git a/internal/use-case/main-use-case/item-price/case.go b/internal/use-case/main-use-case/item-price/case.go new file mode 100644 index 00000000..6566f6e8 --- /dev/null +++ b/internal/use-case/main-use-case/item-price/case.go @@ -0,0 +1,275 @@ +package itemprice + +import ( + e "simrs-vx/internal/domain/main-entities/item-price" + "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" +) + +const source = "item-price" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.ItemPrice{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.ItemPrice + var dataList []e.ItemPrice + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ItemPrice + 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: uint16(input.Id)} + var data *e.ItemPrice + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.ItemPrice + 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 + +} diff --git a/internal/use-case/main-use-case/item-price/helper.go b/internal/use-case/main-use-case/item-price/helper.go new file mode 100644 index 00000000..eb839c19 --- /dev/null +++ b/internal/use-case/main-use-case/item-price/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package itemprice + +import ( + e "simrs-vx/internal/domain/main-entities/item-price" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ItemPrice) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Item_Id = inputSrc.Item_Id + data.Price = inputSrc.Price +} diff --git a/internal/use-case/main-use-case/item-price/lib.go b/internal/use-case/main-use-case/item-price/lib.go new file mode 100644 index 00000000..924752f0 --- /dev/null +++ b/internal/use-case/main-use-case/item-price/lib.go @@ -0,0 +1,149 @@ +package itemprice + +import ( + e "simrs-vx/internal/domain/main-entities/item-price" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.ItemPrice, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.ItemPrice{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ItemPrice, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ItemPrice{} + 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.ItemPrice{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.ItemPrice, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ItemPrice{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.ItemPrice, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.ItemPrice, 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 +} diff --git a/internal/use-case/main-use-case/item-price/middleware-runner.go b/internal/use-case/main-use-case/item-price/middleware-runner.go new file mode 100644 index 00000000..d3d07a29 --- /dev/null +++ b/internal/use-case/main-use-case/item-price/middleware-runner.go @@ -0,0 +1,103 @@ +package itemprice + +import ( + e "simrs-vx/internal/domain/main-entities/item-price" + 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.ItemPrice) 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.ItemPrice) 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.ItemPrice) 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.ItemPrice) 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.ItemPrice) 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 +} diff --git a/internal/use-case/main-use-case/item-price/middleware.go b/internal/use-case/main-use-case/item-price/middleware.go new file mode 100644 index 00000000..55f41515 --- /dev/null +++ b/internal/use-case/main-use-case/item-price/middleware.go @@ -0,0 +1,9 @@ +package itemprice + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/item-price/tycovar.go b/internal/use-case/main-use-case/item-price/tycovar.go new file mode 100644 index 00000000..fc949511 --- /dev/null +++ b/internal/use-case/main-use-case/item-price/tycovar.go @@ -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 itemprice + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/item-price" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ItemPrice, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ItemPrice, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ItemPrice, 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 diff --git a/internal/use-case/main-use-case/item/case.go b/internal/use-case/main-use-case/item/case.go new file mode 100644 index 00000000..77ca4d89 --- /dev/null +++ b/internal/use-case/main-use-case/item/case.go @@ -0,0 +1,275 @@ +package item + +import ( + e "simrs-vx/internal/domain/main-entities/item" + "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" +) + +const source = "item" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Item{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Item + var dataList []e.Item + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Item + 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: uint16(input.Id)} + var data *e.Item + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Item + 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 + +} diff --git a/internal/use-case/main-use-case/item/helper.go b/internal/use-case/main-use-case/item/helper.go new file mode 100644 index 00000000..0ebfcd37 --- /dev/null +++ b/internal/use-case/main-use-case/item/helper.go @@ -0,0 +1,26 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package item + +import ( + e "simrs-vx/internal/domain/main-entities/item" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Item) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.ItemGroup_Code = inputSrc.ItemGroup_Code + data.Uom_Code = inputSrc.Uom_Code + data.Infra_Id = inputSrc.Infra_Id + data.Stock = inputSrc.Stock +} diff --git a/internal/use-case/main-use-case/item/lib.go b/internal/use-case/main-use-case/item/lib.go new file mode 100644 index 00000000..a65f2da9 --- /dev/null +++ b/internal/use-case/main-use-case/item/lib.go @@ -0,0 +1,149 @@ +package item + +import ( + e "simrs-vx/internal/domain/main-entities/item" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Item, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Item{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Item, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Item{} + 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.Item{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Item, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Item{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Item, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Item, 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 +} diff --git a/internal/use-case/main-use-case/item/middleware-runner.go b/internal/use-case/main-use-case/item/middleware-runner.go new file mode 100644 index 00000000..391fa226 --- /dev/null +++ b/internal/use-case/main-use-case/item/middleware-runner.go @@ -0,0 +1,103 @@ +package item + +import ( + e "simrs-vx/internal/domain/main-entities/item" + 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.Item) 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.Item) 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.Item) 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.Item) 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.Item) 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 +} diff --git a/internal/use-case/main-use-case/item/middleware.go b/internal/use-case/main-use-case/item/middleware.go new file mode 100644 index 00000000..ab8ddb1a --- /dev/null +++ b/internal/use-case/main-use-case/item/middleware.go @@ -0,0 +1,9 @@ +package item + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/item/tycovar.go b/internal/use-case/main-use-case/item/tycovar.go new file mode 100644 index 00000000..8389810a --- /dev/null +++ b/internal/use-case/main-use-case/item/tycovar.go @@ -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 item + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/item" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Item, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Item, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Item, 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 diff --git a/internal/use-case/main-use-case/mcu-src-category/case.go b/internal/use-case/main-use-case/mcu-src-category/case.go new file mode 100644 index 00000000..004d97f2 --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src-category/case.go @@ -0,0 +1,275 @@ +package mcusrccategory + +import ( + e "simrs-vx/internal/domain/main-entities/mcu-src-category" + "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" +) + +const source = "mcu-src-category" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.McuSrcCategory{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.McuSrcCategory + var dataList []e.McuSrcCategory + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.McuSrcCategory + 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.McuSrcCategory + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.McuSrcCategory + 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 + +} diff --git a/internal/use-case/main-use-case/mcu-src-category/helper.go b/internal/use-case/main-use-case/mcu-src-category/helper.go new file mode 100644 index 00000000..f733012a --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src-category/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package mcusrccategory + +import ( + e "simrs-vx/internal/domain/main-entities/mcu-src-category" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.McuSrcCategory) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Scope_Code = inputSrc.Scope_Code +} diff --git a/internal/use-case/main-use-case/mcu-src-category/lib.go b/internal/use-case/main-use-case/mcu-src-category/lib.go new file mode 100644 index 00000000..d62184d1 --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src-category/lib.go @@ -0,0 +1,149 @@ +package mcusrccategory + +import ( + e "simrs-vx/internal/domain/main-entities/mcu-src-category" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.McuSrcCategory, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.McuSrcCategory{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.McuSrcCategory, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.McuSrcCategory{} + 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.McuSrcCategory{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.McuSrcCategory, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.McuSrcCategory{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.McuSrcCategory, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.McuSrcCategory, 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 +} diff --git a/internal/use-case/main-use-case/mcu-src-category/middleware-runner.go b/internal/use-case/main-use-case/mcu-src-category/middleware-runner.go new file mode 100644 index 00000000..8d0bd0c1 --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src-category/middleware-runner.go @@ -0,0 +1,103 @@ +package mcusrccategory + +import ( + e "simrs-vx/internal/domain/main-entities/mcu-src-category" + 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.McuSrcCategory) 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.McuSrcCategory) 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.McuSrcCategory) 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.McuSrcCategory) 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.McuSrcCategory) 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 +} diff --git a/internal/use-case/main-use-case/mcu-src-category/middleware.go b/internal/use-case/main-use-case/mcu-src-category/middleware.go new file mode 100644 index 00000000..283c79f7 --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src-category/middleware.go @@ -0,0 +1,9 @@ +package mcusrccategory + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/mcu-src-category/tycovar.go b/internal/use-case/main-use-case/mcu-src-category/tycovar.go new file mode 100644 index 00000000..d33a6d09 --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src-category/tycovar.go @@ -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 mcusrccategory + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/mcu-src-category" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.McuSrcCategory, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.McuSrcCategory, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.McuSrcCategory, 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 diff --git a/internal/use-case/main-use-case/mcu-src/case.go b/internal/use-case/main-use-case/mcu-src/case.go new file mode 100644 index 00000000..3dc69a7c --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src/case.go @@ -0,0 +1,275 @@ +package mcusrc + +import ( + e "simrs-vx/internal/domain/main-entities/mcu-src" + "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" +) + +const source = "mcu-src" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.McuSrc{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.McuSrc + var dataList []e.McuSrc + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.McuSrc + 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.McuSrc + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.McuSrc + 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 + +} diff --git a/internal/use-case/main-use-case/mcu-src/helper.go b/internal/use-case/main-use-case/mcu-src/helper.go new file mode 100644 index 00000000..820dbfa7 --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package mcusrc + +import ( + e "simrs-vx/internal/domain/main-entities/mcu-src" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.McuSrc) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.CheckupCategory_Code = inputSrc.CheckupCategory_Code +} diff --git a/internal/use-case/main-use-case/mcu-src/lib.go b/internal/use-case/main-use-case/mcu-src/lib.go new file mode 100644 index 00000000..023d334e --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src/lib.go @@ -0,0 +1,149 @@ +package mcusrc + +import ( + e "simrs-vx/internal/domain/main-entities/mcu-src" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.McuSrc, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.McuSrc{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.McuSrc, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.McuSrc{} + 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.McuSrc{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.McuSrc, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.McuSrc{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.McuSrc, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.McuSrc, 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 +} diff --git a/internal/use-case/main-use-case/mcu-src/middleware-runner.go b/internal/use-case/main-use-case/mcu-src/middleware-runner.go new file mode 100644 index 00000000..3ced4533 --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src/middleware-runner.go @@ -0,0 +1,103 @@ +package mcusrc + +import ( + e "simrs-vx/internal/domain/main-entities/mcu-src" + 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.McuSrc) 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.McuSrc) 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.McuSrc) 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.McuSrc) 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.McuSrc) 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 +} diff --git a/internal/use-case/main-use-case/mcu-src/middleware.go b/internal/use-case/main-use-case/mcu-src/middleware.go new file mode 100644 index 00000000..a8eacf9f --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src/middleware.go @@ -0,0 +1,9 @@ +package mcusrc + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/mcu-src/tycovar.go b/internal/use-case/main-use-case/mcu-src/tycovar.go new file mode 100644 index 00000000..14a9a881 --- /dev/null +++ b/internal/use-case/main-use-case/mcu-src/tycovar.go @@ -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 mcusrc + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/mcu-src" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.McuSrc, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.McuSrc, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.McuSrc, 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 diff --git a/internal/use-case/main-use-case/medicine-group/case.go b/internal/use-case/main-use-case/medicine-group/case.go new file mode 100644 index 00000000..66fe35b8 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-group/case.go @@ -0,0 +1,275 @@ +package medicinegroup + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-group" + "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" +) + +const source = "medicine-group" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.MedicineGroup{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.MedicineGroup + var dataList []e.MedicineGroup + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.MedicineGroup + 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: uint16(input.Id)} + var data *e.MedicineGroup + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.MedicineGroup + 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 + +} diff --git a/internal/use-case/main-use-case/medicine-group/helper.go b/internal/use-case/main-use-case/medicine-group/helper.go new file mode 100644 index 00000000..7b98cf36 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-group/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package medicinegroup + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-group" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicineGroup) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/medicine-group/lib.go b/internal/use-case/main-use-case/medicine-group/lib.go new file mode 100644 index 00000000..6388544c --- /dev/null +++ b/internal/use-case/main-use-case/medicine-group/lib.go @@ -0,0 +1,149 @@ +package medicinegroup + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-group" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.MedicineGroup, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.MedicineGroup{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.MedicineGroup, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.MedicineGroup{} + 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.MedicineGroup{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.MedicineGroup, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.MedicineGroup{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.MedicineGroup, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.MedicineGroup, 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 +} diff --git a/internal/use-case/main-use-case/medicine-group/middleware-runner.go b/internal/use-case/main-use-case/medicine-group/middleware-runner.go new file mode 100644 index 00000000..c74a8d96 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-group/middleware-runner.go @@ -0,0 +1,103 @@ +package medicinegroup + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-group" + 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.MedicineGroup) 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.MedicineGroup) 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.MedicineGroup) 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.MedicineGroup) 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.MedicineGroup) 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 +} diff --git a/internal/use-case/main-use-case/medicine-group/middleware.go b/internal/use-case/main-use-case/medicine-group/middleware.go new file mode 100644 index 00000000..5ec73b36 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-group/middleware.go @@ -0,0 +1,9 @@ +package medicinegroup + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/medicine-group/tycovar.go b/internal/use-case/main-use-case/medicine-group/tycovar.go new file mode 100644 index 00000000..cc80e651 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-group/tycovar.go @@ -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 medicinegroup + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/medicine-group" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.MedicineGroup, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.MedicineGroup, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.MedicineGroup, 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 diff --git a/internal/use-case/main-use-case/medicine-method/case.go b/internal/use-case/main-use-case/medicine-method/case.go new file mode 100644 index 00000000..2a672f80 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-method/case.go @@ -0,0 +1,275 @@ +package medicinemethod + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-method" + "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" +) + +const source = "medicine-method" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.MedicineMethod{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.MedicineMethod + var dataList []e.MedicineMethod + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.MedicineMethod + 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.MedicineMethod + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.MedicineMethod + 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 + +} diff --git a/internal/use-case/main-use-case/medicine-method/helper.go b/internal/use-case/main-use-case/medicine-method/helper.go new file mode 100644 index 00000000..d9142ae1 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-method/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package medicinemethod + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-method" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicineMethod) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/medicine-method/lib.go b/internal/use-case/main-use-case/medicine-method/lib.go new file mode 100644 index 00000000..8e11d043 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-method/lib.go @@ -0,0 +1,149 @@ +package medicinemethod + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-method" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.MedicineMethod, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.MedicineMethod{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.MedicineMethod, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.MedicineMethod{} + 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.MedicineMethod{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.MedicineMethod, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.MedicineMethod{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.MedicineMethod, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.MedicineMethod, 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 +} diff --git a/internal/use-case/main-use-case/medicine-method/middleware-runner.go b/internal/use-case/main-use-case/medicine-method/middleware-runner.go new file mode 100644 index 00000000..190792d1 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-method/middleware-runner.go @@ -0,0 +1,103 @@ +package medicinemethod + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-method" + 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.MedicineMethod) 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.MedicineMethod) 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.MedicineMethod) 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.MedicineMethod) 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.MedicineMethod) 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 +} diff --git a/internal/use-case/main-use-case/medicine-method/middleware.go b/internal/use-case/main-use-case/medicine-method/middleware.go new file mode 100644 index 00000000..9ab96971 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-method/middleware.go @@ -0,0 +1,9 @@ +package medicinemethod + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/medicine-method/tycovar.go b/internal/use-case/main-use-case/medicine-method/tycovar.go new file mode 100644 index 00000000..452b069f --- /dev/null +++ b/internal/use-case/main-use-case/medicine-method/tycovar.go @@ -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 medicinemethod + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/medicine-method" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.MedicineMethod, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.MedicineMethod, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.MedicineMethod, 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 diff --git a/internal/use-case/main-use-case/uom/case.go b/internal/use-case/main-use-case/uom/case.go new file mode 100644 index 00000000..786d4b7e --- /dev/null +++ b/internal/use-case/main-use-case/uom/case.go @@ -0,0 +1,275 @@ +package uom + +import ( + e "simrs-vx/internal/domain/main-entities/uom" + "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" +) + +const source = "uom" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Uom{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Uom + var dataList []e.Uom + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Uom + 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.Uom + 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) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Uom + 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 + +} diff --git a/internal/use-case/main-use-case/uom/helper.go b/internal/use-case/main-use-case/uom/helper.go new file mode 100644 index 00000000..ea0b875c --- /dev/null +++ b/internal/use-case/main-use-case/uom/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package uom + +import ( + e "simrs-vx/internal/domain/main-entities/uom" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Uom) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/uom/lib.go b/internal/use-case/main-use-case/uom/lib.go new file mode 100644 index 00000000..655be4cd --- /dev/null +++ b/internal/use-case/main-use-case/uom/lib.go @@ -0,0 +1,149 @@ +package uom + +import ( + e "simrs-vx/internal/domain/main-entities/uom" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Uom, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Uom{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Uom, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Uom{} + 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.Uom{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Uom, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Uom{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Uom, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Uom, 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 +} diff --git a/internal/use-case/main-use-case/uom/middleware-runner.go b/internal/use-case/main-use-case/uom/middleware-runner.go new file mode 100644 index 00000000..cffa1b0c --- /dev/null +++ b/internal/use-case/main-use-case/uom/middleware-runner.go @@ -0,0 +1,103 @@ +package uom + +import ( + e "simrs-vx/internal/domain/main-entities/uom" + 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.Uom) 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.Uom) 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.Uom) 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.Uom) 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.Uom) 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 +} diff --git a/internal/use-case/main-use-case/uom/middleware.go b/internal/use-case/main-use-case/uom/middleware.go new file mode 100644 index 00000000..6ff02598 --- /dev/null +++ b/internal/use-case/main-use-case/uom/middleware.go @@ -0,0 +1,9 @@ +package uom + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/uom/tycovar.go b/internal/use-case/main-use-case/uom/tycovar.go new file mode 100644 index 00000000..a93d2d0e --- /dev/null +++ b/internal/use-case/main-use-case/uom/tycovar.go @@ -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 uom + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/uom" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Uom, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Uom, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Uom, 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 From 03fb2858d160b0bb04819a10bd5ce1425f634bf7 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 15:38:00 +0700 Subject: [PATCH 30/40] add insurancecompany, ethnic, alter person --- cmd/migration/migrations/20250827083322.sql | 28 +++++++ cmd/migration/migrations/atlas.sum | 5 +- internal/domain/main-entities/ethnic/dto.go | 63 +++++++++++++++ .../domain/main-entities/ethnic/entity.go | 11 +++ .../main-entities/insurance-company/dto.go | 81 +++++++++++++++++++ .../main-entities/insurance-company/entity.go | 16 ++++ internal/domain/main-entities/person/dto.go | 9 ++- .../domain/main-entities/person/entity.go | 4 +- internal/domain/references/person/person.go | 1 - internal/interface/migration/migration.go | 4 + 10 files changed, 215 insertions(+), 7 deletions(-) create mode 100644 cmd/migration/migrations/20250827083322.sql create mode 100644 internal/domain/main-entities/ethnic/dto.go create mode 100644 internal/domain/main-entities/ethnic/entity.go create mode 100644 internal/domain/main-entities/insurance-company/dto.go create mode 100644 internal/domain/main-entities/insurance-company/entity.go diff --git a/cmd/migration/migrations/20250827083322.sql b/cmd/migration/migrations/20250827083322.sql new file mode 100644 index 00000000..2ba01491 --- /dev/null +++ b/cmd/migration/migrations/20250827083322.sql @@ -0,0 +1,28 @@ +-- Create "InsuranceCompany" table +CREATE TABLE "public"."InsuranceCompany" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + "Regency_Code" character varying(4) NULL, + "Address" character varying(100) NULL, + "PhoneNumber" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_InsuranceCompany_Code" UNIQUE ("Code"), + CONSTRAINT "fk_InsuranceCompany_Regency" FOREIGN KEY ("Regency_Code") REFERENCES "public"."Regency" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Ethnic" table +CREATE TABLE "public"."Ethnic" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Ethnic_Code" UNIQUE ("Code") +); +-- Modify "Person" table +ALTER TABLE "public"."Person" ALTER COLUMN "Ethnic_Code" TYPE character varying(20), ADD CONSTRAINT "fk_Person_Ethnic" FOREIGN KEY ("Ethnic_Code") REFERENCES "public"."Ethnic" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index 47331906..49745602 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:qhTYEMOwm8TQ+FgXjr/nbT0/T/oRb7pvnXTcQSa/V7w= +h1:yoZN1lVD6dE66V3FtMcVHtoRtFmu18Ltn5/loput+Ns= 20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= 20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= 20250825102900.sql h1:OAUnj87Wz7mrHykX14idePckUmRYa5UH0LylYDL76RI= @@ -6,4 +6,5 @@ h1:qhTYEMOwm8TQ+FgXjr/nbT0/T/oRb7pvnXTcQSa/V7w= 20250827015551.sql h1:Jq/RkXSWHEWuNigLunLzIrYgiyroSVD7J0waDMvdzvg= 20250827021904.sql h1:pgjwmQS1TxZ977a1tIXKq6pZnGauPrOUxLUTclV+fE4= 20250827024311.sql h1:eTlrQYcHa/jmb3qSZxgTB+7S4IXJ8B4yklUB36iZaDw= -20250827072230.sql h1:R5H47ODPcZeINYfzLE+VMQ+l000fLwXe70MQ4BxouGw= +20250827072230.sql h1:BfdTcToEYC8d30BS+1Su5Pz5Ecz8bh74F2j+Bh/r2BM= +20250827083322.sql h1:GhPTHNQGAP13Efly86U7baFFw4l3sz+QV3g3lzeIT9Y= diff --git a/internal/domain/main-entities/ethnic/dto.go b/internal/domain/main-entities/ethnic/dto.go new file mode 100644 index 00000000..64e5ca85 --- /dev/null +++ b/internal/domain/main-entities/ethnic/dto.go @@ -0,0 +1,63 @@ +package ethnic + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` +} + +func (d Ethnic) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []Ethnic) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/ethnic/entity.go b/internal/domain/main-entities/ethnic/entity.go new file mode 100644 index 00000000..5217c2d5 --- /dev/null +++ b/internal/domain/main-entities/ethnic/entity.go @@ -0,0 +1,11 @@ +package ethnic + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type Ethnic struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:20"` + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/domain/main-entities/insurance-company/dto.go b/internal/domain/main-entities/insurance-company/dto.go new file mode 100644 index 00000000..2cc36195 --- /dev/null +++ b/internal/domain/main-entities/insurance-company/dto.go @@ -0,0 +1,81 @@ +package insurancecompany + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + er "simrs-vx/internal/domain/main-entities/regency" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + Regency_Code *string `json:"regency_code"` + Address string `json:"address"` + PhoneNumber string `json:"phoneNumber"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + Regency_Code *string `json:"regency_code"` + Address string `json:"address"` + PhoneNumber string `json:"phoneNumber"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Regency_Code *string `json:"regency_code"` + Address string `json:"address"` + PhoneNumber string `json:"phoneNumber"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + Regency_Code *string `json:"regency_code"` + Regency *er.Regency `json:"regency,omitempty"` + Address string `json:"address"` + PhoneNumber string `json:"phoneNumber"` +} + +func (d InsuranceCompany) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + Regency_Code: d.Regency_Code, + Regency: d.Regency, + Address: d.Address, + PhoneNumber: d.PhoneNumber, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []InsuranceCompany) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/insurance-company/entity.go b/internal/domain/main-entities/insurance-company/entity.go new file mode 100644 index 00000000..79bfe583 --- /dev/null +++ b/internal/domain/main-entities/insurance-company/entity.go @@ -0,0 +1,16 @@ +package insurancecompany + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + er "simrs-vx/internal/domain/main-entities/regency" +) + +type InsuranceCompany struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:20"` + Name string `json:"name" gorm:"size:50"` + Regency_Code *string `json:"regency_code" gorm:"size:4"` + Regency *er.Regency `json:"regency,omitempty" gorm:"foreignKey:Regency_Code;references:Code"` + Address string `json:"address" gorm:"size:100"` + PhoneNumber string `json:"phoneNumber" gorm:"size:20"` +} diff --git a/internal/domain/main-entities/person/dto.go b/internal/domain/main-entities/person/dto.go index dcead8c8..296e23b6 100644 --- a/internal/domain/main-entities/person/dto.go +++ b/internal/domain/main-entities/person/dto.go @@ -2,6 +2,7 @@ package person import ( ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/ethnic" epa "simrs-vx/internal/domain/main-entities/person-address" epc "simrs-vx/internal/domain/main-entities/person-contact" erp "simrs-vx/internal/domain/references/person" @@ -18,7 +19,7 @@ type CreateDto struct { Education_Code *erp.EducationCode `json:"education_code"` Ocupation_Code *erp.OcupationCode `json:"occupation_code"` Ocupation_Name *string `json:"occupation_name"` - Ethnic_Code *erp.EthnicCode `json:"ethnic_code"` + Ethnic_Code *string `json:"ethnic_code"` } type ReadListDto struct { @@ -38,7 +39,7 @@ type ReadDetailDto struct { Education_Code *erp.EducationCode `json:"education_code"` Ocupation_Code *erp.OcupationCode `json:"occupation_code"` Ocupation_Name *string `json:"occupation_name"` - Ethnic_Code *erp.EthnicCode `json:"ethnic_code"` + Ethnic_Code *string `json:"ethnic_code"` } type UpdateDto struct { @@ -67,7 +68,8 @@ type ResponseDto struct { Education_Code *erp.EducationCode `json:"education_code"` Ocupation_Code *erp.OcupationCode `json:"occupation_code"` Ocupation_Name *string `json:"occupation_name"` - Ethnic_Code *erp.EthnicCode `json:"ethnic_code"` + Ethnic_Code *string `json:"ethnic_code"` + Ethnic *ee.Ethnic `json:"ethnic,omitempty"` Addresses *[]epa.PersonAddress `json:"addresses,omitempty"` Contacts *[]epc.PersonContact `json:"contacts,omitempty"` } @@ -84,6 +86,7 @@ func (d *Person) ToResponse() ResponseDto { Ocupation_Code: d.Ocupation_Code, Ocupation_Name: d.Ocupation_Name, Ethnic_Code: d.Ethnic_Code, + Ethnic: d.Ethnic, Addresses: d.Addresses, Contacts: d.Contacts, } diff --git a/internal/domain/main-entities/person/entity.go b/internal/domain/main-entities/person/entity.go index 337b506f..0acdbc91 100644 --- a/internal/domain/main-entities/person/entity.go +++ b/internal/domain/main-entities/person/entity.go @@ -2,6 +2,7 @@ package person import ( ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/ethnic" epa "simrs-vx/internal/domain/main-entities/person-address" epc "simrs-vx/internal/domain/main-entities/person-contact" erp "simrs-vx/internal/domain/references/person" @@ -20,7 +21,8 @@ type Person struct { Education_Code *erp.EducationCode `json:"education_code" gorm:"size:10"` Ocupation_Code *erp.OcupationCode `json:"occupation_code" gorm:"size:15"` Ocupation_Name *string `json:"occupation_name" gorm:"size:50"` - Ethnic_Code *erp.EthnicCode `json:"ethnic_code" gorm:"size:15"` + Ethnic_Code *string `json:"ethnic_code" gorm:"size:20"` + Ethnic *ee.Ethnic `json:"ethnic,omitempty" gorm:"foreignKey:Ethnic_Code;references:Code"` Addresses *[]epa.PersonAddress `json:"addresses" gorm:"foreignKey:Person_Id"` Contacts *[]epc.PersonContact `json:"contacts" gorm:"foreignKey:Person_Id"` } diff --git a/internal/domain/references/person/person.go b/internal/domain/references/person/person.go index 0fb3fe27..eef0a7a2 100644 --- a/internal/domain/references/person/person.go +++ b/internal/domain/references/person/person.go @@ -11,7 +11,6 @@ type ( AgeGroupForMedicineCode string RelativeCode string ContactTypeCode string - EthnicCode string ) const ( diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index ed6692b2..60b46ab9 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -12,9 +12,11 @@ import ( divisionposition "simrs-vx/internal/domain/main-entities/division-position" doctor "simrs-vx/internal/domain/main-entities/doctor" employee "simrs-vx/internal/domain/main-entities/employee" + ethnic "simrs-vx/internal/domain/main-entities/ethnic" infra "simrs-vx/internal/domain/main-entities/infra" infragroup "simrs-vx/internal/domain/main-entities/infra-group" installation "simrs-vx/internal/domain/main-entities/installation" + insurancecompany "simrs-vx/internal/domain/main-entities/insurance-company" item "simrs-vx/internal/domain/main-entities/item" itemgroup "simrs-vx/internal/domain/main-entities/item-group" itemprice "simrs-vx/internal/domain/main-entities/item-price" @@ -103,6 +105,8 @@ func GetEntities() []any { &medicinemethod.MedicineMethod{}, &mcusrccategory.McuSrcCategory{}, &mcusrc.McuSrc{}, + ðnic.Ethnic{}, + &insurancecompany.InsuranceCompany{}, } } From aa73c31ffd1f2fe3640ed1dbafa5cbd4f59c13c7 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 27 Aug 2025 15:53:08 +0700 Subject: [PATCH 31/40] add crud for ethnic, insurancecompany --- .../interface/main-handler/ethnic/handler.go | 71 +++++ .../main-handler/insurance-company/handler.go | 71 +++++ .../interface/main-handler/main-handler.go | 4 + .../use-case/main-use-case/ethnic/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/ethnic/helper.go | 22 ++ internal/use-case/main-use-case/ethnic/lib.go | 149 ++++++++++ .../main-use-case/ethnic/middleware-runner.go | 103 +++++++ .../main-use-case/ethnic/middleware.go | 9 + .../use-case/main-use-case/ethnic/tycovar.go | 44 +++ .../main-use-case/insurance-company/case.go | 275 ++++++++++++++++++ .../main-use-case/insurance-company/helper.go | 25 ++ .../main-use-case/insurance-company/lib.go | 149 ++++++++++ .../insurance-company/middleware-runner.go | 103 +++++++ .../insurance-company/middleware.go | 9 + .../insurance-company/tycovar.go | 44 +++ 15 files changed, 1353 insertions(+) create mode 100644 internal/interface/main-handler/ethnic/handler.go create mode 100644 internal/interface/main-handler/insurance-company/handler.go create mode 100644 internal/use-case/main-use-case/ethnic/case.go create mode 100644 internal/use-case/main-use-case/ethnic/helper.go create mode 100644 internal/use-case/main-use-case/ethnic/lib.go create mode 100644 internal/use-case/main-use-case/ethnic/middleware-runner.go create mode 100644 internal/use-case/main-use-case/ethnic/middleware.go create mode 100644 internal/use-case/main-use-case/ethnic/tycovar.go create mode 100644 internal/use-case/main-use-case/insurance-company/case.go create mode 100644 internal/use-case/main-use-case/insurance-company/helper.go create mode 100644 internal/use-case/main-use-case/insurance-company/lib.go create mode 100644 internal/use-case/main-use-case/insurance-company/middleware-runner.go create mode 100644 internal/use-case/main-use-case/insurance-company/middleware.go create mode 100644 internal/use-case/main-use-case/insurance-company/tycovar.go diff --git a/internal/interface/main-handler/ethnic/handler.go b/internal/interface/main-handler/ethnic/handler.go new file mode 100644 index 00000000..8af8bde9 --- /dev/null +++ b/internal/interface/main-handler/ethnic/handler.go @@ -0,0 +1,71 @@ +package ethnic + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/ethnic" + u "simrs-vx/internal/use-case/main-use-case/ethnic" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/insurance-company/handler.go b/internal/interface/main-handler/insurance-company/handler.go new file mode 100644 index 00000000..009c93ab --- /dev/null +++ b/internal/interface/main-handler/insurance-company/handler.go @@ -0,0 +1,71 @@ +package insurancecompany + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/insurance-company" + u "simrs-vx/internal/use-case/main-use-case/insurance-company" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 4fbc704f..91b36af8 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -38,9 +38,11 @@ import ( diagnosesrc "simrs-vx/internal/interface/main-handler/diagnose-src" division "simrs-vx/internal/interface/main-handler/division" divisionposition "simrs-vx/internal/interface/main-handler/division-position" + ethnic "simrs-vx/internal/interface/main-handler/ethnic" infra "simrs-vx/internal/interface/main-handler/infra" infragroup "simrs-vx/internal/interface/main-handler/infra-group" installation "simrs-vx/internal/interface/main-handler/installation" + insurancecompany "simrs-vx/internal/interface/main-handler/insurance-company" item "simrs-vx/internal/interface/main-handler/item" itemgroup "simrs-vx/internal/interface/main-handler/item-group" itemprice "simrs-vx/internal/interface/main-handler/item-price" @@ -118,6 +120,8 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/medicine-method", medicinemethod.O) hc.RegCrud(r, "/v1/mcu-src-category", mcusrccategory.O) hc.RegCrud(r, "/v1/mcu-src", mcusrc.O) + hc.RegCrud(r, "/v1/ethnic", ethnic.O) + hc.RegCrud(r, "/v1/insurance-company", insurancecompany.O) hc.RegCrud(r, "/v1/village", village.O) hc.RegCrud(r, "/v1/district", district.O) diff --git a/internal/use-case/main-use-case/ethnic/case.go b/internal/use-case/main-use-case/ethnic/case.go new file mode 100644 index 00000000..adf50f44 --- /dev/null +++ b/internal/use-case/main-use-case/ethnic/case.go @@ -0,0 +1,275 @@ +package ethnic + +import ( + e "simrs-vx/internal/domain/main-entities/ethnic" + "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" +) + +const source = "ethnic" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Ethnic{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Ethnic + var dataList []e.Ethnic + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Ethnic + 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: uint16(input.Id)} + var data *e.Ethnic + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Ethnic + 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 + +} diff --git a/internal/use-case/main-use-case/ethnic/helper.go b/internal/use-case/main-use-case/ethnic/helper.go new file mode 100644 index 00000000..e53f707b --- /dev/null +++ b/internal/use-case/main-use-case/ethnic/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package ethnic + +import ( + e "simrs-vx/internal/domain/main-entities/ethnic" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Ethnic) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/ethnic/lib.go b/internal/use-case/main-use-case/ethnic/lib.go new file mode 100644 index 00000000..96921640 --- /dev/null +++ b/internal/use-case/main-use-case/ethnic/lib.go @@ -0,0 +1,149 @@ +package ethnic + +import ( + e "simrs-vx/internal/domain/main-entities/ethnic" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Ethnic, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Ethnic{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ethnic, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Ethnic{} + 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.Ethnic{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Ethnic, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Ethnic{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Ethnic, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Ethnic, 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 +} diff --git a/internal/use-case/main-use-case/ethnic/middleware-runner.go b/internal/use-case/main-use-case/ethnic/middleware-runner.go new file mode 100644 index 00000000..5b8f747d --- /dev/null +++ b/internal/use-case/main-use-case/ethnic/middleware-runner.go @@ -0,0 +1,103 @@ +package ethnic + +import ( + e "simrs-vx/internal/domain/main-entities/ethnic" + 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.Ethnic) 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.Ethnic) 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.Ethnic) 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.Ethnic) 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.Ethnic) 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 +} diff --git a/internal/use-case/main-use-case/ethnic/middleware.go b/internal/use-case/main-use-case/ethnic/middleware.go new file mode 100644 index 00000000..24b6ac6b --- /dev/null +++ b/internal/use-case/main-use-case/ethnic/middleware.go @@ -0,0 +1,9 @@ +package ethnic + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/ethnic/tycovar.go b/internal/use-case/main-use-case/ethnic/tycovar.go new file mode 100644 index 00000000..53cd2f2f --- /dev/null +++ b/internal/use-case/main-use-case/ethnic/tycovar.go @@ -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 ethnic + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/ethnic" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Ethnic, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Ethnic, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Ethnic, 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 diff --git a/internal/use-case/main-use-case/insurance-company/case.go b/internal/use-case/main-use-case/insurance-company/case.go new file mode 100644 index 00000000..fafec031 --- /dev/null +++ b/internal/use-case/main-use-case/insurance-company/case.go @@ -0,0 +1,275 @@ +package insurancecompany + +import ( + e "simrs-vx/internal/domain/main-entities/insurance-company" + "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" +) + +const source = "insurance-company" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.InsuranceCompany{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.InsuranceCompany + var dataList []e.InsuranceCompany + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.InsuranceCompany + 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: uint16(input.Id)} + var data *e.InsuranceCompany + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.InsuranceCompany + 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 + +} diff --git a/internal/use-case/main-use-case/insurance-company/helper.go b/internal/use-case/main-use-case/insurance-company/helper.go new file mode 100644 index 00000000..d9969523 --- /dev/null +++ b/internal/use-case/main-use-case/insurance-company/helper.go @@ -0,0 +1,25 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package insurancecompany + +import ( + e "simrs-vx/internal/domain/main-entities/insurance-company" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.InsuranceCompany) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Regency_Code = inputSrc.Regency_Code + data.Address = inputSrc.Address + data.PhoneNumber = inputSrc.PhoneNumber +} diff --git a/internal/use-case/main-use-case/insurance-company/lib.go b/internal/use-case/main-use-case/insurance-company/lib.go new file mode 100644 index 00000000..06438edb --- /dev/null +++ b/internal/use-case/main-use-case/insurance-company/lib.go @@ -0,0 +1,149 @@ +package insurancecompany + +import ( + e "simrs-vx/internal/domain/main-entities/insurance-company" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.InsuranceCompany, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.InsuranceCompany{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.InsuranceCompany, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.InsuranceCompany{} + 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.InsuranceCompany{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.InsuranceCompany, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.InsuranceCompany{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.InsuranceCompany, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.InsuranceCompany, 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 +} diff --git a/internal/use-case/main-use-case/insurance-company/middleware-runner.go b/internal/use-case/main-use-case/insurance-company/middleware-runner.go new file mode 100644 index 00000000..d733235d --- /dev/null +++ b/internal/use-case/main-use-case/insurance-company/middleware-runner.go @@ -0,0 +1,103 @@ +package insurancecompany + +import ( + e "simrs-vx/internal/domain/main-entities/insurance-company" + 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.InsuranceCompany) 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.InsuranceCompany) 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.InsuranceCompany) 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.InsuranceCompany) 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.InsuranceCompany) 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 +} diff --git a/internal/use-case/main-use-case/insurance-company/middleware.go b/internal/use-case/main-use-case/insurance-company/middleware.go new file mode 100644 index 00000000..8bb1de0d --- /dev/null +++ b/internal/use-case/main-use-case/insurance-company/middleware.go @@ -0,0 +1,9 @@ +package insurancecompany + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/insurance-company/tycovar.go b/internal/use-case/main-use-case/insurance-company/tycovar.go new file mode 100644 index 00000000..d927f48e --- /dev/null +++ b/internal/use-case/main-use-case/insurance-company/tycovar.go @@ -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 insurancecompany + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/insurance-company" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.InsuranceCompany, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.InsuranceCompany, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.InsuranceCompany, 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 From b4cef1606135f2b34e7f6167f49814fefb58cdc0 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 28 Aug 2025 13:12:50 +0700 Subject: [PATCH 32/40] add medicine, medicinemix, medicinemixitem, medicalactionsrc, medicalactionsrcitem, device, material, doctorfee --- cmd/migration/migrations/20250828061151.sql | 121 ++++++++++++++++++ cmd/migration/migrations/atlas.sum | 5 +- internal/domain/main-entities/device/dto.go | 79 ++++++++++++ .../domain/main-entities/device/entity.go | 17 +++ .../domain/main-entities/doctor-fee/dto.go | 80 ++++++++++++ .../domain/main-entities/doctor-fee/entity.go | 18 +++ .../domain/main-entities/item-price/dto.go | 33 +++-- .../domain/main-entities/item-price/entity.go | 11 +- internal/domain/main-entities/item/dto.go | 40 +++--- internal/domain/main-entities/item/entity.go | 2 +- internal/domain/main-entities/material/dto.go | 84 ++++++++++++ .../domain/main-entities/material/entity.go | 18 +++ .../medical-action-src-item/dto.go | 77 +++++++++++ .../medical-action-src-item/entity.go | 18 +++ .../main-entities/medical-action-src/dto.go | 71 ++++++++++ .../medical-action-src/entity.go | 14 ++ .../main-entities/medicine-mix-item/dto.go | 74 +++++++++++ .../main-entities/medicine-mix-item/entity.go | 16 +++ .../domain/main-entities/medicine-mix/dto.go | 58 +++++++++ .../main-entities/medicine-mix/entity.go | 10 ++ internal/domain/main-entities/medicine/dto.go | 113 ++++++++++++++++ .../domain/main-entities/medicine/entity.go | 28 ++++ .../domain/references/clinical/clinical.go | 8 +- internal/interface/migration/migration.go | 16 +++ 24 files changed, 971 insertions(+), 40 deletions(-) create mode 100644 cmd/migration/migrations/20250828061151.sql create mode 100644 internal/domain/main-entities/device/dto.go create mode 100644 internal/domain/main-entities/device/entity.go create mode 100644 internal/domain/main-entities/doctor-fee/dto.go create mode 100644 internal/domain/main-entities/doctor-fee/entity.go create mode 100644 internal/domain/main-entities/material/dto.go create mode 100644 internal/domain/main-entities/material/entity.go create mode 100644 internal/domain/main-entities/medical-action-src-item/dto.go create mode 100644 internal/domain/main-entities/medical-action-src-item/entity.go create mode 100644 internal/domain/main-entities/medical-action-src/dto.go create mode 100644 internal/domain/main-entities/medical-action-src/entity.go create mode 100644 internal/domain/main-entities/medicine-mix-item/dto.go create mode 100644 internal/domain/main-entities/medicine-mix-item/entity.go create mode 100644 internal/domain/main-entities/medicine-mix/dto.go create mode 100644 internal/domain/main-entities/medicine-mix/entity.go create mode 100644 internal/domain/main-entities/medicine/dto.go create mode 100644 internal/domain/main-entities/medicine/entity.go diff --git a/cmd/migration/migrations/20250828061151.sql b/cmd/migration/migrations/20250828061151.sql new file mode 100644 index 00000000..64ab7eb5 --- /dev/null +++ b/cmd/migration/migrations/20250828061151.sql @@ -0,0 +1,121 @@ +-- Modify "Item" table +ALTER TABLE "public"."Item" ALTER COLUMN "Stock" TYPE bigint; +-- Create "Device" table +CREATE TABLE "public"."Device" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "Uom_Code" character varying(10) NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Device_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Device_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Device_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "DoctorFee" table +CREATE TABLE "public"."DoctorFee" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Doctor_Id" bigint NULL, + "FeeTypeCode" character varying(11) NULL, + "Price" numeric NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_DoctorFee_Doctor" FOREIGN KEY ("Doctor_Id") REFERENCES "public"."Doctor" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_DoctorFee_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Modify "ItemPrice" table +ALTER TABLE "public"."ItemPrice" ADD COLUMN "InsuranceCompany_Code" character varying(20) NULL, ADD CONSTRAINT "fk_ItemPrice_InsuranceCompany" FOREIGN KEY ("InsuranceCompany_Code") REFERENCES "public"."InsuranceCompany" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; +-- Create "Material" table +CREATE TABLE "public"."Material" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "Uom_Code" character varying(10) NULL, + "Stock" bigint NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Material_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Material_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Material_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "MedicalActionSrc" table +CREATE TABLE "public"."MedicalActionSrc" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_MedicalActionSrc_Code" UNIQUE ("Code"), + CONSTRAINT "fk_MedicalActionSrc_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "MedicalActionSrcItem" table +CREATE TABLE "public"."MedicalActionSrcItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "MedicalActionSrc_Id" bigint NULL, + "ProcedureSrc_Id" bigint NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_MedicalActionSrcItem_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_MedicalActionSrcItem_MedicalActionSrc" FOREIGN KEY ("MedicalActionSrc_Id") REFERENCES "public"."MedicalActionSrc" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_MedicalActionSrcItem_ProcedureSrc" FOREIGN KEY ("ProcedureSrc_Id") REFERENCES "public"."ProcedureSrc" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Medicine" table +CREATE TABLE "public"."Medicine" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "MedicineGroup_Code" character varying(10) NULL, + "MedicineMethod_Code" character varying(10) NULL, + "Uom_Code" character varying(10) NULL, + "Dose" smallint NULL, + "Infra_Id" integer NULL, + "Stock" bigint NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Medicine_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Medicine_Infra" FOREIGN KEY ("Infra_Id") REFERENCES "public"."Infra" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Medicine_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Medicine_MedicineGroup" FOREIGN KEY ("MedicineGroup_Code") REFERENCES "public"."MedicineGroup" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Medicine_MedicineMethod" FOREIGN KEY ("MedicineMethod_Code") REFERENCES "public"."MedicineMethod" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Medicine_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "MedicineMix" table +CREATE TABLE "public"."MedicineMix" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id") +); +-- Create "MedicineMixItem" table +CREATE TABLE "public"."MedicineMixItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "MedicineMix_Id" bigint NULL, + "Medicine_Id" bigint NULL, + "Dose" smallint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_MedicineMixItem_Medicine" FOREIGN KEY ("Medicine_Id") REFERENCES "public"."Medicine" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_MedicineMixItem_MedicineMix" FOREIGN KEY ("MedicineMix_Id") REFERENCES "public"."MedicineMix" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index 49745602..b8ef29bb 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:yoZN1lVD6dE66V3FtMcVHtoRtFmu18Ltn5/loput+Ns= +h1:m00Lt6P6Ck2i7UG8WlVBOWl5vmvSQZltNb1O7Z7zM+I= 20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= 20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= 20250825102900.sql h1:OAUnj87Wz7mrHykX14idePckUmRYa5UH0LylYDL76RI= @@ -7,4 +7,5 @@ h1:yoZN1lVD6dE66V3FtMcVHtoRtFmu18Ltn5/loput+Ns= 20250827021904.sql h1:pgjwmQS1TxZ977a1tIXKq6pZnGauPrOUxLUTclV+fE4= 20250827024311.sql h1:eTlrQYcHa/jmb3qSZxgTB+7S4IXJ8B4yklUB36iZaDw= 20250827072230.sql h1:BfdTcToEYC8d30BS+1Su5Pz5Ecz8bh74F2j+Bh/r2BM= -20250827083322.sql h1:GhPTHNQGAP13Efly86U7baFFw4l3sz+QV3g3lzeIT9Y= +20250827083322.sql h1:2MErE7W1JTjcxtgKJs/1iEF8kgV6vrcGrDVx/m6LwHQ= +20250828061151.sql h1:cZkYO1VHCc2RtOwP1yesHNG/p+o/zeOAGvqJRU4Q4Xc= diff --git a/internal/domain/main-entities/device/dto.go b/internal/domain/main-entities/device/dto.go new file mode 100644 index 00000000..0a9aba7a --- /dev/null +++ b/internal/domain/main-entities/device/dto.go @@ -0,0 +1,79 @@ +package device + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" + eu "simrs-vx/internal/domain/main-entities/uom" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Item_Id *uint `json:"item_id"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Item_Id *uint `json:"item_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Item_Id *uint `json:"item_id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Uom *eu.Uom `json:"uom,omitempty"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` +} + +func (d Device) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + Uom_Code: d.Uom_Code, + Uom: d.Uom, + Item_Id: d.Item_Id, + Item: d.Item, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Device) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/device/entity.go b/internal/domain/main-entities/device/entity.go new file mode 100644 index 00000000..bf75c746 --- /dev/null +++ b/internal/domain/main-entities/device/entity.go @@ -0,0 +1,17 @@ +package device + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" + eu "simrs-vx/internal/domain/main-entities/uom" +) + +type Device struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:50"` + Uom_Code string `json:"uom_code" gorm:"size:10"` + Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` +} diff --git a/internal/domain/main-entities/doctor-fee/dto.go b/internal/domain/main-entities/doctor-fee/dto.go new file mode 100644 index 00000000..15da2c61 --- /dev/null +++ b/internal/domain/main-entities/doctor-fee/dto.go @@ -0,0 +1,80 @@ +package doctorfee + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" + ei "simrs-vx/internal/domain/main-entities/item" + erc "simrs-vx/internal/domain/references/clinical" +) + +type CreateDto struct { + Doctor_Id *uint `json:"doctor_id"` + FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` +} + +type ReadListDto struct { + Doctor_Id *uint `json:"doctor_id"` + FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Doctor_Id *uint `json:"doctor_id"` + FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Doctor_Id *uint `json:"doctor_id"` + Doctor *ed.Doctor `json:"doctor,omitempty"` + FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` +} + +func (d DoctorFee) ToResponse() ResponseDto { + resp := ResponseDto{ + Doctor_Id: d.Doctor_Id, + Doctor: d.Doctor, + FeeTypeCode: d.FeeTypeCode, + Price: d.Price, + Item_Id: d.Item_Id, + Item: d.Item, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []DoctorFee) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/doctor-fee/entity.go b/internal/domain/main-entities/doctor-fee/entity.go new file mode 100644 index 00000000..e0e87d0f --- /dev/null +++ b/internal/domain/main-entities/doctor-fee/entity.go @@ -0,0 +1,18 @@ +package doctorfee + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" + ei "simrs-vx/internal/domain/main-entities/item" + erc "simrs-vx/internal/domain/references/clinical" +) + +type DoctorFee struct { + ecore.Main // adjust this according to the needs + Doctor_Id *uint `json:"doctor_id"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Id;references:Id"` + FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code" gorm:"size:11"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` +} diff --git a/internal/domain/main-entities/item-price/dto.go b/internal/domain/main-entities/item-price/dto.go index d048012b..a86bd89f 100644 --- a/internal/domain/main-entities/item-price/dto.go +++ b/internal/domain/main-entities/item-price/dto.go @@ -2,17 +2,20 @@ package itemprice import ( ecore "simrs-vx/internal/domain/base-entities/core" + eic "simrs-vx/internal/domain/main-entities/insurance-company" ei "simrs-vx/internal/domain/main-entities/item" ) type CreateDto struct { - Item_Id *uint `json:"item_id"` - Price float64 `json:"price"` + Item_Id *uint `json:"item_id"` + Price float64 `json:"price"` + InsuranceCompany_Code *uint16 `json:"insuranceCompany_code"` } type ReadListDto struct { - Item_Id *uint `json:"item_id"` - Price float64 `json:"price"` + Item_Id *uint `json:"item_id"` + Price float64 `json:"price"` + InsuranceCompany_Code *uint16 `json:"insuranceCompany_code"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -20,9 +23,10 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Item_Id *uint `json:"item_id"` - Price float64 `json:"price"` + Id uint16 `json:"id"` + Item_Id *uint `json:"item_id"` + Price float64 `json:"price"` + InsuranceCompany_Code *uint16 `json:"insuranceCompany_code"` } type UpdateDto struct { @@ -42,15 +46,20 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Item_Id *uint `json:"item_id"` - Item *ei.Item `json:"item,omitempty"` - Price float64 `json:"price"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` + Price float64 `json:"price"` + InsuranceCompany_Code *uint16 `json:"insuranceCompany_code"` + InsuranceCompany *eic.InsuranceCompany `json:"insuranceCompany,omitempty"` } func (d ItemPrice) ToResponse() ResponseDto { resp := ResponseDto{ - Item_Id: d.Item_Id, - Price: d.Price, + Item_Id: d.Item_Id, + Item: d.Item, + Price: d.Price, + InsuranceCompany_Code: d.InsuranceCompany_Code, + InsuranceCompany: d.InsuranceCompany, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/item-price/entity.go b/internal/domain/main-entities/item-price/entity.go index f1bf072f..f25c21b1 100644 --- a/internal/domain/main-entities/item-price/entity.go +++ b/internal/domain/main-entities/item-price/entity.go @@ -2,12 +2,15 @@ package itemprice import ( ecore "simrs-vx/internal/domain/base-entities/core" + eic "simrs-vx/internal/domain/main-entities/insurance-company" ei "simrs-vx/internal/domain/main-entities/item" ) type ItemPrice struct { - ecore.Main // adjust this according to the needs - Item_Id *uint `json:"item_id"` - Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` - Price float64 `json:"price"` + ecore.Main // adjust this according to the needs + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` + Price float64 `json:"price"` + InsuranceCompany_Code *uint16 `json:"insuranceCompany_code" gorm:"size:20"` + InsuranceCompany *eic.InsuranceCompany `json:"insuranceCompany,omitempty" gorm:"foreignKey:InsuranceCompany_Code;references:Code"` } diff --git a/internal/domain/main-entities/item/dto.go b/internal/domain/main-entities/item/dto.go index 5094e971..78f5fa4b 100644 --- a/internal/domain/main-entities/item/dto.go +++ b/internal/domain/main-entities/item/dto.go @@ -7,21 +7,21 @@ import ( ) type CreateDto struct { - Code string `json:"code"` - Name string `json:"name"` - ItemGroup_Code *string `json:"itemGroup_code"` - Uom_Code *string `json:"uom_code"` - Infra_Id *int16 `json:"infra_id"` - Stock *float64 `json:"stock"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *string `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *int16 `json:"infra_id"` + Stock *int `json:"stock"` } type ReadListDto struct { - Code string `json:"code"` - Name string `json:"name"` - ItemGroup_Code *string `json:"itemGroup_code"` - Uom_Code *string `json:"uom_code"` - Infra_Id *int16 `json:"infra_id"` - Stock *float64 `json:"stock"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *string `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *int16 `json:"infra_id"` + Stock *int `json:"stock"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -29,13 +29,13 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - ItemGroup_Code *string `json:"itemGroup_code"` - Uom_Code *string `json:"uom_code"` - Infra_Id *int16 `json:"infra_id"` - Stock *float64 `json:"stock"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *string `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *int16 `json:"infra_id"` + Stock *int `json:"stock"` } type UpdateDto struct { @@ -62,7 +62,7 @@ type ResponseDto struct { Uom_Code *string `json:"uom_code"` Uom *eu.Uom `json:"uom,omitempty"` Infra_Id *int16 `json:"infra_id"` - Stock *float64 `json:"stock"` + Stock *int `json:"stock"` } func (d Item) ToResponse() ResponseDto { diff --git a/internal/domain/main-entities/item/entity.go b/internal/domain/main-entities/item/entity.go index 561da2b2..9eeb9425 100644 --- a/internal/domain/main-entities/item/entity.go +++ b/internal/domain/main-entities/item/entity.go @@ -15,5 +15,5 @@ type Item struct { Uom_Code *string `json:"uom_code" gorm:"size:10"` Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` Infra_Id *int16 `json:"infra_id"` - Stock *float64 `json:"stock"` + Stock *int `json:"stock"` } diff --git a/internal/domain/main-entities/material/dto.go b/internal/domain/main-entities/material/dto.go new file mode 100644 index 00000000..e466e5df --- /dev/null +++ b/internal/domain/main-entities/material/dto.go @@ -0,0 +1,84 @@ +package material + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" + eu "simrs-vx/internal/domain/main-entities/uom" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Uom *eu.Uom `json:"uom,omitempty"` + Stock *int `json:"stock"` + Item_Id uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` +} + +func (d Material) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + Uom_Code: d.Uom_Code, + Uom: d.Uom, + Stock: d.Stock, + Item_Id: d.Item_Id, + Item: d.Item, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Material) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/material/entity.go b/internal/domain/main-entities/material/entity.go new file mode 100644 index 00000000..8f10d0e5 --- /dev/null +++ b/internal/domain/main-entities/material/entity.go @@ -0,0 +1,18 @@ +package material + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" + eu "simrs-vx/internal/domain/main-entities/uom" +) + +type Material struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:50"` + Uom_Code string `json:"uom_code" gorm:"size:10"` + Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` + Stock *int `json:"stock"` + Item_Id uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` +} diff --git a/internal/domain/main-entities/medical-action-src-item/dto.go b/internal/domain/main-entities/medical-action-src-item/dto.go new file mode 100644 index 00000000..79ba260c --- /dev/null +++ b/internal/domain/main-entities/medical-action-src-item/dto.go @@ -0,0 +1,77 @@ +package medicalactionsrcitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" + emas "simrs-vx/internal/domain/main-entities/medical-action-src" + eps "simrs-vx/internal/domain/main-entities/procedure-src" +) + +type CreateDto struct { + MedicalActionSrc_Id *uint `json:"medicalActionSrc_id"` + ProcedureSrc_Id *uint `json:"procedureSrc_id"` + Item_Id *uint `json:"item_id"` +} + +type ReadListDto struct { + MedicalActionSrc_Id *uint `json:"medicalActionSrc_id"` + ProcedureSrc_Id *uint `json:"procedureSrc_id"` + Item_Id *uint `json:"item_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + MedicalActionSrc_Id *uint `json:"medicalActionSrc_id"` + ProcedureSrc_Id *uint `json:"procedureSrc_id"` + Item_Id *uint `json:"item_id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + MedicalActionSrc_Id *uint `json:"medicalActionSrc_id"` + MedicalActionSrc *emas.MedicalActionSrc `json:"medicalActionSrc,omitempty"` + ProcedureSrc_Id *uint `json:"procedureSrc_id"` + ProcedureSrc *eps.ProcedureSrc `json:"procedureSrc,omitempty"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` +} + +func (d MedicalActionSrcItem) ToResponse() ResponseDto { + resp := ResponseDto{ + MedicalActionSrc_Id: d.MedicalActionSrc_Id, + MedicalActionSrc: d.MedicalActionSrc, + ProcedureSrc_Id: d.ProcedureSrc_Id, + ProcedureSrc: d.ProcedureSrc, + Item_Id: d.Item_Id, + Item: d.Item, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []MedicalActionSrcItem) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/medical-action-src-item/entity.go b/internal/domain/main-entities/medical-action-src-item/entity.go new file mode 100644 index 00000000..59ecb828 --- /dev/null +++ b/internal/domain/main-entities/medical-action-src-item/entity.go @@ -0,0 +1,18 @@ +package medicalactionsrcitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" + emas "simrs-vx/internal/domain/main-entities/medical-action-src" + eps "simrs-vx/internal/domain/main-entities/procedure-src" +) + +type MedicalActionSrcItem struct { + ecore.Main // adjust this according to the needs + MedicalActionSrc_Id *uint `json:"medicalActionSrc_id"` + MedicalActionSrc *emas.MedicalActionSrc `json:"medicalActionSrc,omitempty" gorm:"foreignKey:MedicalActionSrc_Id;references:Id"` + ProcedureSrc_Id *uint `json:"procedureSrc_id"` + ProcedureSrc *eps.ProcedureSrc `json:"procedureSrc,omitempty" gorm:"foreignKey:ProcedureSrc_Id;references:Id"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` +} diff --git a/internal/domain/main-entities/medical-action-src/dto.go b/internal/domain/main-entities/medical-action-src/dto.go new file mode 100644 index 00000000..85fdf003 --- /dev/null +++ b/internal/domain/main-entities/medical-action-src/dto.go @@ -0,0 +1,71 @@ +package medicalactionsrc + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + Item_Id *uint `json:"item_id"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + Item_Id *uint `json:"item_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Item_Id *uint `json:"item_id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Code string `json:"code"` + Name string `json:"name"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` +} + +func (d MedicalActionSrc) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + Item_Id: d.Item_Id, + Item: d.Item, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []MedicalActionSrc) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/medical-action-src/entity.go b/internal/domain/main-entities/medical-action-src/entity.go new file mode 100644 index 00000000..fbbbdb28 --- /dev/null +++ b/internal/domain/main-entities/medical-action-src/entity.go @@ -0,0 +1,14 @@ +package medicalactionsrc + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/item" +) + +type MedicalActionSrc struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:20"` + Name string `json:"name" gorm:"size:50"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` +} diff --git a/internal/domain/main-entities/medicine-mix-item/dto.go b/internal/domain/main-entities/medicine-mix-item/dto.go new file mode 100644 index 00000000..fcc1865e --- /dev/null +++ b/internal/domain/main-entities/medicine-mix-item/dto.go @@ -0,0 +1,74 @@ +package medicinemixitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + em "simrs-vx/internal/domain/main-entities/medicine" + emm "simrs-vx/internal/domain/main-entities/medicine-mix" +) + +type CreateDto struct { + MedicineMix_Id *uint `json:"medicineMix_id"` + Medicine_Id *uint `json:"medicine_id"` + Dose *uint8 `json:"dose"` +} + +type ReadListDto struct { + MedicineMix_Id *uint `json:"medicineMix_id"` + Medicine_Id *uint `json:"medicine_id"` + Dose *uint8 `json:"dose"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + MedicineMix_Id *uint `json:"medicineMix_id"` + Medicine_Id *uint `json:"medicine_id"` + Dose *uint8 `json:"dose"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + MedicineMix_Id *uint `json:"medicineMix_id"` + MedicineMix *emm.MedicineMix `json:"medicineMix,omitempty"` + Medicine_Id *uint `json:"medicine_id"` + Medicine *em.Medicine `json:"medicine,omitempty"` + Dose *uint8 `json:"dose"` +} + +func (d MedicineMixItem) ToResponse() ResponseDto { + resp := ResponseDto{ + MedicineMix_Id: d.MedicineMix_Id, + MedicineMix: d.MedicineMix, + Medicine_Id: d.Medicine_Id, + Medicine: d.Medicine, + Dose: d.Dose, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []MedicineMixItem) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/medicine-mix-item/entity.go b/internal/domain/main-entities/medicine-mix-item/entity.go new file mode 100644 index 00000000..7c456fcb --- /dev/null +++ b/internal/domain/main-entities/medicine-mix-item/entity.go @@ -0,0 +1,16 @@ +package medicinemixitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + em "simrs-vx/internal/domain/main-entities/medicine" + emm "simrs-vx/internal/domain/main-entities/medicine-mix" +) + +type MedicineMixItem struct { + ecore.Main // adjust this according to the needs + MedicineMix_Id *uint `json:"medicineMix_id"` + MedicineMix *emm.MedicineMix `json:"medicineMix,omitempty" gorm:"foreignKey:MedicineMix_Id;references:Id"` + Medicine_Id *uint `json:"medicine_id"` + Medicine *em.Medicine `json:"medicine,omitempty" gorm:"foreignKey:Medicine_Id;references:Id"` + Dose *uint8 `json:"dose"` +} diff --git a/internal/domain/main-entities/medicine-mix/dto.go b/internal/domain/main-entities/medicine-mix/dto.go new file mode 100644 index 00000000..1d21a635 --- /dev/null +++ b/internal/domain/main-entities/medicine-mix/dto.go @@ -0,0 +1,58 @@ +package medicinemix + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Name string `json:"name"` +} + +type ReadListDto struct { + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Name string `json:"name"` +} + +func (d MedicineMix) ToResponse() ResponseDto { + resp := ResponseDto{ + Name: d.Name, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []MedicineMix) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/medicine-mix/entity.go b/internal/domain/main-entities/medicine-mix/entity.go new file mode 100644 index 00000000..3670c6d6 --- /dev/null +++ b/internal/domain/main-entities/medicine-mix/entity.go @@ -0,0 +1,10 @@ +package medicinemix + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type MedicineMix struct { + ecore.Main // adjust this according to the needs + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/domain/main-entities/medicine/dto.go b/internal/domain/main-entities/medicine/dto.go new file mode 100644 index 00000000..9e505b8b --- /dev/null +++ b/internal/domain/main-entities/medicine/dto.go @@ -0,0 +1,113 @@ +package medicine + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ein "simrs-vx/internal/domain/main-entities/infra" + eit "simrs-vx/internal/domain/main-entities/item" + emg "simrs-vx/internal/domain/main-entities/medicine-group" + emm "simrs-vx/internal/domain/main-entities/medicine-method" + eu "simrs-vx/internal/domain/main-entities/uom" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + MedicineGroup_Code *string `json:"medicineGroup_code"` + MedicineMethod_Code *string `json:"medicineMethod_code"` + Uom_Code *string `json:"uom_code"` + Dose uint8 `json:"dose"` + Infra_Id *uint16 `json:"infra_id"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + MedicineGroup_Code *string `json:"medicineGroup_code"` + MedicineMethod_Code *string `json:"medicineMethod_code"` + Uom_Code *string `json:"uom_code"` + Dose uint8 `json:"dose"` + Infra_Id *uint16 `json:"infra_id"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + MedicineGroup_Code *string `json:"medicineGroup_code"` + MedicineMethod_Code *string `json:"medicineMethod_code"` + Uom_Code *string `json:"uom_code"` + Dose uint8 `json:"dose"` + Infra_Id *uint16 `json:"infra_id"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Code string `json:"code"` + Name string `json:"name"` + MedicineGroup_Code *string `json:"medicineGroup_code"` + MedicineGroup *emg.MedicineGroup `json:"medicineGroup"` + MedicineMethod_Code *string `json:"medicineMethod_code"` + MedicineMethod *emm.MedicineMethod `json:"medicineMethod"` + Uom_Code *string `json:"uom_code"` + Uom *eu.Uom `json:"uom"` + Dose uint8 `json:"dose"` + Infra_Id *uint16 `json:"infra_id"` + Infra *ein.Infra `json:"infra,omitempty"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` + Item *eit.Item `json:"item,omitempty"` +} + +func (d Medicine) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + MedicineGroup_Code: d.MedicineGroup_Code, + MedicineGroup: d.MedicineGroup, + MedicineMethod_Code: d.MedicineMethod_Code, + MedicineMethod: d.MedicineMethod, + Uom_Code: d.Uom_Code, + Uom: d.Uom, + Dose: d.Dose, + Infra_Id: d.Infra_Id, + Infra: d.Infra, + Stock: d.Stock, + Item_Id: d.Item_Id, + Item: d.Item, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Medicine) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/medicine/entity.go b/internal/domain/main-entities/medicine/entity.go new file mode 100644 index 00000000..d538f496 --- /dev/null +++ b/internal/domain/main-entities/medicine/entity.go @@ -0,0 +1,28 @@ +package medicine + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ein "simrs-vx/internal/domain/main-entities/infra" + eit "simrs-vx/internal/domain/main-entities/item" + emg "simrs-vx/internal/domain/main-entities/medicine-group" + emm "simrs-vx/internal/domain/main-entities/medicine-method" + eu "simrs-vx/internal/domain/main-entities/uom" +) + +type Medicine struct { + ecore.Main // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:50"` + MedicineGroup_Code *string `json:"medicineGroup_code" gorm:"size:10"` + MedicineGroup *emg.MedicineGroup `json:"medicineGroup,omitempty" gorm:"foreignKey:MedicineGroup_Code;references:Code"` + MedicineMethod_Code *string `json:"medicineMethod_code" gorm:"size:10"` + MedicineMethod *emm.MedicineMethod `json:"medicineMethod,omitempty" gorm:"foreignKey:MedicineMethod_Code;references:Code"` + Uom_Code *string `json:"uom_code" gorm:"size:10"` + Uom *eu.Uom `json:"uom" gorm:"foreignKey:Uom_Code;references:Code"` + Dose uint8 `json:"dose"` + Infra_Id *uint16 `json:"infra_id"` + Infra *ein.Infra `json:"infra,omitempty" gorm:"foreignKey:Infra_Id;references:Id"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` + Item *eit.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` +} diff --git a/internal/domain/references/clinical/clinical.go b/internal/domain/references/clinical/clinical.go index 13e95581..f1be0605 100644 --- a/internal/domain/references/clinical/clinical.go +++ b/internal/domain/references/clinical/clinical.go @@ -1,7 +1,8 @@ package clinical type ( - CheckupScopeCode string + CheckupScopeCode string + DoctorFeeTypeCode string ) const ( @@ -9,4 +10,9 @@ const ( CSCMLab CheckupScopeCode = "mic-lab" // Microbacterial Laboratorium CSCPLab CheckupScopeCode = "pa-lab" // Patology Anatomy Laboratorium CSCRad CheckupScopeCode = "radiology" // Radiology + + DFTCOut DoctorFeeTypeCode = "outpatient" // Rawat Jalan + DFTCInp DoctorFeeTypeCode = "inpatient" // Rawat Inap + DFTCEme DoctorFeeTypeCode = "emergency" // Darurat + DFTCReh DoctorFeeTypeCode = "medic-rehab" // Rehab Medik ) diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 60b46ab9..6122597c 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -6,11 +6,13 @@ import ( "os" "os/exec" counter "simrs-vx/internal/domain/main-entities/counter" + device "simrs-vx/internal/domain/main-entities/device" diagnosesrc "simrs-vx/internal/domain/main-entities/diagnose-src" district "simrs-vx/internal/domain/main-entities/district" division "simrs-vx/internal/domain/main-entities/division" divisionposition "simrs-vx/internal/domain/main-entities/division-position" doctor "simrs-vx/internal/domain/main-entities/doctor" + doctorfee "simrs-vx/internal/domain/main-entities/doctor-fee" employee "simrs-vx/internal/domain/main-entities/employee" ethnic "simrs-vx/internal/domain/main-entities/ethnic" infra "simrs-vx/internal/domain/main-entities/infra" @@ -20,10 +22,16 @@ import ( item "simrs-vx/internal/domain/main-entities/item" itemgroup "simrs-vx/internal/domain/main-entities/item-group" itemprice "simrs-vx/internal/domain/main-entities/item-price" + material "simrs-vx/internal/domain/main-entities/material" mcusrc "simrs-vx/internal/domain/main-entities/mcu-src" mcusrccategory "simrs-vx/internal/domain/main-entities/mcu-src-category" + medicalactionsrc "simrs-vx/internal/domain/main-entities/medical-action-src" + medicalactionsrcitem "simrs-vx/internal/domain/main-entities/medical-action-src-item" + medicine "simrs-vx/internal/domain/main-entities/medicine" medicinegroup "simrs-vx/internal/domain/main-entities/medicine-group" medicinemethod "simrs-vx/internal/domain/main-entities/medicine-method" + medicinemix "simrs-vx/internal/domain/main-entities/medicine-mix" + medicinemixitem "simrs-vx/internal/domain/main-entities/medicine-mix-item" nurse "simrs-vx/internal/domain/main-entities/nurse" nutritionist "simrs-vx/internal/domain/main-entities/nutritionist" person "simrs-vx/internal/domain/main-entities/person" @@ -107,6 +115,14 @@ func GetEntities() []any { &mcusrc.McuSrc{}, ðnic.Ethnic{}, &insurancecompany.InsuranceCompany{}, + &medicine.Medicine{}, + &medicinemix.MedicineMix{}, + &medicinemixitem.MedicineMixItem{}, + &medicalactionsrc.MedicalActionSrc{}, + &medicalactionsrcitem.MedicalActionSrcItem{}, + &material.Material{}, + &device.Device{}, + &doctorfee.DoctorFee{}, } } From 645640689bc56f24739ef2fc07d3a5c82b4a13a7 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 28 Aug 2025 14:06:23 +0700 Subject: [PATCH 33/40] feat (medicine): wip --- .../use-case/main-use-case/medicine/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/medicine/helper.go | 28 ++ .../use-case/main-use-case/medicine/lib.go | 149 ++++++++++ .../medicine/middleware-runner.go | 103 +++++++ .../main-use-case/medicine/middleware.go | 23 ++ .../main-use-case/medicine/tycovar.go | 44 +++ 6 files changed, 622 insertions(+) create mode 100644 internal/use-case/main-use-case/medicine/case.go create mode 100644 internal/use-case/main-use-case/medicine/helper.go create mode 100644 internal/use-case/main-use-case/medicine/lib.go create mode 100644 internal/use-case/main-use-case/medicine/middleware-runner.go create mode 100644 internal/use-case/main-use-case/medicine/middleware.go create mode 100644 internal/use-case/main-use-case/medicine/tycovar.go diff --git a/internal/use-case/main-use-case/medicine/case.go b/internal/use-case/main-use-case/medicine/case.go new file mode 100644 index 00000000..20955134 --- /dev/null +++ b/internal/use-case/main-use-case/medicine/case.go @@ -0,0 +1,275 @@ +package medicine + +import ( + e "simrs-vx/internal/domain/main-entities/medicine" + "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" +) + +const source = "medicine" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Medicine{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Medicine + var dataList []e.Medicine + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Medicine + 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: uint16(input.Id)} + var data *e.Medicine + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Medicine + 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 + +} diff --git a/internal/use-case/main-use-case/medicine/helper.go b/internal/use-case/main-use-case/medicine/helper.go new file mode 100644 index 00000000..2bd7ab7e --- /dev/null +++ b/internal/use-case/main-use-case/medicine/helper.go @@ -0,0 +1,28 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package medicine + +import ( + e "simrs-vx/internal/domain/main-entities/medicine" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Medicine) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.MedicineGroup_Code = inputSrc.MedicineGroup_Code + data.MedicineMethod_Code = inputSrc.MedicineMethod_Code + data.Uom_Code = inputSrc.Uom_Code + data.Dose = inputSrc.Dose + data.Infra_Id = inputSrc.Infra_Id + data.Stock = inputSrc.Stock +} diff --git a/internal/use-case/main-use-case/medicine/lib.go b/internal/use-case/main-use-case/medicine/lib.go new file mode 100644 index 00000000..cbf756d4 --- /dev/null +++ b/internal/use-case/main-use-case/medicine/lib.go @@ -0,0 +1,149 @@ +package medicine + +import ( + e "simrs-vx/internal/domain/main-entities/medicine" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Medicine, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Medicine{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Medicine, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Medicine{} + 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.Medicine{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Medicine, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Medicine{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Medicine, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Medicine, 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 +} diff --git a/internal/use-case/main-use-case/medicine/middleware-runner.go b/internal/use-case/main-use-case/medicine/middleware-runner.go new file mode 100644 index 00000000..0bf8922b --- /dev/null +++ b/internal/use-case/main-use-case/medicine/middleware-runner.go @@ -0,0 +1,103 @@ +package medicine + +import ( + e "simrs-vx/internal/domain/main-entities/medicine" + 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.Medicine) 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.Medicine) 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.Medicine) 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.Medicine) 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.Medicine) 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 +} diff --git a/internal/use-case/main-use-case/medicine/middleware.go b/internal/use-case/main-use-case/medicine/middleware.go new file mode 100644 index 00000000..29a280cb --- /dev/null +++ b/internal/use-case/main-use-case/medicine/middleware.go @@ -0,0 +1,23 @@ +package medicine + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } + +// func createItemAndItemPrice(input *e.CreateDto, data *e.Medicine, tx *gorm.DB) error { +// if input != nil { +// itemCreate := ei.CreateDto{ +// Code: input.Code, +// Name: input.Name, +// ItemGroup_Code: "Medicine", +// Uom_Code: input.Uom_Code, +// Infra_Id: input.Infra_Id, +// Stock: input.Stock, +// } +// } +// return nil +// } diff --git a/internal/use-case/main-use-case/medicine/tycovar.go b/internal/use-case/main-use-case/medicine/tycovar.go new file mode 100644 index 00000000..3e68abb0 --- /dev/null +++ b/internal/use-case/main-use-case/medicine/tycovar.go @@ -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 medicine + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/medicine" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Medicine, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Medicine, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Medicine, 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 From f8a4c8ab9727fe7c41e2dafa76b1bf751eb65a4a Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 28 Aug 2025 14:10:11 +0700 Subject: [PATCH 34/40] changed infra id data type --- cmd/migration/migrations/20250828070941.sql | 2 ++ cmd/migration/migrations/atlas.sum | 5 +++-- internal/domain/main-entities/item/dto.go | 6 +++--- internal/domain/main-entities/item/entity.go | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 cmd/migration/migrations/20250828070941.sql diff --git a/cmd/migration/migrations/20250828070941.sql b/cmd/migration/migrations/20250828070941.sql new file mode 100644 index 00000000..2f68a1b8 --- /dev/null +++ b/cmd/migration/migrations/20250828070941.sql @@ -0,0 +1,2 @@ +-- Modify "Item" table +ALTER TABLE "public"."Item" ALTER COLUMN "Infra_Id" TYPE integer; diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index b8ef29bb..7bb9cb01 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:m00Lt6P6Ck2i7UG8WlVBOWl5vmvSQZltNb1O7Z7zM+I= +h1:MjDAKEJK5Xf8q46mZR+EV6dJDBnGujQZyg98WDs/oJM= 20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= 20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= 20250825102900.sql h1:OAUnj87Wz7mrHykX14idePckUmRYa5UH0LylYDL76RI= @@ -8,4 +8,5 @@ h1:m00Lt6P6Ck2i7UG8WlVBOWl5vmvSQZltNb1O7Z7zM+I= 20250827024311.sql h1:eTlrQYcHa/jmb3qSZxgTB+7S4IXJ8B4yklUB36iZaDw= 20250827072230.sql h1:BfdTcToEYC8d30BS+1Su5Pz5Ecz8bh74F2j+Bh/r2BM= 20250827083322.sql h1:2MErE7W1JTjcxtgKJs/1iEF8kgV6vrcGrDVx/m6LwHQ= -20250828061151.sql h1:cZkYO1VHCc2RtOwP1yesHNG/p+o/zeOAGvqJRU4Q4Xc= +20250828061151.sql h1:CxTT3e9ZJ+Rp4UXE40SuFswVedlagKqDneFkg4BZkRs= +20250828070941.sql h1:IFzr/lvd99yOUdNXuW8wJNjBkXPhrHfMR2Ilx9+2MqE= diff --git a/internal/domain/main-entities/item/dto.go b/internal/domain/main-entities/item/dto.go index 78f5fa4b..c157b541 100644 --- a/internal/domain/main-entities/item/dto.go +++ b/internal/domain/main-entities/item/dto.go @@ -11,7 +11,7 @@ type CreateDto struct { Name string `json:"name"` ItemGroup_Code *string `json:"itemGroup_code"` Uom_Code *string `json:"uom_code"` - Infra_Id *int16 `json:"infra_id"` + Infra_Id *uint16 `json:"infra_id"` Stock *int `json:"stock"` } @@ -20,7 +20,7 @@ type ReadListDto struct { Name string `json:"name"` ItemGroup_Code *string `json:"itemGroup_code"` Uom_Code *string `json:"uom_code"` - Infra_Id *int16 `json:"infra_id"` + Infra_Id *uint16 `json:"infra_id"` Stock *int `json:"stock"` Page int `json:"page"` @@ -61,7 +61,7 @@ type ResponseDto struct { ItemGroup *eig.ItemGroup `json:"itemGroup,omitempty"` Uom_Code *string `json:"uom_code"` Uom *eu.Uom `json:"uom,omitempty"` - Infra_Id *int16 `json:"infra_id"` + Infra_Id *uint16 `json:"infra_id"` Stock *int `json:"stock"` } diff --git a/internal/domain/main-entities/item/entity.go b/internal/domain/main-entities/item/entity.go index 9eeb9425..c6cb0b8f 100644 --- a/internal/domain/main-entities/item/entity.go +++ b/internal/domain/main-entities/item/entity.go @@ -14,6 +14,6 @@ type Item struct { ItemGroup *eig.ItemGroup `json:"itemGroup,omitempty" gorm:"foreignKey:ItemGroup_Code;references:Code"` Uom_Code *string `json:"uom_code" gorm:"size:10"` Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` - Infra_Id *int16 `json:"infra_id"` + Infra_Id *uint16 `json:"infra_id"` Stock *int `json:"stock"` } From e827f3d1a90f17c40b70cb295afa60cff35025f7 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 28 Aug 2025 14:43:39 +0700 Subject: [PATCH 35/40] feat (medicine): wip --- internal/domain/main-entities/medicine/dto.go | 19 ++--- .../interface/main-handler/main-handler.go | 2 + .../main-handler/medicine/handler.go | 71 +++++++++++++++++++ .../use-case/main-use-case/medicine/case.go | 3 + .../use-case/main-use-case/medicine/helper.go | 51 +++++++++++++ .../main-use-case/medicine/middleware.go | 14 ---- pkg/use-case-helper/use-case-helper.go | 4 ++ 7 files changed, 141 insertions(+), 23 deletions(-) create mode 100644 internal/interface/main-handler/medicine/handler.go diff --git a/internal/domain/main-entities/medicine/dto.go b/internal/domain/main-entities/medicine/dto.go index 9e505b8b..a0ed5d1b 100644 --- a/internal/domain/main-entities/medicine/dto.go +++ b/internal/domain/main-entities/medicine/dto.go @@ -10,15 +10,16 @@ import ( ) type CreateDto struct { - Code string `json:"code"` - Name string `json:"name"` - MedicineGroup_Code *string `json:"medicineGroup_code"` - MedicineMethod_Code *string `json:"medicineMethod_code"` - Uom_Code *string `json:"uom_code"` - Dose uint8 `json:"dose"` - Infra_Id *uint16 `json:"infra_id"` - Stock *int `json:"stock"` - Item_Id *uint `json:"item_id"` + Code string `json:"code"` + Name string `json:"name"` + MedicineGroup_Code *string `json:"medicineGroup_code"` + MedicineMethod_Code *string `json:"medicineMethod_code"` + Uom_Code *string `json:"uom_code"` + Dose uint8 `json:"dose"` + Infra_Id *uint16 `json:"infra_id"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` + InsuranceCompany_Code *string `json:"insuranceCompany_code"` } type ReadListDto struct { diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 91b36af8..3044f79c 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -48,6 +48,7 @@ import ( itemprice "simrs-vx/internal/interface/main-handler/item-price" mcusrc "simrs-vx/internal/interface/main-handler/mcu-src" mcusrccategory "simrs-vx/internal/interface/main-handler/mcu-src-category" + medicine "simrs-vx/internal/interface/main-handler/medicine" medicinegroup "simrs-vx/internal/interface/main-handler/medicine-group" medicinemethod "simrs-vx/internal/interface/main-handler/medicine-method" pharmacycompany "simrs-vx/internal/interface/main-handler/pharmacy-company" @@ -122,6 +123,7 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/mcu-src", mcusrc.O) hc.RegCrud(r, "/v1/ethnic", ethnic.O) hc.RegCrud(r, "/v1/insurance-company", insurancecompany.O) + hc.RegCrud(r, "/v1/medicine", medicine.O) hc.RegCrud(r, "/v1/village", village.O) hc.RegCrud(r, "/v1/district", district.O) diff --git a/internal/interface/main-handler/medicine/handler.go b/internal/interface/main-handler/medicine/handler.go new file mode 100644 index 00000000..5a5b28e0 --- /dev/null +++ b/internal/interface/main-handler/medicine/handler.go @@ -0,0 +1,71 @@ +package medicine + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/medicine" + u "simrs-vx/internal/use-case/main-use-case/medicine" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/main-use-case/medicine/case.go b/internal/use-case/main-use-case/medicine/case.go index 20955134..3775751e 100644 --- a/internal/use-case/main-use-case/medicine/case.go +++ b/internal/use-case/main-use-case/medicine/case.go @@ -34,6 +34,9 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + if err := createItemWithDefaultPrice(&input, &event, tx); err != nil { + return err + } if resData, err := CreateData(input, &event, tx); err != nil { return err } else { diff --git a/internal/use-case/main-use-case/medicine/helper.go b/internal/use-case/main-use-case/medicine/helper.go index 2bd7ab7e..29a2f9ad 100644 --- a/internal/use-case/main-use-case/medicine/helper.go +++ b/internal/use-case/main-use-case/medicine/helper.go @@ -5,7 +5,17 @@ Any functions that are used internally by the use-case package medicine import ( + ei "simrs-vx/internal/domain/main-entities/item" + eip "simrs-vx/internal/domain/main-entities/item-price" e "simrs-vx/internal/domain/main-entities/medicine" + + ui "simrs-vx/internal/use-case/main-use-case/item" + uip "simrs-vx/internal/use-case/main-use-case/item-price" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" ) func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Medicine) { @@ -26,3 +36,44 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Medicine) { data.Infra_Id = inputSrc.Infra_Id data.Stock = inputSrc.Stock } + +func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + igcMed := "Medicine" + itemCreate := ei.CreateDto{ + Code: pu.AddPrefix("med-", input.Code), + Name: input.Name, + ItemGroup_Code: &igcMed, + Uom_Code: input.Uom_Code, + Infra_Id: input.Infra_Id, + Stock: input.Stock, + } + item, err := ui.CreateData(itemCreate, event, tx) + if err != nil { + return err + } + + input.Item_Id = &item.Id + return nil +} + +func createItemPrice(input *e.CreateDto, event *pl.Event, tx *gorm.DB, item_id *uint) error { + itemPriceCreate := eip.CreateDto{ + Item_Id: item_id, + Price: 0, + InsuranceCompany_Code: input.InsuranceCompany_Code, + } + _, err := uip.CreateData(itemPriceCreate, event, tx) + return err +} + +func createItemWithDefaultPrice(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + if err := createItem(input, event, tx); err != nil { + return err + } + + if err := createItemPrice(input, event, tx, input.Item_Id); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/medicine/middleware.go b/internal/use-case/main-use-case/medicine/middleware.go index 29a280cb..4c429bff 100644 --- a/internal/use-case/main-use-case/medicine/middleware.go +++ b/internal/use-case/main-use-case/medicine/middleware.go @@ -7,17 +7,3 @@ package medicine // CreateMw{Name: "check-data", Func: pm.CheckData}, // ) // } - -// func createItemAndItemPrice(input *e.CreateDto, data *e.Medicine, tx *gorm.DB) error { -// if input != nil { -// itemCreate := ei.CreateDto{ -// Code: input.Code, -// Name: input.Name, -// ItemGroup_Code: "Medicine", -// Uom_Code: input.Uom_Code, -// Infra_Id: input.Infra_Id, -// Stock: input.Stock, -// } -// } -// return nil -// } diff --git a/pkg/use-case-helper/use-case-helper.go b/pkg/use-case-helper/use-case-helper.go index b88db3b4..fadfa373 100644 --- a/pkg/use-case-helper/use-case-helper.go +++ b/pkg/use-case-helper/use-case-helper.go @@ -76,3 +76,7 @@ func HandleMiddlewareError(event *pl.Event, mwType, mwName string, logData inter } return pl.SetLogError(event, logData) } + +func AddPrefix(prefix string, str string) string { + return prefix + str +} From 034c8e79e22e5c3761fad04513109f1b7b0e0c18 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 28 Aug 2025 14:53:08 +0700 Subject: [PATCH 36/40] feat (item-price): change insurancecompany datatype --- cmd/migration/migrations/atlas.sum | 4 ++-- internal/domain/main-entities/item-price/dto.go | 8 ++++---- internal/domain/main-entities/item-price/entity.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index 7bb9cb01..e1837c02 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:MjDAKEJK5Xf8q46mZR+EV6dJDBnGujQZyg98WDs/oJM= +h1:NHJkMhPA1vP9q0CThwWTfKyvuE9V0Cn7WN+gtrIMw/8= 20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= 20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= 20250825102900.sql h1:OAUnj87Wz7mrHykX14idePckUmRYa5UH0LylYDL76RI= @@ -9,4 +9,4 @@ h1:MjDAKEJK5Xf8q46mZR+EV6dJDBnGujQZyg98WDs/oJM= 20250827072230.sql h1:BfdTcToEYC8d30BS+1Su5Pz5Ecz8bh74F2j+Bh/r2BM= 20250827083322.sql h1:2MErE7W1JTjcxtgKJs/1iEF8kgV6vrcGrDVx/m6LwHQ= 20250828061151.sql h1:CxTT3e9ZJ+Rp4UXE40SuFswVedlagKqDneFkg4BZkRs= -20250828070941.sql h1:IFzr/lvd99yOUdNXuW8wJNjBkXPhrHfMR2Ilx9+2MqE= +20250828070941.sql h1:Tr4Nal4jB9vFY6lpN2b9VIDKej91DWIgjD3K/dA69kc= diff --git a/internal/domain/main-entities/item-price/dto.go b/internal/domain/main-entities/item-price/dto.go index a86bd89f..730284e0 100644 --- a/internal/domain/main-entities/item-price/dto.go +++ b/internal/domain/main-entities/item-price/dto.go @@ -9,13 +9,13 @@ import ( type CreateDto struct { Item_Id *uint `json:"item_id"` Price float64 `json:"price"` - InsuranceCompany_Code *uint16 `json:"insuranceCompany_code"` + InsuranceCompany_Code *string `json:"insuranceCompany_code"` } type ReadListDto struct { Item_Id *uint `json:"item_id"` Price float64 `json:"price"` - InsuranceCompany_Code *uint16 `json:"insuranceCompany_code"` + InsuranceCompany_Code *string `json:"insuranceCompany_code"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -26,7 +26,7 @@ type ReadDetailDto struct { Id uint16 `json:"id"` Item_Id *uint `json:"item_id"` Price float64 `json:"price"` - InsuranceCompany_Code *uint16 `json:"insuranceCompany_code"` + InsuranceCompany_Code *string `json:"insuranceCompany_code"` } type UpdateDto struct { @@ -49,7 +49,7 @@ type ResponseDto struct { Item_Id *uint `json:"item_id"` Item *ei.Item `json:"item,omitempty"` Price float64 `json:"price"` - InsuranceCompany_Code *uint16 `json:"insuranceCompany_code"` + InsuranceCompany_Code *string `json:"insuranceCompany_code"` InsuranceCompany *eic.InsuranceCompany `json:"insuranceCompany,omitempty"` } diff --git a/internal/domain/main-entities/item-price/entity.go b/internal/domain/main-entities/item-price/entity.go index f25c21b1..a2a3ddcd 100644 --- a/internal/domain/main-entities/item-price/entity.go +++ b/internal/domain/main-entities/item-price/entity.go @@ -11,6 +11,6 @@ type ItemPrice struct { Item_Id *uint `json:"item_id"` Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` Price float64 `json:"price"` - InsuranceCompany_Code *uint16 `json:"insuranceCompany_code" gorm:"size:20"` + InsuranceCompany_Code *string `json:"insuranceCompany_code" gorm:"size:20"` InsuranceCompany *eic.InsuranceCompany `json:"insuranceCompany,omitempty" gorm:"foreignKey:InsuranceCompany_Code;references:Code"` } From 2073165f820ed6b01276baebc4c00ea6fee8cd18 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 28 Aug 2025 16:04:15 +0700 Subject: [PATCH 37/40] add crud for medicine, medicinemix, medicinemixitem, device, material, medicalactionsrc, medicalactionsrcitem, doctorfee --- .../interface/main-handler/device/handler.go | 71 +++++ .../main-handler/doctor-fee/handler.go | 71 +++++ .../interface/main-handler/main-handler.go | 14 + .../main-handler/material/handler.go | 71 +++++ .../medical-action-src-item/handler.go | 71 +++++ .../medical-action-src/handler.go | 71 +++++ .../main-handler/medicine-mix-item/handler.go | 71 +++++ .../main-handler/medicine-mix/handler.go | 71 +++++ .../use-case/main-use-case/device/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/device/helper.go | 24 ++ internal/use-case/main-use-case/device/lib.go | 149 ++++++++++ .../main-use-case/device/middleware-runner.go | 103 +++++++ .../main-use-case/device/middleware.go | 9 + .../use-case/main-use-case/device/tycovar.go | 44 +++ .../use-case/main-use-case/doctor-fee/case.go | 275 ++++++++++++++++++ .../main-use-case/doctor-fee/helper.go | 24 ++ .../use-case/main-use-case/doctor-fee/lib.go | 149 ++++++++++ .../doctor-fee/middleware-runner.go | 103 +++++++ .../main-use-case/doctor-fee/middleware.go | 9 + .../main-use-case/doctor-fee/tycovar.go | 44 +++ .../main-use-case/item-price/helper.go | 1 + .../use-case/main-use-case/material/case.go | 275 ++++++++++++++++++ .../use-case/main-use-case/material/helper.go | 25 ++ .../use-case/main-use-case/material/lib.go | 149 ++++++++++ .../material/middleware-runner.go | 103 +++++++ .../main-use-case/material/middleware.go | 9 + .../main-use-case/material/tycovar.go | 44 +++ .../medical-action-src-item/case.go | 275 ++++++++++++++++++ .../medical-action-src-item/helper.go | 22 ++ .../medical-action-src-item/lib.go | 149 ++++++++++ .../middleware-runner.go | 103 +++++++ .../medical-action-src-item/middleware.go | 9 + .../medical-action-src-item/tycovar.go | 44 +++ .../main-use-case/medical-action-src/case.go | 275 ++++++++++++++++++ .../medical-action-src/helper.go | 23 ++ .../main-use-case/medical-action-src/lib.go | 149 ++++++++++ .../medical-action-src/middleware-runner.go | 103 +++++++ .../medical-action-src/middleware.go | 9 + .../medical-action-src/tycovar.go | 44 +++ .../main-use-case/medicine-mix-item/case.go | 275 ++++++++++++++++++ .../main-use-case/medicine-mix-item/helper.go | 23 ++ .../main-use-case/medicine-mix-item/lib.go | 149 ++++++++++ .../medicine-mix-item/middleware-runner.go | 103 +++++++ .../medicine-mix-item/middleware.go | 9 + .../medicine-mix-item/tycovar.go | 44 +++ .../main-use-case/medicine-mix/case.go | 275 ++++++++++++++++++ .../main-use-case/medicine-mix/helper.go | 21 ++ .../main-use-case/medicine-mix/lib.go | 149 ++++++++++ .../medicine-mix/middleware-runner.go | 103 +++++++ .../main-use-case/medicine-mix/middleware.go | 9 + .../main-use-case/medicine-mix/tycovar.go | 44 +++ .../use-case/main-use-case/medicine/helper.go | 1 + .../use-case/main-use-case/medicine/lib.go | 1 + 53 files changed, 4736 insertions(+) create mode 100644 internal/interface/main-handler/device/handler.go create mode 100644 internal/interface/main-handler/doctor-fee/handler.go create mode 100644 internal/interface/main-handler/material/handler.go create mode 100644 internal/interface/main-handler/medical-action-src-item/handler.go create mode 100644 internal/interface/main-handler/medical-action-src/handler.go create mode 100644 internal/interface/main-handler/medicine-mix-item/handler.go create mode 100644 internal/interface/main-handler/medicine-mix/handler.go create mode 100644 internal/use-case/main-use-case/device/case.go create mode 100644 internal/use-case/main-use-case/device/helper.go create mode 100644 internal/use-case/main-use-case/device/lib.go create mode 100644 internal/use-case/main-use-case/device/middleware-runner.go create mode 100644 internal/use-case/main-use-case/device/middleware.go create mode 100644 internal/use-case/main-use-case/device/tycovar.go create mode 100644 internal/use-case/main-use-case/doctor-fee/case.go create mode 100644 internal/use-case/main-use-case/doctor-fee/helper.go create mode 100644 internal/use-case/main-use-case/doctor-fee/lib.go create mode 100644 internal/use-case/main-use-case/doctor-fee/middleware-runner.go create mode 100644 internal/use-case/main-use-case/doctor-fee/middleware.go create mode 100644 internal/use-case/main-use-case/doctor-fee/tycovar.go create mode 100644 internal/use-case/main-use-case/material/case.go create mode 100644 internal/use-case/main-use-case/material/helper.go create mode 100644 internal/use-case/main-use-case/material/lib.go create mode 100644 internal/use-case/main-use-case/material/middleware-runner.go create mode 100644 internal/use-case/main-use-case/material/middleware.go create mode 100644 internal/use-case/main-use-case/material/tycovar.go create mode 100644 internal/use-case/main-use-case/medical-action-src-item/case.go create mode 100644 internal/use-case/main-use-case/medical-action-src-item/helper.go create mode 100644 internal/use-case/main-use-case/medical-action-src-item/lib.go create mode 100644 internal/use-case/main-use-case/medical-action-src-item/middleware-runner.go create mode 100644 internal/use-case/main-use-case/medical-action-src-item/middleware.go create mode 100644 internal/use-case/main-use-case/medical-action-src-item/tycovar.go create mode 100644 internal/use-case/main-use-case/medical-action-src/case.go create mode 100644 internal/use-case/main-use-case/medical-action-src/helper.go create mode 100644 internal/use-case/main-use-case/medical-action-src/lib.go create mode 100644 internal/use-case/main-use-case/medical-action-src/middleware-runner.go create mode 100644 internal/use-case/main-use-case/medical-action-src/middleware.go create mode 100644 internal/use-case/main-use-case/medical-action-src/tycovar.go create mode 100644 internal/use-case/main-use-case/medicine-mix-item/case.go create mode 100644 internal/use-case/main-use-case/medicine-mix-item/helper.go create mode 100644 internal/use-case/main-use-case/medicine-mix-item/lib.go create mode 100644 internal/use-case/main-use-case/medicine-mix-item/middleware-runner.go create mode 100644 internal/use-case/main-use-case/medicine-mix-item/middleware.go create mode 100644 internal/use-case/main-use-case/medicine-mix-item/tycovar.go create mode 100644 internal/use-case/main-use-case/medicine-mix/case.go create mode 100644 internal/use-case/main-use-case/medicine-mix/helper.go create mode 100644 internal/use-case/main-use-case/medicine-mix/lib.go create mode 100644 internal/use-case/main-use-case/medicine-mix/middleware-runner.go create mode 100644 internal/use-case/main-use-case/medicine-mix/middleware.go create mode 100644 internal/use-case/main-use-case/medicine-mix/tycovar.go diff --git a/internal/interface/main-handler/device/handler.go b/internal/interface/main-handler/device/handler.go new file mode 100644 index 00000000..1a3cb18d --- /dev/null +++ b/internal/interface/main-handler/device/handler.go @@ -0,0 +1,71 @@ +package device + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/device" + u "simrs-vx/internal/use-case/main-use-case/device" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/doctor-fee/handler.go b/internal/interface/main-handler/doctor-fee/handler.go new file mode 100644 index 00000000..66bf88e5 --- /dev/null +++ b/internal/interface/main-handler/doctor-fee/handler.go @@ -0,0 +1,71 @@ +package doctorfee + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/doctor-fee" + u "simrs-vx/internal/use-case/main-use-case/doctor-fee" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 3044f79c..4b5fd1f1 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -6,6 +6,8 @@ import ( /******************** main / transaction ********************/ auth "simrs-vx/internal/interface/main-handler/authentication" counter "simrs-vx/internal/interface/main-handler/counter" + medicicinemix "simrs-vx/internal/interface/main-handler/medicine-mix" + medicicinemixitem "simrs-vx/internal/interface/main-handler/medicine-mix-item" practiceschedule "simrs-vx/internal/interface/main-handler/practice-schedule" /******************** actor ********************/ @@ -35,9 +37,11 @@ import ( zlc "simrs-vx/pkg/zerolog-ctx" /******************** sources ********************/ + device "simrs-vx/internal/interface/main-handler/device" diagnosesrc "simrs-vx/internal/interface/main-handler/diagnose-src" division "simrs-vx/internal/interface/main-handler/division" divisionposition "simrs-vx/internal/interface/main-handler/division-position" + doctorfee "simrs-vx/internal/interface/main-handler/doctor-fee" ethnic "simrs-vx/internal/interface/main-handler/ethnic" infra "simrs-vx/internal/interface/main-handler/infra" infragroup "simrs-vx/internal/interface/main-handler/infra-group" @@ -46,8 +50,11 @@ import ( item "simrs-vx/internal/interface/main-handler/item" itemgroup "simrs-vx/internal/interface/main-handler/item-group" itemprice "simrs-vx/internal/interface/main-handler/item-price" + material "simrs-vx/internal/interface/main-handler/material" mcusrc "simrs-vx/internal/interface/main-handler/mcu-src" mcusrccategory "simrs-vx/internal/interface/main-handler/mcu-src-category" + medicalactionsrc "simrs-vx/internal/interface/main-handler/medical-action-src" + medicalactionsrcitem "simrs-vx/internal/interface/main-handler/medical-action-src-item" medicine "simrs-vx/internal/interface/main-handler/medicine" medicinegroup "simrs-vx/internal/interface/main-handler/medicine-group" medicinemethod "simrs-vx/internal/interface/main-handler/medicine-method" @@ -83,6 +90,8 @@ func SetRoutes() http.Handler { hk.Route("POST /v1/authentication/logout", r, auth.GuardMW, auth.Logout) hc.RegCrud(r, "/v1/practice-schedule", practiceschedule.O) hc.RegCrud(r, "/v1/counter", counter.O) + hc.RegCrud(r, "/v1/medicine-mix", medicicinemix.O) + hc.RegCrud(r, "/v1/medicine-mix-item", medicicinemixitem.O) /******************** actor ********************/ hk.GroupRoutes("/v1/user", r, hk.MapHandlerFunc{ @@ -124,6 +133,11 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/ethnic", ethnic.O) hc.RegCrud(r, "/v1/insurance-company", insurancecompany.O) hc.RegCrud(r, "/v1/medicine", medicine.O) + hc.RegCrud(r, "/v1/device", device.O) + hc.RegCrud(r, "/v1/material", material.O) + hc.RegCrud(r, "/v1/doctor-fee", doctorfee.O) + hc.RegCrud(r, "/v1/medical-action-src", medicalactionsrc.O) + hc.RegCrud(r, "/v1/medical-action-src-item", medicalactionsrcitem.O) hc.RegCrud(r, "/v1/village", village.O) hc.RegCrud(r, "/v1/district", district.O) diff --git a/internal/interface/main-handler/material/handler.go b/internal/interface/main-handler/material/handler.go new file mode 100644 index 00000000..2b152625 --- /dev/null +++ b/internal/interface/main-handler/material/handler.go @@ -0,0 +1,71 @@ +package material + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/material" + u "simrs-vx/internal/use-case/main-use-case/material" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/medical-action-src-item/handler.go b/internal/interface/main-handler/medical-action-src-item/handler.go new file mode 100644 index 00000000..9314b64b --- /dev/null +++ b/internal/interface/main-handler/medical-action-src-item/handler.go @@ -0,0 +1,71 @@ +package medicalactionsrcitem + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/medical-action-src-item" + u "simrs-vx/internal/use-case/main-use-case/medical-action-src-item" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/medical-action-src/handler.go b/internal/interface/main-handler/medical-action-src/handler.go new file mode 100644 index 00000000..c8b24706 --- /dev/null +++ b/internal/interface/main-handler/medical-action-src/handler.go @@ -0,0 +1,71 @@ +package medicalactionsrc + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/medical-action-src" + u "simrs-vx/internal/use-case/main-use-case/medical-action-src" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/medicine-mix-item/handler.go b/internal/interface/main-handler/medicine-mix-item/handler.go new file mode 100644 index 00000000..2b8022fa --- /dev/null +++ b/internal/interface/main-handler/medicine-mix-item/handler.go @@ -0,0 +1,71 @@ +package medicinemixitem + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/medicine-mix-item" + u "simrs-vx/internal/use-case/main-use-case/medicine-mix-item" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/medicine-mix/handler.go b/internal/interface/main-handler/medicine-mix/handler.go new file mode 100644 index 00000000..1adb6216 --- /dev/null +++ b/internal/interface/main-handler/medicine-mix/handler.go @@ -0,0 +1,71 @@ +package medicinemix + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/medicine-mix" + u "simrs-vx/internal/use-case/main-use-case/medicine-mix" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/main-use-case/device/case.go b/internal/use-case/main-use-case/device/case.go new file mode 100644 index 00000000..cb40c1eb --- /dev/null +++ b/internal/use-case/main-use-case/device/case.go @@ -0,0 +1,275 @@ +package device + +import ( + e "simrs-vx/internal/domain/main-entities/device" + "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" +) + +const source = "device" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Device{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Device + var dataList []e.Device + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Device + 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: uint16(input.Id)} + var data *e.Device + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Device + 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 + +} diff --git a/internal/use-case/main-use-case/device/helper.go b/internal/use-case/main-use-case/device/helper.go new file mode 100644 index 00000000..137425b1 --- /dev/null +++ b/internal/use-case/main-use-case/device/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package device + +import ( + e "simrs-vx/internal/domain/main-entities/device" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Device) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Uom_Code = inputSrc.Uom_Code + data.Item_Id = inputSrc.Item_Id +} diff --git a/internal/use-case/main-use-case/device/lib.go b/internal/use-case/main-use-case/device/lib.go new file mode 100644 index 00000000..ae369a58 --- /dev/null +++ b/internal/use-case/main-use-case/device/lib.go @@ -0,0 +1,149 @@ +package device + +import ( + e "simrs-vx/internal/domain/main-entities/device" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Device, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Device{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Device, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Device{} + 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.Device{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Device, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Device{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Device, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Device, 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 +} diff --git a/internal/use-case/main-use-case/device/middleware-runner.go b/internal/use-case/main-use-case/device/middleware-runner.go new file mode 100644 index 00000000..de92f305 --- /dev/null +++ b/internal/use-case/main-use-case/device/middleware-runner.go @@ -0,0 +1,103 @@ +package device + +import ( + e "simrs-vx/internal/domain/main-entities/device" + 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.Device) 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.Device) 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.Device) 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.Device) 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.Device) 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 +} diff --git a/internal/use-case/main-use-case/device/middleware.go b/internal/use-case/main-use-case/device/middleware.go new file mode 100644 index 00000000..53d4872e --- /dev/null +++ b/internal/use-case/main-use-case/device/middleware.go @@ -0,0 +1,9 @@ +package device + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/device/tycovar.go b/internal/use-case/main-use-case/device/tycovar.go new file mode 100644 index 00000000..32c9f777 --- /dev/null +++ b/internal/use-case/main-use-case/device/tycovar.go @@ -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 device + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/device" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Device, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Device, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Device, 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 diff --git a/internal/use-case/main-use-case/doctor-fee/case.go b/internal/use-case/main-use-case/doctor-fee/case.go new file mode 100644 index 00000000..449349a1 --- /dev/null +++ b/internal/use-case/main-use-case/doctor-fee/case.go @@ -0,0 +1,275 @@ +package doctorfee + +import ( + e "simrs-vx/internal/domain/main-entities/doctor-fee" + "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" +) + +const source = "doctor-fee" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.DoctorFee{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.DoctorFee + var dataList []e.DoctorFee + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.DoctorFee + 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: uint16(input.Id)} + var data *e.DoctorFee + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.DoctorFee + 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 + +} diff --git a/internal/use-case/main-use-case/doctor-fee/helper.go b/internal/use-case/main-use-case/doctor-fee/helper.go new file mode 100644 index 00000000..26ac7bec --- /dev/null +++ b/internal/use-case/main-use-case/doctor-fee/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package doctorfee + +import ( + e "simrs-vx/internal/domain/main-entities/doctor-fee" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.DoctorFee) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Doctor_Id = inputSrc.Doctor_Id + data.FeeTypeCode = inputSrc.FeeTypeCode + data.Price = inputSrc.Price + data.Item_Id = inputSrc.Item_Id +} diff --git a/internal/use-case/main-use-case/doctor-fee/lib.go b/internal/use-case/main-use-case/doctor-fee/lib.go new file mode 100644 index 00000000..f34ab9d7 --- /dev/null +++ b/internal/use-case/main-use-case/doctor-fee/lib.go @@ -0,0 +1,149 @@ +package doctorfee + +import ( + e "simrs-vx/internal/domain/main-entities/doctor-fee" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.DoctorFee, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.DoctorFee{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.DoctorFee, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.DoctorFee{} + 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.DoctorFee{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.DoctorFee, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.DoctorFee{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.DoctorFee, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.DoctorFee, 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 +} diff --git a/internal/use-case/main-use-case/doctor-fee/middleware-runner.go b/internal/use-case/main-use-case/doctor-fee/middleware-runner.go new file mode 100644 index 00000000..e51d6a68 --- /dev/null +++ b/internal/use-case/main-use-case/doctor-fee/middleware-runner.go @@ -0,0 +1,103 @@ +package doctorfee + +import ( + e "simrs-vx/internal/domain/main-entities/doctor-fee" + 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.DoctorFee) 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.DoctorFee) 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.DoctorFee) 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.DoctorFee) 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.DoctorFee) 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 +} diff --git a/internal/use-case/main-use-case/doctor-fee/middleware.go b/internal/use-case/main-use-case/doctor-fee/middleware.go new file mode 100644 index 00000000..20b69a20 --- /dev/null +++ b/internal/use-case/main-use-case/doctor-fee/middleware.go @@ -0,0 +1,9 @@ +package doctorfee + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/doctor-fee/tycovar.go b/internal/use-case/main-use-case/doctor-fee/tycovar.go new file mode 100644 index 00000000..9a92ed70 --- /dev/null +++ b/internal/use-case/main-use-case/doctor-fee/tycovar.go @@ -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 doctorfee + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/doctor-fee" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.DoctorFee, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.DoctorFee, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.DoctorFee, 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 diff --git a/internal/use-case/main-use-case/item-price/helper.go b/internal/use-case/main-use-case/item-price/helper.go index eb839c19..f0bab4ae 100644 --- a/internal/use-case/main-use-case/item-price/helper.go +++ b/internal/use-case/main-use-case/item-price/helper.go @@ -19,4 +19,5 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ItemPrice) { data.Item_Id = inputSrc.Item_Id data.Price = inputSrc.Price + data.InsuranceCompany_Code = inputSrc.InsuranceCompany_Code } diff --git a/internal/use-case/main-use-case/material/case.go b/internal/use-case/main-use-case/material/case.go new file mode 100644 index 00000000..f855f044 --- /dev/null +++ b/internal/use-case/main-use-case/material/case.go @@ -0,0 +1,275 @@ +package material + +import ( + e "simrs-vx/internal/domain/main-entities/material" + "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" +) + +const source = "material" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Material{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Material + var dataList []e.Material + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Material + 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: uint16(input.Id)} + var data *e.Material + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.Material + 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 + +} diff --git a/internal/use-case/main-use-case/material/helper.go b/internal/use-case/main-use-case/material/helper.go new file mode 100644 index 00000000..4e674eb9 --- /dev/null +++ b/internal/use-case/main-use-case/material/helper.go @@ -0,0 +1,25 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package material + +import ( + e "simrs-vx/internal/domain/main-entities/material" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Material) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Uom_Code = inputSrc.Uom_Code + data.Stock = inputSrc.Stock + data.Item_Id = *inputSrc.Item_Id +} diff --git a/internal/use-case/main-use-case/material/lib.go b/internal/use-case/main-use-case/material/lib.go new file mode 100644 index 00000000..ab114241 --- /dev/null +++ b/internal/use-case/main-use-case/material/lib.go @@ -0,0 +1,149 @@ +package material + +import ( + e "simrs-vx/internal/domain/main-entities/material" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Material, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Material{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Material, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Material{} + 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.Material{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.Material, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Material{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.Material, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.Material, 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 +} diff --git a/internal/use-case/main-use-case/material/middleware-runner.go b/internal/use-case/main-use-case/material/middleware-runner.go new file mode 100644 index 00000000..d131ca59 --- /dev/null +++ b/internal/use-case/main-use-case/material/middleware-runner.go @@ -0,0 +1,103 @@ +package material + +import ( + e "simrs-vx/internal/domain/main-entities/material" + 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.Material) 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.Material) 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.Material) 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.Material) 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.Material) 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 +} diff --git a/internal/use-case/main-use-case/material/middleware.go b/internal/use-case/main-use-case/material/middleware.go new file mode 100644 index 00000000..39800926 --- /dev/null +++ b/internal/use-case/main-use-case/material/middleware.go @@ -0,0 +1,9 @@ +package material + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/material/tycovar.go b/internal/use-case/main-use-case/material/tycovar.go new file mode 100644 index 00000000..5b503d76 --- /dev/null +++ b/internal/use-case/main-use-case/material/tycovar.go @@ -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 material + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/material" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Material, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Material, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Material, 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 diff --git a/internal/use-case/main-use-case/medical-action-src-item/case.go b/internal/use-case/main-use-case/medical-action-src-item/case.go new file mode 100644 index 00000000..e811714d --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src-item/case.go @@ -0,0 +1,275 @@ +package medicalactionsrcitem + +import ( + e "simrs-vx/internal/domain/main-entities/medical-action-src-item" + "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" +) + +const source = "medical-action-src-item" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.MedicalActionSrcItem{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.MedicalActionSrcItem + var dataList []e.MedicalActionSrcItem + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.MedicalActionSrcItem + 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: uint16(input.Id)} + var data *e.MedicalActionSrcItem + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.MedicalActionSrcItem + 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 + +} diff --git a/internal/use-case/main-use-case/medical-action-src-item/helper.go b/internal/use-case/main-use-case/medical-action-src-item/helper.go new file mode 100644 index 00000000..385b0f53 --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src-item/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package medicalactionsrcitem + +import ( + e "simrs-vx/internal/domain/main-entities/medical-action-src-item" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicalActionSrcItem) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + data.MedicalActionSrc_Id = inputSrc.MedicalActionSrc_Id + data.ProcedureSrc_Id = inputSrc.ProcedureSrc_Id + data.Item_Id = inputSrc.Item_Id +} diff --git a/internal/use-case/main-use-case/medical-action-src-item/lib.go b/internal/use-case/main-use-case/medical-action-src-item/lib.go new file mode 100644 index 00000000..f294c118 --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src-item/lib.go @@ -0,0 +1,149 @@ +package medicalactionsrcitem + +import ( + e "simrs-vx/internal/domain/main-entities/medical-action-src-item" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.MedicalActionSrcItem, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.MedicalActionSrcItem{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.MedicalActionSrcItem, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.MedicalActionSrcItem{} + 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.MedicalActionSrcItem{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.MedicalActionSrcItem, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.MedicalActionSrcItem{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.MedicalActionSrcItem, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.MedicalActionSrcItem, 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 +} diff --git a/internal/use-case/main-use-case/medical-action-src-item/middleware-runner.go b/internal/use-case/main-use-case/medical-action-src-item/middleware-runner.go new file mode 100644 index 00000000..8ac26507 --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src-item/middleware-runner.go @@ -0,0 +1,103 @@ +package medicalactionsrcitem + +import ( + e "simrs-vx/internal/domain/main-entities/medical-action-src-item" + 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.MedicalActionSrcItem) 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.MedicalActionSrcItem) 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.MedicalActionSrcItem) 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.MedicalActionSrcItem) 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.MedicalActionSrcItem) 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 +} diff --git a/internal/use-case/main-use-case/medical-action-src-item/middleware.go b/internal/use-case/main-use-case/medical-action-src-item/middleware.go new file mode 100644 index 00000000..9e93530a --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src-item/middleware.go @@ -0,0 +1,9 @@ +package medicalactionsrcitem + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/medical-action-src-item/tycovar.go b/internal/use-case/main-use-case/medical-action-src-item/tycovar.go new file mode 100644 index 00000000..c7966901 --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src-item/tycovar.go @@ -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 medicalactionsrcitem + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/medical-action-src-item" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.MedicalActionSrcItem, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.MedicalActionSrcItem, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.MedicalActionSrcItem, 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 diff --git a/internal/use-case/main-use-case/medical-action-src/case.go b/internal/use-case/main-use-case/medical-action-src/case.go new file mode 100644 index 00000000..0b22aa7e --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src/case.go @@ -0,0 +1,275 @@ +package medicalactionsrc + +import ( + e "simrs-vx/internal/domain/main-entities/medical-action-src" + "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" +) + +const source = "medical-action-src" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.MedicalActionSrc{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.MedicalActionSrc + var dataList []e.MedicalActionSrc + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.MedicalActionSrc + 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: uint16(input.Id)} + var data *e.MedicalActionSrc + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.MedicalActionSrc + 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 + +} diff --git a/internal/use-case/main-use-case/medical-action-src/helper.go b/internal/use-case/main-use-case/medical-action-src/helper.go new file mode 100644 index 00000000..22c0d26d --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package medicalactionsrc + +import ( + e "simrs-vx/internal/domain/main-entities/medical-action-src" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicalActionSrc) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Item_Id = inputSrc.Item_Id +} diff --git a/internal/use-case/main-use-case/medical-action-src/lib.go b/internal/use-case/main-use-case/medical-action-src/lib.go new file mode 100644 index 00000000..b0cdbdc0 --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src/lib.go @@ -0,0 +1,149 @@ +package medicalactionsrc + +import ( + e "simrs-vx/internal/domain/main-entities/medical-action-src" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.MedicalActionSrc, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.MedicalActionSrc{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.MedicalActionSrc, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.MedicalActionSrc{} + 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.MedicalActionSrc{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.MedicalActionSrc, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.MedicalActionSrc{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.MedicalActionSrc, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.MedicalActionSrc, 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 +} diff --git a/internal/use-case/main-use-case/medical-action-src/middleware-runner.go b/internal/use-case/main-use-case/medical-action-src/middleware-runner.go new file mode 100644 index 00000000..503758fc --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src/middleware-runner.go @@ -0,0 +1,103 @@ +package medicalactionsrc + +import ( + e "simrs-vx/internal/domain/main-entities/medical-action-src" + 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.MedicalActionSrc) 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.MedicalActionSrc) 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.MedicalActionSrc) 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.MedicalActionSrc) 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.MedicalActionSrc) 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 +} diff --git a/internal/use-case/main-use-case/medical-action-src/middleware.go b/internal/use-case/main-use-case/medical-action-src/middleware.go new file mode 100644 index 00000000..734b104a --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src/middleware.go @@ -0,0 +1,9 @@ +package medicalactionsrc + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/medical-action-src/tycovar.go b/internal/use-case/main-use-case/medical-action-src/tycovar.go new file mode 100644 index 00000000..141e1f86 --- /dev/null +++ b/internal/use-case/main-use-case/medical-action-src/tycovar.go @@ -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 medicalactionsrc + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/medical-action-src" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.MedicalActionSrc, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.MedicalActionSrc, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.MedicalActionSrc, 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 diff --git a/internal/use-case/main-use-case/medicine-mix-item/case.go b/internal/use-case/main-use-case/medicine-mix-item/case.go new file mode 100644 index 00000000..1b6dfc6e --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix-item/case.go @@ -0,0 +1,275 @@ +package medicinemixitem + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-mix-item" + "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" +) + +const source = "medicine-mix-item" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.MedicineMixItem{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.MedicineMixItem + var dataList []e.MedicineMixItem + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.MedicineMixItem + 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: uint16(input.Id)} + var data *e.MedicineMixItem + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.MedicineMixItem + 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 + +} diff --git a/internal/use-case/main-use-case/medicine-mix-item/helper.go b/internal/use-case/main-use-case/medicine-mix-item/helper.go new file mode 100644 index 00000000..d4ac8020 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix-item/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package medicinemixitem + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-mix-item" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicineMixItem) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.MedicineMix_Id = inputSrc.MedicineMix_Id + data.Medicine_Id = inputSrc.Medicine_Id + data.Dose = inputSrc.Dose +} diff --git a/internal/use-case/main-use-case/medicine-mix-item/lib.go b/internal/use-case/main-use-case/medicine-mix-item/lib.go new file mode 100644 index 00000000..739c6a7a --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix-item/lib.go @@ -0,0 +1,149 @@ +package medicinemixitem + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-mix-item" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.MedicineMixItem, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.MedicineMixItem{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.MedicineMixItem, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.MedicineMixItem{} + 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.MedicineMixItem{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.MedicineMixItem, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.MedicineMixItem{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.MedicineMixItem, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.MedicineMixItem, 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 +} diff --git a/internal/use-case/main-use-case/medicine-mix-item/middleware-runner.go b/internal/use-case/main-use-case/medicine-mix-item/middleware-runner.go new file mode 100644 index 00000000..0a75aaf8 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix-item/middleware-runner.go @@ -0,0 +1,103 @@ +package medicinemixitem + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-mix-item" + 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.MedicineMixItem) 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.MedicineMixItem) 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.MedicineMixItem) 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.MedicineMixItem) 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.MedicineMixItem) 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 +} diff --git a/internal/use-case/main-use-case/medicine-mix-item/middleware.go b/internal/use-case/main-use-case/medicine-mix-item/middleware.go new file mode 100644 index 00000000..974a1f2c --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix-item/middleware.go @@ -0,0 +1,9 @@ +package medicinemixitem + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/medicine-mix-item/tycovar.go b/internal/use-case/main-use-case/medicine-mix-item/tycovar.go new file mode 100644 index 00000000..ad05cc4d --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix-item/tycovar.go @@ -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 medicinemixitem + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/medicine-mix-item" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.MedicineMixItem, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.MedicineMixItem, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.MedicineMixItem, 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 diff --git a/internal/use-case/main-use-case/medicine-mix/case.go b/internal/use-case/main-use-case/medicine-mix/case.go new file mode 100644 index 00000000..13602162 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix/case.go @@ -0,0 +1,275 @@ +package medicinemix + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-mix" + "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" +) + +const source = "medicine-mix" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.MedicineMix{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // 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 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 { + return err + } + + 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: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.MedicineMix + var dataList []e.MedicineMix + 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), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.MedicineMix + 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: uint16(input.Id)} + var data *e.MedicineMix + 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) { + rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + var data *e.MedicineMix + 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 + +} diff --git a/internal/use-case/main-use-case/medicine-mix/helper.go b/internal/use-case/main-use-case/medicine-mix/helper.go new file mode 100644 index 00000000..bd0892e0 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix/helper.go @@ -0,0 +1,21 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package medicinemix + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-mix" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicineMix) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/medicine-mix/lib.go b/internal/use-case/main-use-case/medicine-mix/lib.go new file mode 100644 index 00000000..2c20870c --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix/lib.go @@ -0,0 +1,149 @@ +package medicinemix + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-mix" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.MedicineMix, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.MedicineMix{} + setData(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return nil, pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.MedicineMix, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.MedicineMix{} + 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.MedicineMix{}). + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, nil, pl.SetLogError(event, input) + + } + 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.MedicineMix, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.MedicineMix{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.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(input e.UpdateDto, data *e.MedicineMix, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "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 DeleteData(data *e.MedicineMix, 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 +} diff --git a/internal/use-case/main-use-case/medicine-mix/middleware-runner.go b/internal/use-case/main-use-case/medicine-mix/middleware-runner.go new file mode 100644 index 00000000..b5649d69 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix/middleware-runner.go @@ -0,0 +1,103 @@ +package medicinemix + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-mix" + 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.MedicineMix) 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.MedicineMix) 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.MedicineMix) 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.MedicineMix) 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.MedicineMix) 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 +} diff --git a/internal/use-case/main-use-case/medicine-mix/middleware.go b/internal/use-case/main-use-case/medicine-mix/middleware.go new file mode 100644 index 00000000..06c1a9f0 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix/middleware.go @@ -0,0 +1,9 @@ +package medicinemix + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/main-use-case/medicine-mix/tycovar.go b/internal/use-case/main-use-case/medicine-mix/tycovar.go new file mode 100644 index 00000000..4243a4d3 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-mix/tycovar.go @@ -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 medicinemix + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/medicine-mix" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.MedicineMix, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.MedicineMix, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.MedicineMix, 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 diff --git a/internal/use-case/main-use-case/medicine/helper.go b/internal/use-case/main-use-case/medicine/helper.go index 29a2f9ad..1414b966 100644 --- a/internal/use-case/main-use-case/medicine/helper.go +++ b/internal/use-case/main-use-case/medicine/helper.go @@ -35,6 +35,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Medicine) { data.Dose = inputSrc.Dose data.Infra_Id = inputSrc.Infra_Id data.Stock = inputSrc.Stock + data.Item_Id = inputSrc.Item_Id } func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { diff --git a/internal/use-case/main-use-case/medicine/lib.go b/internal/use-case/main-use-case/medicine/lib.go index cbf756d4..a66e7cd0 100644 --- a/internal/use-case/main-use-case/medicine/lib.go +++ b/internal/use-case/main-use-case/medicine/lib.go @@ -90,6 +90,7 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e tx = dg.I } + tx = tx.Preload("Item") if err := tx.First(&data, input.Id).Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { return nil, processedErr From 691f7078adbf390a6a0fb5be7eab613a60967bac Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 28 Aug 2025 16:12:48 +0700 Subject: [PATCH 38/40] feat (material): change item id datatype --- internal/domain/main-entities/material/dto.go | 2 +- internal/domain/main-entities/material/entity.go | 2 +- internal/use-case/main-use-case/material/helper.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/domain/main-entities/material/dto.go b/internal/domain/main-entities/material/dto.go index e466e5df..ec565e59 100644 --- a/internal/domain/main-entities/material/dto.go +++ b/internal/domain/main-entities/material/dto.go @@ -57,7 +57,7 @@ type ResponseDto struct { Uom_Code string `json:"uom_code"` Uom *eu.Uom `json:"uom,omitempty"` Stock *int `json:"stock"` - Item_Id uint `json:"item_id"` + Item_Id *uint `json:"item_id"` Item *ei.Item `json:"item,omitempty"` } diff --git a/internal/domain/main-entities/material/entity.go b/internal/domain/main-entities/material/entity.go index 8f10d0e5..c14aac78 100644 --- a/internal/domain/main-entities/material/entity.go +++ b/internal/domain/main-entities/material/entity.go @@ -13,6 +13,6 @@ type Material struct { Uom_Code string `json:"uom_code" gorm:"size:10"` Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` Stock *int `json:"stock"` - Item_Id uint `json:"item_id"` + Item_Id *uint `json:"item_id"` Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` } diff --git a/internal/use-case/main-use-case/material/helper.go b/internal/use-case/main-use-case/material/helper.go index 4e674eb9..11b4900c 100644 --- a/internal/use-case/main-use-case/material/helper.go +++ b/internal/use-case/main-use-case/material/helper.go @@ -21,5 +21,5 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Material) { data.Name = inputSrc.Name data.Uom_Code = inputSrc.Uom_Code data.Stock = inputSrc.Stock - data.Item_Id = *inputSrc.Item_Id + data.Item_Id = inputSrc.Item_Id } From 78c2b2eada1632493d9944d8a2f01cc06ff4cc73 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 28 Aug 2025 16:15:32 +0700 Subject: [PATCH 39/40] feat (doctor-fee): change naming --- .../domain/main-entities/doctor-fee/dto.go | 50 +++++++++---------- .../domain/main-entities/doctor-fee/entity.go | 14 +++--- .../use-case/main-use-case/material/helper.go | 25 ++++++++++ 3 files changed, 57 insertions(+), 32 deletions(-) create mode 100644 internal/use-case/main-use-case/material/helper.go diff --git a/internal/domain/main-entities/doctor-fee/dto.go b/internal/domain/main-entities/doctor-fee/dto.go index 15da2c61..4d35d903 100644 --- a/internal/domain/main-entities/doctor-fee/dto.go +++ b/internal/domain/main-entities/doctor-fee/dto.go @@ -8,17 +8,17 @@ import ( ) type CreateDto struct { - Doctor_Id *uint `json:"doctor_id"` - FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code"` - Price *float64 `json:"price"` - Item_Id *uint `json:"item_id"` + Doctor_Id *uint `json:"doctor_id"` + FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` } type ReadListDto struct { - Doctor_Id *uint `json:"doctor_id"` - FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code"` - Price *float64 `json:"price"` - Item_Id *uint `json:"item_id"` + Doctor_Id *uint `json:"doctor_id"` + FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -26,11 +26,11 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Doctor_Id *uint `json:"doctor_id"` - FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code"` - Price *float64 `json:"price"` - Item_Id *uint `json:"item_id"` + Id uint16 `json:"id"` + Doctor_Id *uint `json:"doctor_id"` + FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { @@ -50,22 +50,22 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Doctor_Id *uint `json:"doctor_id"` - Doctor *ed.Doctor `json:"doctor,omitempty"` - FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code"` - Price *float64 `json:"price"` - Item_Id *uint `json:"item_id"` - Item *ei.Item `json:"item,omitempty"` + Doctor_Id *uint `json:"doctor_id"` + Doctor *ed.Doctor `json:"doctor,omitempty"` + FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` } func (d DoctorFee) ToResponse() ResponseDto { resp := ResponseDto{ - Doctor_Id: d.Doctor_Id, - Doctor: d.Doctor, - FeeTypeCode: d.FeeTypeCode, - Price: d.Price, - Item_Id: d.Item_Id, - Item: d.Item, + Doctor_Id: d.Doctor_Id, + Doctor: d.Doctor, + FeeType_Code: d.FeeType_Code, + Price: d.Price, + Item_Id: d.Item_Id, + Item: d.Item, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/doctor-fee/entity.go b/internal/domain/main-entities/doctor-fee/entity.go index e0e87d0f..af15173b 100644 --- a/internal/domain/main-entities/doctor-fee/entity.go +++ b/internal/domain/main-entities/doctor-fee/entity.go @@ -8,11 +8,11 @@ import ( ) type DoctorFee struct { - ecore.Main // adjust this according to the needs - Doctor_Id *uint `json:"doctor_id"` - Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Id;references:Id"` - FeeTypeCode *erc.DoctorFeeTypeCode `json:"feeType_code" gorm:"size:11"` - Price *float64 `json:"price"` - Item_Id *uint `json:"item_id"` - Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` + ecore.Main // adjust this according to the needs + Doctor_Id *uint `json:"doctor_id"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Id;references:Id"` + FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code" gorm:"size:11"` + Price *float64 `json:"price"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` } diff --git a/internal/use-case/main-use-case/material/helper.go b/internal/use-case/main-use-case/material/helper.go new file mode 100644 index 00000000..11b4900c --- /dev/null +++ b/internal/use-case/main-use-case/material/helper.go @@ -0,0 +1,25 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package material + +import ( + e "simrs-vx/internal/domain/main-entities/material" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Material) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.Uom_Code = inputSrc.Uom_Code + data.Stock = inputSrc.Stock + data.Item_Id = inputSrc.Item_Id +} From 579ee573c5599d28312661fc258099c78bfde50c Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 28 Aug 2025 16:21:37 +0700 Subject: [PATCH 40/40] reproduce sql script --- cmd/migration/migrations/20250825054027.sql | 147 ----- cmd/migration/migrations/20250825060522.sql | 2 - cmd/migration/migrations/20250825102900.sql | 12 - cmd/migration/migrations/20250825103029.sql | 24 - cmd/migration/migrations/20250827015551.sql | 37 -- cmd/migration/migrations/20250827021904.sql | 77 --- cmd/migration/migrations/20250827024311.sql | 2 - cmd/migration/migrations/20250827072230.sql | 101 ---- cmd/migration/migrations/20250827083322.sql | 28 - cmd/migration/migrations/20250828061151.sql | 121 ---- cmd/migration/migrations/20250828070941.sql | 2 - cmd/migration/migrations/20250828092003.sql | 545 ++++++++++++++++++ cmd/migration/migrations/atlas.sum | 14 +- .../main-use-case/doctor-fee/helper.go | 2 +- 14 files changed, 548 insertions(+), 566 deletions(-) delete mode 100644 cmd/migration/migrations/20250825054027.sql delete mode 100644 cmd/migration/migrations/20250825060522.sql delete mode 100644 cmd/migration/migrations/20250825102900.sql delete mode 100644 cmd/migration/migrations/20250825103029.sql delete mode 100644 cmd/migration/migrations/20250827015551.sql delete mode 100644 cmd/migration/migrations/20250827021904.sql delete mode 100644 cmd/migration/migrations/20250827024311.sql delete mode 100644 cmd/migration/migrations/20250827072230.sql delete mode 100644 cmd/migration/migrations/20250827083322.sql delete mode 100644 cmd/migration/migrations/20250828061151.sql delete mode 100644 cmd/migration/migrations/20250828070941.sql create mode 100644 cmd/migration/migrations/20250828092003.sql diff --git a/cmd/migration/migrations/20250825054027.sql b/cmd/migration/migrations/20250825054027.sql deleted file mode 100644 index a0eb2358..00000000 --- a/cmd/migration/migrations/20250825054027.sql +++ /dev/null @@ -1,147 +0,0 @@ --- Create "Province" table -CREATE TABLE "public"."Province" ( - "Id" smallserial NOT NULL, - "Code" character varying(2) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Province_Code" UNIQUE ("Code") -); --- Create "User" table -CREATE TABLE "public"."User" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Name" character varying(25) NOT NULL, - "Password" character varying(255) NOT NULL, - "Status_Code" character varying(10) NOT NULL, - "FailedLoginCount" smallint NULL, - "LoginAttemptCount" bigint NULL, - "LastSuccessLogin" timestamptz NULL, - "LastAllowdLogin" timestamptz NULL, - PRIMARY KEY ("Id") -); --- Create "Regency" table -CREATE TABLE "public"."Regency" ( - "Id" serial NOT NULL, - "Province_Code" character varying(2) NULL, - "Code" character varying(4) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Regency_Code" UNIQUE ("Code"), - CONSTRAINT "fk_Province_Regencies" FOREIGN KEY ("Province_Code") REFERENCES "public"."Province" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "District" table -CREATE TABLE "public"."District" ( - "Id" bigserial NOT NULL, - "Regency_Code" character varying(4) NULL, - "Code" character varying(6) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_District_Code" UNIQUE ("Code"), - CONSTRAINT "fk_Regency_Districts" FOREIGN KEY ("Regency_Code") REFERENCES "public"."Regency" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Division" table -CREATE TABLE "public"."Division" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - "Parent_Id" smallint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Division_Code" UNIQUE ("Code") -); --- Create "DivisionPosition" table -CREATE TABLE "public"."DivisionPosition" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Division_Id" integer NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_DivisionPosition_Code" UNIQUE ("Code"), - CONSTRAINT "fk_DivisionPosition_Division" FOREIGN KEY ("Division_Id") REFERENCES "public"."Division" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Person" table -CREATE TABLE "public"."Person" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Name" character varying(150) NOT NULL, - "BirthDate" timestamptz NULL, - "BirthRegency_Code" character varying(4) NULL, - "Gender_Code" character varying(10) NULL, - "ResidentIdentityNumber" character varying(16) NULL, - "Religion_Code" character varying(10) NULL, - "Education_Code" character varying(10) NULL, - "Ocupation_Code" character varying(15) NULL, - "Ocupation_Name" character varying(50) NULL, - "Ethnic_Code" character varying(15) NULL, - PRIMARY KEY ("Id") -); --- Create "PersonAddress" table -CREATE TABLE "public"."PersonAddress" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Person_Id" bigint NULL, - "Address" character varying(150) NULL, - "Rt" character varying(2) NULL, - "Rw" character varying(2) NULL, - "Village_Code" character varying(10) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_Person_Addresses" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "PersonContact" table -CREATE TABLE "public"."PersonContact" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Person_Id" bigint NULL, - "Type_Code" character varying(10) NULL, - "Value" character varying(100) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_Person_Contacts" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Installation" table -CREATE TABLE "public"."Installation" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - "EncounterClass_Code" character varying(10) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Installation_Code" UNIQUE ("Code") -); --- Create "Unit" table -CREATE TABLE "public"."Unit" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Installation_Id" integer NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Unit_Code" UNIQUE ("Code"), - CONSTRAINT "fk_Unit_Installation" FOREIGN KEY ("Installation_Id") REFERENCES "public"."Installation" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Village" table -CREATE TABLE "public"."Village" ( - "Id" bigserial NOT NULL, - "District_Code" character varying(6) NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Village_Code" UNIQUE ("Code"), - CONSTRAINT "fk_District_Villages" FOREIGN KEY ("District_Code") REFERENCES "public"."District" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); diff --git a/cmd/migration/migrations/20250825060522.sql b/cmd/migration/migrations/20250825060522.sql deleted file mode 100644 index 1c1306c1..00000000 --- a/cmd/migration/migrations/20250825060522.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Modify "PersonContact" table -ALTER TABLE "public"."PersonContact" ALTER COLUMN "Type_Code" TYPE character varying(15); diff --git a/cmd/migration/migrations/20250825102900.sql b/cmd/migration/migrations/20250825102900.sql deleted file mode 100644 index 766aca3d..00000000 --- a/cmd/migration/migrations/20250825102900.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Create "PharmacyCompany" table -CREATE TABLE "public"."PharmacyCompany" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(20) NULL, - "Name" character varying(100) NULL, - "Regency_Code" character varying(4) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_PharmacyCompany_Code" UNIQUE ("Code") -); diff --git a/cmd/migration/migrations/20250825103029.sql b/cmd/migration/migrations/20250825103029.sql deleted file mode 100644 index 9c3613c7..00000000 --- a/cmd/migration/migrations/20250825103029.sql +++ /dev/null @@ -1,24 +0,0 @@ --- Create "DiagnoseSrc" table -CREATE TABLE "public"."DiagnoseSrc" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(2048) NULL, - "IndName" character varying(2048) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_DiagnoseSrc_Code" UNIQUE ("Code") -); --- Create "ProcedureSrc" table -CREATE TABLE "public"."ProcedureSrc" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(2048) NULL, - "IndName" character varying(2048) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_ProcedureSrc_Code" UNIQUE ("Code") -); diff --git a/cmd/migration/migrations/20250827015551.sql b/cmd/migration/migrations/20250827015551.sql deleted file mode 100644 index 7d9745db..00000000 --- a/cmd/migration/migrations/20250827015551.sql +++ /dev/null @@ -1,37 +0,0 @@ --- Create "InfraGroup" table -CREATE TABLE "public"."InfraGroup" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(50) NULL, - "Name" character varying(100) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_InfraGroup_Code" UNIQUE ("Code") -); --- Create "ItemGroup" table -CREATE TABLE "public"."ItemGroup" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(50) NULL, - "Name" character varying(100) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_ItemGroup_Code" UNIQUE ("Code") -); --- Create "Employee" table -CREATE TABLE "public"."Employee" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "User_Id" bigint NULL, - "Person_Id" bigint NULL, - "Position_Code" character varying(20) NOT NULL, - "Division_Code" character varying(10) NULL, - "Number" character varying(20) NULL, - "Status_Code" character varying(10) NOT NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_Employee_Division" FOREIGN KEY ("Division_Code") REFERENCES "public"."Division" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); diff --git a/cmd/migration/migrations/20250827021904.sql b/cmd/migration/migrations/20250827021904.sql deleted file mode 100644 index cf990cc5..00000000 --- a/cmd/migration/migrations/20250827021904.sql +++ /dev/null @@ -1,77 +0,0 @@ --- Create "Counter" table -CREATE TABLE "public"."Counter" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(30) NULL, - "Number" smallint NULL, - "Parent_Id" integer NULL, - "Type_Code" text NULL, - "Queue_Code" character varying(5) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Counter_Code" UNIQUE ("Code") -); --- Create "Doctor" table -CREATE TABLE "public"."Doctor" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Employee_Id" bigint NULL, - "IHS_Number" character varying(20) NULL, - "SIP_Number" character varying(20) NULL, - "Unit_Id" bigint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_Doctor_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_Doctor_Unit" FOREIGN KEY ("Unit_Id") REFERENCES "public"."Unit" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Nurse" table -CREATE TABLE "public"."Nurse" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Employee_Id" bigint NULL, - "IHS_Number" character varying(20) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_Nurse_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Nutritionist" table -CREATE TABLE "public"."Nutritionist" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Employee_Id" bigint NULL, - "IHS_Number" character varying(20) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_Nutritionist_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Pharmacist" table -CREATE TABLE "public"."Pharmacist" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Employee_Id" bigint NULL, - "IHS_Number" character varying(20) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_Pharmacist_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "PracticeSchedule" table -CREATE TABLE "public"."PracticeSchedule" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Doctor_Id" bigint NULL, - "Unit_Code" character varying(10) NULL, - "Day_Code" smallint NULL, - "StartTime" character varying(5) NULL, - "EndTime" character varying(5) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_PracticeSchedule_Doctor" FOREIGN KEY ("Doctor_Id") REFERENCES "public"."Doctor" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_PracticeSchedule_Unit" FOREIGN KEY ("Unit_Code") REFERENCES "public"."Unit" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); diff --git a/cmd/migration/migrations/20250827024311.sql b/cmd/migration/migrations/20250827024311.sql deleted file mode 100644 index 8ac1d2a6..00000000 --- a/cmd/migration/migrations/20250827024311.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Modify "InfraGroup" table -ALTER TABLE "public"."InfraGroup" ALTER COLUMN "Code" TYPE character varying(10), ALTER COLUMN "Name" TYPE character varying(50), ADD COLUMN "Level" smallint NULL; diff --git a/cmd/migration/migrations/20250827072230.sql b/cmd/migration/migrations/20250827072230.sql deleted file mode 100644 index b2968446..00000000 --- a/cmd/migration/migrations/20250827072230.sql +++ /dev/null @@ -1,101 +0,0 @@ --- Create "McuSrc" table -CREATE TABLE "public"."McuSrc" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(20) NULL, - "Name" character varying(50) NULL, - "CheckupCategory_Code" character varying(20) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_McuSrc_Code" UNIQUE ("Code") -); --- Create "McuSrcCategory" table -CREATE TABLE "public"."McuSrcCategory" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(20) NULL, - "Name" character varying(50) NULL, - "Scope_Code" character varying(10) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_McuSrcCategory_Code" UNIQUE ("Code") -); --- Create "MedicineGroup" table -CREATE TABLE "public"."MedicineGroup" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(50) NULL, - "Name" character varying(100) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_MedicineGroup_Code" UNIQUE ("Code") -); --- Create "MedicineMethod" table -CREATE TABLE "public"."MedicineMethod" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(50) NULL, - "Name" character varying(100) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_MedicineMethod_Code" UNIQUE ("Code") -); --- Create "Uom" table -CREATE TABLE "public"."Uom" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Uom_Code" UNIQUE ("Code") -); --- Create "Item" table -CREATE TABLE "public"."Item" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(50) NULL, - "Name" character varying(100) NULL, - "ItemGroup_Code" character varying(10) NULL, - "Uom_Code" character varying(10) NULL, - "Infra_Id" smallint NULL, - "Stock" numeric NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Item_Code" UNIQUE ("Code"), - CONSTRAINT "fk_Item_ItemGroup" FOREIGN KEY ("ItemGroup_Code") REFERENCES "public"."ItemGroup" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_Item_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Infra" table -CREATE TABLE "public"."Infra" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - "InfraGroup_Code" character varying(10) NULL, - "Parent_Id" smallint NULL, - "Item_Id" bigint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Infra_Code" UNIQUE ("Code"), - CONSTRAINT "fk_Infra_InfraGroup" FOREIGN KEY ("InfraGroup_Code") REFERENCES "public"."InfraGroup" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_Infra_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "ItemPrice" table -CREATE TABLE "public"."ItemPrice" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Item_Id" bigint NULL, - "Price" numeric NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_ItemPrice_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); diff --git a/cmd/migration/migrations/20250827083322.sql b/cmd/migration/migrations/20250827083322.sql deleted file mode 100644 index 2ba01491..00000000 --- a/cmd/migration/migrations/20250827083322.sql +++ /dev/null @@ -1,28 +0,0 @@ --- Create "InsuranceCompany" table -CREATE TABLE "public"."InsuranceCompany" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(20) NULL, - "Name" character varying(50) NULL, - "Regency_Code" character varying(4) NULL, - "Address" character varying(100) NULL, - "PhoneNumber" character varying(20) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_InsuranceCompany_Code" UNIQUE ("Code"), - CONSTRAINT "fk_InsuranceCompany_Regency" FOREIGN KEY ("Regency_Code") REFERENCES "public"."Regency" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Ethnic" table -CREATE TABLE "public"."Ethnic" ( - "Id" serial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(20) NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Ethnic_Code" UNIQUE ("Code") -); --- Modify "Person" table -ALTER TABLE "public"."Person" ALTER COLUMN "Ethnic_Code" TYPE character varying(20), ADD CONSTRAINT "fk_Person_Ethnic" FOREIGN KEY ("Ethnic_Code") REFERENCES "public"."Ethnic" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/migration/migrations/20250828061151.sql b/cmd/migration/migrations/20250828061151.sql deleted file mode 100644 index 64ab7eb5..00000000 --- a/cmd/migration/migrations/20250828061151.sql +++ /dev/null @@ -1,121 +0,0 @@ --- Modify "Item" table -ALTER TABLE "public"."Item" ALTER COLUMN "Stock" TYPE bigint; --- Create "Device" table -CREATE TABLE "public"."Device" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - "Uom_Code" character varying(10) NULL, - "Item_Id" bigint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Device_Code" UNIQUE ("Code"), - CONSTRAINT "fk_Device_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_Device_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "DoctorFee" table -CREATE TABLE "public"."DoctorFee" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Doctor_Id" bigint NULL, - "FeeTypeCode" character varying(11) NULL, - "Price" numeric NULL, - "Item_Id" bigint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_DoctorFee_Doctor" FOREIGN KEY ("Doctor_Id") REFERENCES "public"."Doctor" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_DoctorFee_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Modify "ItemPrice" table -ALTER TABLE "public"."ItemPrice" ADD COLUMN "InsuranceCompany_Code" character varying(20) NULL, ADD CONSTRAINT "fk_ItemPrice_InsuranceCompany" FOREIGN KEY ("InsuranceCompany_Code") REFERENCES "public"."InsuranceCompany" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; --- Create "Material" table -CREATE TABLE "public"."Material" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - "Uom_Code" character varying(10) NULL, - "Stock" bigint NULL, - "Item_Id" bigint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Material_Code" UNIQUE ("Code"), - CONSTRAINT "fk_Material_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_Material_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "MedicalActionSrc" table -CREATE TABLE "public"."MedicalActionSrc" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(20) NULL, - "Name" character varying(50) NULL, - "Item_Id" bigint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_MedicalActionSrc_Code" UNIQUE ("Code"), - CONSTRAINT "fk_MedicalActionSrc_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "MedicalActionSrcItem" table -CREATE TABLE "public"."MedicalActionSrcItem" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "MedicalActionSrc_Id" bigint NULL, - "ProcedureSrc_Id" bigint NULL, - "Item_Id" bigint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_MedicalActionSrcItem_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_MedicalActionSrcItem_MedicalActionSrc" FOREIGN KEY ("MedicalActionSrc_Id") REFERENCES "public"."MedicalActionSrc" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_MedicalActionSrcItem_ProcedureSrc" FOREIGN KEY ("ProcedureSrc_Id") REFERENCES "public"."ProcedureSrc" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "Medicine" table -CREATE TABLE "public"."Medicine" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, - "Name" character varying(50) NULL, - "MedicineGroup_Code" character varying(10) NULL, - "MedicineMethod_Code" character varying(10) NULL, - "Uom_Code" character varying(10) NULL, - "Dose" smallint NULL, - "Infra_Id" integer NULL, - "Stock" bigint NULL, - "Item_Id" bigint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "uni_Medicine_Code" UNIQUE ("Code"), - CONSTRAINT "fk_Medicine_Infra" FOREIGN KEY ("Infra_Id") REFERENCES "public"."Infra" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_Medicine_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_Medicine_MedicineGroup" FOREIGN KEY ("MedicineGroup_Code") REFERENCES "public"."MedicineGroup" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_Medicine_MedicineMethod" FOREIGN KEY ("MedicineMethod_Code") REFERENCES "public"."MedicineMethod" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_Medicine_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION -); --- Create "MedicineMix" table -CREATE TABLE "public"."MedicineMix" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "Name" character varying(50) NULL, - PRIMARY KEY ("Id") -); --- Create "MedicineMixItem" table -CREATE TABLE "public"."MedicineMixItem" ( - "Id" bigserial NOT NULL, - "CreatedAt" timestamptz NULL, - "UpdatedAt" timestamptz NULL, - "DeletedAt" timestamptz NULL, - "MedicineMix_Id" bigint NULL, - "Medicine_Id" bigint NULL, - "Dose" smallint NULL, - PRIMARY KEY ("Id"), - CONSTRAINT "fk_MedicineMixItem_Medicine" FOREIGN KEY ("Medicine_Id") REFERENCES "public"."Medicine" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, - CONSTRAINT "fk_MedicineMixItem_MedicineMix" FOREIGN KEY ("MedicineMix_Id") REFERENCES "public"."MedicineMix" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION -); diff --git a/cmd/migration/migrations/20250828070941.sql b/cmd/migration/migrations/20250828070941.sql deleted file mode 100644 index 2f68a1b8..00000000 --- a/cmd/migration/migrations/20250828070941.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Modify "Item" table -ALTER TABLE "public"."Item" ALTER COLUMN "Infra_Id" TYPE integer; diff --git a/cmd/migration/migrations/20250828092003.sql b/cmd/migration/migrations/20250828092003.sql new file mode 100644 index 00000000..175129a6 --- /dev/null +++ b/cmd/migration/migrations/20250828092003.sql @@ -0,0 +1,545 @@ +-- Create "DiagnoseSrc" table +CREATE TABLE "public"."DiagnoseSrc" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(2048) NULL, + "IndName" character varying(2048) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_DiagnoseSrc_Code" UNIQUE ("Code") +); +-- Create "PharmacyCompany" table +CREATE TABLE "public"."PharmacyCompany" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(100) NULL, + "Regency_Code" character varying(4) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_PharmacyCompany_Code" UNIQUE ("Code") +); +-- Create "McuSrc" table +CREATE TABLE "public"."McuSrc" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + "CheckupCategory_Code" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_McuSrc_Code" UNIQUE ("Code") +); +-- Create "ItemGroup" table +CREATE TABLE "public"."ItemGroup" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(50) NULL, + "Name" character varying(100) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_ItemGroup_Code" UNIQUE ("Code") +); +-- Create "McuSrcCategory" table +CREATE TABLE "public"."McuSrcCategory" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + "Scope_Code" character varying(10) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_McuSrcCategory_Code" UNIQUE ("Code") +); +-- Create "Counter" table +CREATE TABLE "public"."Counter" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(30) NULL, + "Number" smallint NULL, + "Parent_Id" integer NULL, + "Type_Code" text NULL, + "Queue_Code" character varying(5) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Counter_Code" UNIQUE ("Code") +); +-- Create "User" table +CREATE TABLE "public"."User" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Name" character varying(25) NOT NULL, + "Password" character varying(255) NOT NULL, + "Status_Code" character varying(10) NOT NULL, + "FailedLoginCount" smallint NULL, + "LoginAttemptCount" bigint NULL, + "LastSuccessLogin" timestamptz NULL, + "LastAllowdLogin" timestamptz NULL, + PRIMARY KEY ("Id") +); +-- Create "Uom" table +CREATE TABLE "public"."Uom" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Uom_Code" UNIQUE ("Code") +); +-- Create "Item" table +CREATE TABLE "public"."Item" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(50) NULL, + "Name" character varying(100) NULL, + "ItemGroup_Code" character varying(10) NULL, + "Uom_Code" character varying(10) NULL, + "Infra_Id" integer NULL, + "Stock" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Item_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Item_ItemGroup" FOREIGN KEY ("ItemGroup_Code") REFERENCES "public"."ItemGroup" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Item_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Device" table +CREATE TABLE "public"."Device" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "Uom_Code" character varying(10) NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Device_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Device_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Device_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Province" table +CREATE TABLE "public"."Province" ( + "Id" smallserial NOT NULL, + "Code" character varying(2) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Province_Code" UNIQUE ("Code") +); +-- Create "Regency" table +CREATE TABLE "public"."Regency" ( + "Id" serial NOT NULL, + "Province_Code" character varying(2) NULL, + "Code" character varying(4) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Regency_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Province_Regencies" FOREIGN KEY ("Province_Code") REFERENCES "public"."Province" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "District" table +CREATE TABLE "public"."District" ( + "Id" bigserial NOT NULL, + "Regency_Code" character varying(4) NULL, + "Code" character varying(6) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_District_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Regency_Districts" FOREIGN KEY ("Regency_Code") REFERENCES "public"."Regency" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Division" table +CREATE TABLE "public"."Division" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "Parent_Id" smallint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Division_Code" UNIQUE ("Code") +); +-- Create "DivisionPosition" table +CREATE TABLE "public"."DivisionPosition" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Division_Id" integer NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_DivisionPosition_Code" UNIQUE ("Code"), + CONSTRAINT "fk_DivisionPosition_Division" FOREIGN KEY ("Division_Id") REFERENCES "public"."Division" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Employee" table +CREATE TABLE "public"."Employee" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "User_Id" bigint NULL, + "Person_Id" bigint NULL, + "Position_Code" character varying(20) NOT NULL, + "Division_Code" character varying(10) NULL, + "Number" character varying(20) NULL, + "Status_Code" character varying(10) NOT NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Employee_Division" FOREIGN KEY ("Division_Code") REFERENCES "public"."Division" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Installation" table +CREATE TABLE "public"."Installation" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "EncounterClass_Code" character varying(10) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Installation_Code" UNIQUE ("Code") +); +-- Create "Unit" table +CREATE TABLE "public"."Unit" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Installation_Id" integer NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Unit_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Unit_Installation" FOREIGN KEY ("Installation_Id") REFERENCES "public"."Installation" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Doctor" table +CREATE TABLE "public"."Doctor" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "IHS_Number" character varying(20) NULL, + "SIP_Number" character varying(20) NULL, + "Unit_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Doctor_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Doctor_Unit" FOREIGN KEY ("Unit_Id") REFERENCES "public"."Unit" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "DoctorFee" table +CREATE TABLE "public"."DoctorFee" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Doctor_Id" bigint NULL, + "FeeType_Code" character varying(11) NULL, + "Price" numeric NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_DoctorFee_Doctor" FOREIGN KEY ("Doctor_Id") REFERENCES "public"."Doctor" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_DoctorFee_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "InfraGroup" table +CREATE TABLE "public"."InfraGroup" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "Level" smallint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_InfraGroup_Code" UNIQUE ("Code") +); +-- Create "Infra" table +CREATE TABLE "public"."Infra" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "InfraGroup_Code" character varying(10) NULL, + "Parent_Id" smallint NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Infra_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Infra_InfraGroup" FOREIGN KEY ("InfraGroup_Code") REFERENCES "public"."InfraGroup" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Infra_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "InsuranceCompany" table +CREATE TABLE "public"."InsuranceCompany" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + "Regency_Code" character varying(4) NULL, + "Address" character varying(100) NULL, + "PhoneNumber" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_InsuranceCompany_Code" UNIQUE ("Code"), + CONSTRAINT "fk_InsuranceCompany_Regency" FOREIGN KEY ("Regency_Code") REFERENCES "public"."Regency" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "ItemPrice" table +CREATE TABLE "public"."ItemPrice" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Item_Id" bigint NULL, + "Price" numeric NULL, + "InsuranceCompany_Code" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_ItemPrice_InsuranceCompany" FOREIGN KEY ("InsuranceCompany_Code") REFERENCES "public"."InsuranceCompany" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_ItemPrice_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Material" table +CREATE TABLE "public"."Material" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "Uom_Code" character varying(10) NULL, + "Stock" bigint NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Material_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Material_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Material_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "MedicalActionSrc" table +CREATE TABLE "public"."MedicalActionSrc" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_MedicalActionSrc_Code" UNIQUE ("Code"), + CONSTRAINT "fk_MedicalActionSrc_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "ProcedureSrc" table +CREATE TABLE "public"."ProcedureSrc" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(2048) NULL, + "IndName" character varying(2048) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_ProcedureSrc_Code" UNIQUE ("Code") +); +-- Create "MedicalActionSrcItem" table +CREATE TABLE "public"."MedicalActionSrcItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "MedicalActionSrc_Id" bigint NULL, + "ProcedureSrc_Id" bigint NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_MedicalActionSrcItem_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_MedicalActionSrcItem_MedicalActionSrc" FOREIGN KEY ("MedicalActionSrc_Id") REFERENCES "public"."MedicalActionSrc" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_MedicalActionSrcItem_ProcedureSrc" FOREIGN KEY ("ProcedureSrc_Id") REFERENCES "public"."ProcedureSrc" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "MedicineGroup" table +CREATE TABLE "public"."MedicineGroup" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(50) NULL, + "Name" character varying(100) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_MedicineGroup_Code" UNIQUE ("Code") +); +-- Create "MedicineMethod" table +CREATE TABLE "public"."MedicineMethod" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(50) NULL, + "Name" character varying(100) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_MedicineMethod_Code" UNIQUE ("Code") +); +-- Create "Medicine" table +CREATE TABLE "public"."Medicine" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "MedicineGroup_Code" character varying(10) NULL, + "MedicineMethod_Code" character varying(10) NULL, + "Uom_Code" character varying(10) NULL, + "Dose" smallint NULL, + "Infra_Id" integer NULL, + "Stock" bigint NULL, + "Item_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Medicine_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Medicine_Infra" FOREIGN KEY ("Infra_Id") REFERENCES "public"."Infra" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Medicine_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Medicine_MedicineGroup" FOREIGN KEY ("MedicineGroup_Code") REFERENCES "public"."MedicineGroup" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Medicine_MedicineMethod" FOREIGN KEY ("MedicineMethod_Code") REFERENCES "public"."MedicineMethod" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Medicine_Uom" FOREIGN KEY ("Uom_Code") REFERENCES "public"."Uom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "MedicineMix" table +CREATE TABLE "public"."MedicineMix" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id") +); +-- Create "MedicineMixItem" table +CREATE TABLE "public"."MedicineMixItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "MedicineMix_Id" bigint NULL, + "Medicine_Id" bigint NULL, + "Dose" smallint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_MedicineMixItem_Medicine" FOREIGN KEY ("Medicine_Id") REFERENCES "public"."Medicine" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_MedicineMixItem_MedicineMix" FOREIGN KEY ("MedicineMix_Id") REFERENCES "public"."MedicineMix" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Nurse" table +CREATE TABLE "public"."Nurse" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "IHS_Number" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Nurse_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Nutritionist" table +CREATE TABLE "public"."Nutritionist" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "IHS_Number" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Nutritionist_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Ethnic" table +CREATE TABLE "public"."Ethnic" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Ethnic_Code" UNIQUE ("Code") +); +-- Create "Person" table +CREATE TABLE "public"."Person" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Name" character varying(150) NOT NULL, + "BirthDate" timestamptz NULL, + "BirthRegency_Code" character varying(4) NULL, + "Gender_Code" character varying(10) NULL, + "ResidentIdentityNumber" character varying(16) NULL, + "Religion_Code" character varying(10) NULL, + "Education_Code" character varying(10) NULL, + "Ocupation_Code" character varying(15) NULL, + "Ocupation_Name" character varying(50) NULL, + "Ethnic_Code" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Person_Ethnic" FOREIGN KEY ("Ethnic_Code") REFERENCES "public"."Ethnic" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "PersonAddress" table +CREATE TABLE "public"."PersonAddress" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Person_Id" bigint NULL, + "Address" character varying(150) NULL, + "Rt" character varying(2) NULL, + "Rw" character varying(2) NULL, + "Village_Code" character varying(10) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Person_Addresses" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "PersonContact" table +CREATE TABLE "public"."PersonContact" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Person_Id" bigint NULL, + "Type_Code" character varying(15) NULL, + "Value" character varying(100) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Person_Contacts" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Pharmacist" table +CREATE TABLE "public"."Pharmacist" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "IHS_Number" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Pharmacist_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "PracticeSchedule" table +CREATE TABLE "public"."PracticeSchedule" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Doctor_Id" bigint NULL, + "Unit_Code" character varying(10) NULL, + "Day_Code" smallint NULL, + "StartTime" character varying(5) NULL, + "EndTime" character varying(5) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_PracticeSchedule_Doctor" FOREIGN KEY ("Doctor_Id") REFERENCES "public"."Doctor" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_PracticeSchedule_Unit" FOREIGN KEY ("Unit_Code") REFERENCES "public"."Unit" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "Village" table +CREATE TABLE "public"."Village" ( + "Id" bigserial NOT NULL, + "District_Code" character varying(6) NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_Village_Code" UNIQUE ("Code"), + CONSTRAINT "fk_District_Villages" FOREIGN KEY ("District_Code") REFERENCES "public"."District" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index e1837c02..d3527869 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,12 +1,2 @@ -h1:NHJkMhPA1vP9q0CThwWTfKyvuE9V0Cn7WN+gtrIMw/8= -20250825054027.sql h1:zRUeuuP4bDLf96Cb38D/l9ivBAQC745XRao0rxbzdVI= -20250825060522.sql h1:NiE1fVzydcg8Y8ytSHgt0DkkauQFveNXv42BoG5m+bI= -20250825102900.sql h1:OAUnj87Wz7mrHykX14idePckUmRYa5UH0LylYDL76RI= -20250825103029.sql h1:iuZFrfUjNQM5kRpEwdYR8qinSp8SIkoJc3Dr8rD8BuI= -20250827015551.sql h1:Jq/RkXSWHEWuNigLunLzIrYgiyroSVD7J0waDMvdzvg= -20250827021904.sql h1:pgjwmQS1TxZ977a1tIXKq6pZnGauPrOUxLUTclV+fE4= -20250827024311.sql h1:eTlrQYcHa/jmb3qSZxgTB+7S4IXJ8B4yklUB36iZaDw= -20250827072230.sql h1:BfdTcToEYC8d30BS+1Su5Pz5Ecz8bh74F2j+Bh/r2BM= -20250827083322.sql h1:2MErE7W1JTjcxtgKJs/1iEF8kgV6vrcGrDVx/m6LwHQ= -20250828061151.sql h1:CxTT3e9ZJ+Rp4UXE40SuFswVedlagKqDneFkg4BZkRs= -20250828070941.sql h1:Tr4Nal4jB9vFY6lpN2b9VIDKej91DWIgjD3K/dA69kc= +h1:MMNuESyEk0KZHA2z+7AukfG/ATboITROipz2wK3YNPg= +20250828092003.sql h1:Rr221/6KN53t0eoEHK5+sPeMaVsnKjN4322WLulN8AQ= diff --git a/internal/use-case/main-use-case/doctor-fee/helper.go b/internal/use-case/main-use-case/doctor-fee/helper.go index 26ac7bec..92aa61bb 100644 --- a/internal/use-case/main-use-case/doctor-fee/helper.go +++ b/internal/use-case/main-use-case/doctor-fee/helper.go @@ -18,7 +18,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.DoctorFee) { } data.Doctor_Id = inputSrc.Doctor_Id - data.FeeTypeCode = inputSrc.FeeTypeCode + data.FeeType_Code = inputSrc.FeeType_Code data.Price = inputSrc.Price data.Item_Id = inputSrc.Item_Id }