From 0843fca961cd7c3292ca6195ca7d02eaff74f65d Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 11 Aug 2025 11:05:42 +0700 Subject: [PATCH 01/75] setup debugger --- .gitignore | 2 +- .vscode/launch.json | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 .vscode/launch.json diff --git a/.gitignore b/.gitignore index 1fe7cee2..a5fc84d8 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,4 @@ config.yml # Editor/IDE # .idea/ -# .vscode/ +.vscode/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..e542bfc3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Launch Package main API", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/main-api" + }, + // { + // "name": "Launch Package excel migrator", + // "type": "go", + // "request": "launch", + // "mode": "auto", + // "program": "${workspaceFolder}/cmd/excelmigrator" + // } + ] +} \ No newline at end of file From 61512963bd0335ac82c4aeba68e8ddc688591104 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 11 Aug 2025 11:10:56 +0700 Subject: [PATCH 02/75] tidy --- go.mod | 1 - go.sum | 2 -- 2 files changed, 3 deletions(-) diff --git a/go.mod b/go.mod index 535bb824..f663ad8a 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ toolchain go1.23.11 require ( github.com/karincake/apem v0.0.16-e - github.com/karincake/dodol v0.0.1 gorm.io/gorm v1.25.10 ) diff --git a/go.sum b/go.sum index 79fad110..1b938924 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,6 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/karincake/apem v0.0.16-e h1:KGeQYmgNw8luidSWkZyGcMbW1PP3KMRCHMTEHQ7twU8= github.com/karincake/apem v0.0.16-e/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= -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/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= From d2356e1a2d69edce0e2c8e3189772c65233c1d57 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 11 Aug 2025 11:49:14 +0700 Subject: [PATCH 03/75] add karincake/dodol --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index f663ad8a..f33ca425 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ toolchain go1.23.11 require ( github.com/karincake/apem v0.0.16-e + github.com/karincake/dodol v0.1.0-d gorm.io/gorm v1.25.10 ) diff --git a/go.sum b/go.sum index 1b938924..ce87c852 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/karincake/apem v0.0.16-e h1:KGeQYmgNw8luidSWkZyGcMbW1PP3KMRCHMTEHQ7twU8= github.com/karincake/apem v0.0.16-e/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= +github.com/karincake/dodol v0.1.0-d h1:f5p35a2el+9XbiCCZKT7Gf/hXs8m2p5iD1C20RZ/aKI= +github.com/karincake/dodol v0.1.0-d/go.mod h1:2f1NcvkvY0J3GMUkwILNDYVvRUpz0W3lpPp/Ha/Ld24= 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= From 5a950b5fe9197f546bc5d44f8dc9a1859ab497aa Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 11 Aug 2025 13:10:54 +0700 Subject: [PATCH 04/75] pre-dev: update dependency --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index f33ca425..e3d5ebea 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/jackc/pgx/v5 v5.4.3 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/karincake/getuk v0.1.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect diff --git a/go.sum b/go.sum index ce87c852..2016cbae 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ github.com/karincake/apem v0.0.16-e h1:KGeQYmgNw8luidSWkZyGcMbW1PP3KMRCHMTEHQ7tw github.com/karincake/apem v0.0.16-e/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= github.com/karincake/dodol v0.1.0-d h1:f5p35a2el+9XbiCCZKT7Gf/hXs8m2p5iD1C20RZ/aKI= github.com/karincake/dodol v0.1.0-d/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/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= From 4b3090d78833ccef1fac27e95dbc77e7289ad9d3 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 11 Aug 2025 13:13:29 +0700 Subject: [PATCH 05/75] pre-dev: wip crud template --- internal/domain/_template/single/dto.go | 11 ++ .../use-case/_use-case-template/crud/case.go | 146 +++++++++++++++--- .../use-case/_use-case-template/crud/lib.go | 94 +++++++++-- 3 files changed, 224 insertions(+), 27 deletions(-) diff --git a/internal/domain/_template/single/dto.go b/internal/domain/_template/single/dto.go index ba3e602b..472137a4 100644 --- a/internal/domain/_template/single/dto.go +++ b/internal/domain/_template/single/dto.go @@ -9,9 +9,14 @@ type Createdto struct { 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 uint `json:"id"` Code string `json:"code"` Name string `json:"name"` } @@ -24,3 +29,9 @@ type Updatedto struct { type Deletedto struct { Id uint `json:"id"` } + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int64 `json:"count"` +} diff --git a/internal/use-case/_use-case-template/crud/case.go b/internal/use-case/_use-case-template/crud/case.go index cf617ff7..6312c950 100644 --- a/internal/use-case/_use-case-template/crud/case.go +++ b/internal/use-case/_use-case-template/crud/case.go @@ -5,29 +5,36 @@ Any functions that are available to be used externally. package crud import ( + "strconv" + dg "github.com/karincake/apem/db-gorm-pg" + lo "github.com/karincake/apem/logero" d "github.com/karincake/dodol" "gorm.io/gorm" - e "simrs-vx/internal/domain/main-entities/single" + e "simrs-vx/internal/domain/_template/single" ) const source = "crud" func Create(input e.Createdto) (*d.Data, error) { + data := e.Single{} + + setData(&data, &input) err := dg.I.Transaction(func(tx *gorm.DB) error { + lo.I. for i := range createPreMw { - if err := createPreMw[i](&input, &data, dg.I); err != nil { + if err := createPreMw[i](&input, &data, tx); err != nil { return nil } } - - if err := dg.I.Create(&data).Error; err != nil { + slog. + if result, err := CreateData(&data, tx).Error; err != nil { return nil } for i := range createPostMw { - if err := createPostMw[i](&input, &data, dg.I); err != nil { + if err := createPostMw[i](&input, &data, tx); err != nil { return nil } } @@ -46,26 +53,129 @@ func Create(input e.Createdto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - data := d.Data{} - query := dg.I - query.Find(&data) - if err := query.Error; err != nil { - return nil, err - } + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range readListPreMw { + if err := readListPreMw[i](&input, &data, tx); err != nil { + return nil + } + } + + data, meta, err := ReadListData(input, tx) + if err != nil { + return nil, err + } + + for i := range readListPostMw { + if err := readListPostMw[i](&input, &data, tx); err != nil { + return nil + } + } + + return nil + }) + return &d.Data{ - Meta: d.II{}, + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(meta.PageNumber), + "page_size": strconv.Itoa(meta.PageSize), + "record_totalCount": strconv.Itoa(meta.Count), + }, Data: data, }, nil } -func ReadDetail() { +func ReadDetail(input e.ReadDetailDto) (*d.Data, 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 nil, err + } + for i := range readDetailPostMw { + if err := readDetailPostMw[i](&input, &data, tx); err != nil { + return nil + } + } + return nil + }) + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data, + }, nil +} + +func Update(input e.Updatedto) (*d.Data, error) { + err := dg.I.Transaction(func(tx *gorm.DB) error { + data, err := ReadDetailData(input, tx) + if err != nil { + return nil + } + + setData(&data, &input) + for i := range updatePreMw { + if err := updatePreMw[i](&input, &data, tx); err != nil { + return nil + } + } + if err := UpdateData(*data, tx); err != nil { + return nil + } + for i := range updatePostMw { + if err := updatePostMw[i](&input, &data, tx); err != nil { + return nil + } + } + return nil + }) + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data, + }, nil } -func Update() { - -} - -func Delete() { +func Delete(input e.Deletedto) (*d.Data, error) { + err := dg.I.Transaction(func(tx *gorm.DB) error { + data, err := ReadDetailData(input, tx) + if err != nil { + return nil + } + for i := range deletePreMw { + if err := deletePreMw[i](&input, &data, tx); err != nil { + return nil + } + } + if err := DeleteData(data, tx); err != nil { + return nil + } + for i := range deletePostMw { + if err := deletePostMw[i](&input, &data, tx); err != nil { + return nil + } + } + }) + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data, + }, nil } diff --git a/internal/use-case/_use-case-template/crud/lib.go b/internal/use-case/_use-case-template/crud/lib.go index 0283c7d8..24ee2398 100644 --- a/internal/use-case/_use-case-template/crud/lib.go +++ b/internal/use-case/_use-case-template/crud/lib.go @@ -1,25 +1,101 @@ package crud import ( - e "simrs-vx/internal/domain/main-entities/single" + e "simrs-vx/internal/domain/_template/single" dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" "gorm.io/gorm" ) -func CreateData(input e.Createdto, tx ...*gorm.DB) (*e.Single, error) { - data := e.Single{} - - var db *gorm.DB - if tx != nil { - db = tx +func CreateData(input *e.Single, dbx ...*gorm.DB) (*e.Single, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] } else { - db = dg.I + tx = dg.I } - if err := dg.I.Create(&data).Error; err != nil { + if err := tx.Create(&data).Error; err != nil { return nil, err } return &data, err } + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Single, *e.MetaDto, error) { + data := []e.Single{} + 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.Single{}). + // 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.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = count + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Single, error) { + data := e.Single{} + + 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 err == gorm.ErrRecordNotFound { + return nil, nil + } + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.Single, 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.Single, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} From 28e043f4dae7a1eeb58c5778cbad75aa09065c52 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 12 Aug 2025 10:47:14 +0700 Subject: [PATCH 06/75] pre-dev: add lang helper --- .gitignore | 2 +- assets/language/en/data.json | 75 +++++++++++++++++++++++++++++++++ assets/language/id/data.json | 76 ++++++++++++++++++++++++++++++++++ assets/language/readme.md | 2 + go.mod | 4 +- go.sum | 8 ++-- pkg/lang-helper/lang-helper.go | 19 +++++++++ 7 files changed, 179 insertions(+), 7 deletions(-) create mode 100644 assets/language/en/data.json create mode 100644 assets/language/id/data.json create mode 100644 assets/language/readme.md create mode 100644 pkg/lang-helper/lang-helper.go diff --git a/.gitignore b/.gitignore index a5fc84d8..904cf795 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,4 @@ config.yml # Editor/IDE # .idea/ -.vscode/ +.vscode/* diff --git a/assets/language/en/data.json b/assets/language/en/data.json new file mode 100644 index 00000000..cbb70be5 --- /dev/null +++ b/assets/language/en/data.json @@ -0,0 +1,75 @@ +{ + "request-ok": "request is done succesfully", + "request-methodNotAllowed": "request has been rejected, method is not allowed", + "request-toomany": "too many request", + "payload-bad": "invalid data structure", + + "auth-required": "authentication required", + "auth-missingHeader": "authentication header is missing", + "auth-forbidden": "forbidden", + "auth-login-success": "login success", + "auth-login-incorrect": "login failed, icorrect username or password", + "auth-login-tooMany": "login failed, too many login attempts", + "auth-login-blocked": "login failed, account is blocked", + "auth-login-unverified": "login failed, account is not verified", + "auth-logout-success": "logout success", + "auth-reject-suspend": "restricted for suspended account", + + "balance-exceed-notAllowed": "must not exceeds balance", + + "emailConfirm-success": "email confirmation success", + "emailConfirm-fail": "failed to confirm email", + "emailConfirm-resend-fail": "failed to resend email confirmation", + + "data-create-done": "data has been created", + "data-notFound": "data or resource can not be found", + "data-notFound-condition": "\"%v\" with %v \"%v\" can not be found", + "data-get-fail": "get data failed, %v", + "data-send-fail": "send data failed, %v", + "data-create-fail": "failed to create data", + "data-update-fail": "failed to update data", + "data-delete-fail": "failed to delete data", + "data-delete-success": "data has been deleted", + "data-fetch-fail": "failed to fetch data", + "data-copy-fail": "failed to copy data", + "data-process-fail": "failed to process data", + "data-confirm-fail": "failed to confirm data", + "data-generate-fail": "failed to generate data", + "data-registered": "is already registered", + "data-state-mismatch": "\"%v\" is not in \"%v\" state", + "data-duplicate": "duplicate data", + "data-payment-fail": "failed to create payment", + + "expired": "is expired", + "registered": "is already registered", + "mustUuid": "must be a valid uuid", + "invalid": "invalid value", + "equalToField": "must equal to", + "constraint-vioalate": "must not violate constraint", + + "config-fetch-done": "app config is fetched successfully", + "userToken-incorrect": "incorrect email, token, or token type", + + "token-missing": "missing required token", + "token-invalid": "invalid token", + "token-invalidType": "invalid token type", + "token-sign-unexcpeted": "unexpected signing method: %v", + "token-sign-err": "token signing failed, %v", + "token-parse-fail": "token parsing failed, %v", + "token-expired": "token is expired", + "token-unidentified": "token is could not be identified", + + "file-detect-fail": "file type detection failed", + "file-type-mismatch": "file type mismatch", + "file-create-fail": "failed to create file, %v", + "file-open-fail": "failed to open file, %v", + "file-copy-fail": "failed to copy file, %v", + + "uuid-gen-fail" : "failed to generate uuid, %v", + "nanoid-gen-fail" : "failed to generate nanoid, %v", + + "redis-store-fail": "redis storing value failed, %v", + + "gte": "greater than or equal to %v", + "lte": "less than or equal to %v" +} diff --git a/assets/language/id/data.json b/assets/language/id/data.json new file mode 100644 index 00000000..b800d90d --- /dev/null +++ b/assets/language/id/data.json @@ -0,0 +1,76 @@ +{ + "request-ok": "'request' berhasil diproses", + "request-methodNotAllowed": "'request' ditolak, method tidak diijinkan", + "request-toomany": "terlalu banyak 'request'", + "payload-bad": "struktur data tidak sesuai standar", + + "auth-required": "butuh autentikasi", + "auth-missingHeader": "Header autentikasi tidak ditemukan", + "auth-forbidden": "tidak diijinkan", + "auth-login-success": "login berhasil", + "auth-login-incorrect": "Username atau Password Tidak Sesuai", + "auth-login-tooMany": "login gagal, terlalu banyak percobaan", + "auth-login-blocked": "login gagal, akun diblokir", + "auth-login-unverified": "login gagal, akun belum terverifikasi", + "auth-logout-success": "logout berhasil", + "auth-reject-suspend": "dibatasi untuk akun dibekukan", + + "balance-exceed-notAllowed": "tidak boleh melebihi saldo", + + "emailConfirm-success": "konfimrasi email berhasil", + "emailConfirm-fail": "gagal mengkonfirmasi email", + "emailConfirm-resend-fail": "gagal mengirim konfirmasi email", + + "data-create-done": "data telah dibuat", + "data-notFound": "data atau sumber tidak daoat ditemukan", + "data-notFound-condition": "\"%v\" dengan %v \"%v\" tidak dapat ditemukan", + "data-get-fail": "gagal mengambil data, %v", + "data-create-fail": "gagal membuat data", + "data-update-fail": "gagal memperbarui data", + "data-delete-fail": "gagal menghapus data", + "data-delete-success": "data telah dihapus", + "data-fetch-fail": "gagal mengambil data", + "data-copy-fail": "gagal menyalin data", + "data-process-fail": "gagal memproses data", + "data-confirm-fail": "gagal mengirim data", + "data-generate-fail": "gagal membuat data", + "data-registered": "sudah pernah dibuat", + "data-state-mismatch": "\"%v\" tidak dalam kondisi \"%v\"", + + "expired": "expired", + "registered": "sudah terdaftar", + "mustUuid": "harus UUID yang valid", + "invalid": "nilai tidak sesuai", + "equalToField": "harus sama dengan", + "constraint-vioalate": "tidak boleh melanggar batasan", + + "config-fetch-done": "konfigurasi app berhasil diterapkan", + "userToken-incorrect": "salah email, token, atau jenis token", + + "token-missing": "token tidak dapat ditemukan", + "token-invalid": "token tidak berlaku", + "token-invalidType": "jenis token tidak berlaku", + "token-sign-unexcpeted": "metode penanda tidak beralku: %v", + "token-sign-err": "penanda token tidak sesuai, %v", + "token-parse-fail": "%v", + "token-expired": "Token Expired", + "token-unidentified": "token tidak dapat diidentifikasi", + + "file-detect-fail": "gagal mendeteksi tipe file", + "file-type-mismatch": "tipe file tidak sesuai", + "file-create-fail": "gagal membuat file, %v", + "file-open-fail": "gagal membuka file, %v", + "file-copy-fail": "gagal menyalin file, %v", + + "uuid-gen-fail" : "gagal membuat UUID, %v", + "nanoid-gen-fail" : "gagal membuat NANOID, %v", + + "redis-store-fail": "gagal mengimpan data pada redis, %v", + + "gte": "lebih besar atau sama dengan %v", + "lte": "lebih kecil atau sama dengan %v", + "jknData-required": "%v Belum Diisi", + "jknData-length": "Format %v Tidak Sesuai", + "jknData-numeric": "Format %v Tidak Sesuai", + "jknData-notFound": "%v Tidak Ditemukan" +} diff --git a/assets/language/readme.md b/assets/language/readme.md new file mode 100644 index 00000000..720e25c8 --- /dev/null +++ b/assets/language/readme.md @@ -0,0 +1,2 @@ +# convention +Key - value data indexed. Key prefered to be be consisting of 3 part: [feature]-[action]-[status]. Special case for validation that is intended to point error on an input (field), the key can be stated directly to the validation index, for example: min is for minimum value needed. \ No newline at end of file diff --git a/go.mod b/go.mod index e3d5ebea..ef9113ab 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.23.11 require ( github.com/karincake/apem v0.0.16-e - github.com/karincake/dodol v0.1.0-d + github.com/karincake/lepet v0.0.1 gorm.io/gorm v1.25.10 ) @@ -18,13 +18,13 @@ require ( github.com/jackc/pgx/v5 v5.4.3 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/karincake/getuk v0.1.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/nxadm/tail v1.4.11 // indirect github.com/rs/zerolog v1.33.0 // indirect golang.org/x/crypto v0.40.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect golang.org/x/net v0.42.0 // indirect golang.org/x/sys v0.34.0 // indirect golang.org/x/text v0.27.0 // indirect diff --git a/go.sum b/go.sum index 2016cbae..5ff115b0 100644 --- a/go.sum +++ b/go.sum @@ -22,10 +22,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/karincake/apem v0.0.16-e h1:KGeQYmgNw8luidSWkZyGcMbW1PP3KMRCHMTEHQ7twU8= github.com/karincake/apem v0.0.16-e/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= -github.com/karincake/dodol v0.1.0-d h1:f5p35a2el+9XbiCCZKT7Gf/hXs8m2p5iD1C20RZ/aKI= -github.com/karincake/dodol v0.1.0-d/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/lepet v0.0.1 h1:eq/cwn5BBg0jWZ1c/MmvhFIBma0zBpVs2LwkfDOncy4= +github.com/karincake/lepet v0.0.1/go.mod h1:U84w7olXO3BPJw2Hu6MBonFmJmPKaFjtyAj1HTu3z1A= 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= @@ -56,6 +54,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/pkg/lang-helper/lang-helper.go b/pkg/lang-helper/lang-helper.go new file mode 100644 index 00000000..b13dc415 --- /dev/null +++ b/pkg/lang-helper/lang-helper.go @@ -0,0 +1,19 @@ +// Package langhelper provides helper functions for language +package langhelper + +import ( + a "github.com/karincake/apem" + l "github.com/karincake/lepet" +) + +type Cfg struct { + LangCfg *l.LangCfg `yaml:"langCfg"` +} + +func Populate() { + cfg := &Cfg{ + LangCfg: &l.LangCfg{}, + } + a.ParseCfg(&cfg) + l.Init(cfg.LangCfg) +} From 974562e86a31257cb06411675c825d6a7c31cf07 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 12 Aug 2025 15:04:04 +0700 Subject: [PATCH 07/75] pre-dev: add logger --- go.mod | 3 +- go.sum | 6 +- .../use-case/_use-case-template/crud/case.go | 69 ++++++++++++++++--- pkg/logger/logger.go | 66 ++++++++++++++++++ 4 files changed, 133 insertions(+), 11 deletions(-) create mode 100644 pkg/logger/logger.go diff --git a/go.mod b/go.mod index ef9113ab..ba9efe29 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,8 @@ go 1.23.0 toolchain go1.23.11 require ( - github.com/karincake/apem v0.0.16-e + github.com/karincake/apem v0.0.16-g + github.com/karincake/dodol v0.0.1 github.com/karincake/lepet v0.0.1 gorm.io/gorm v1.25.10 ) diff --git a/go.sum b/go.sum index 5ff115b0..cd5f268c 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,10 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/karincake/apem v0.0.16-e h1:KGeQYmgNw8luidSWkZyGcMbW1PP3KMRCHMTEHQ7twU8= -github.com/karincake/apem v0.0.16-e/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= +github.com/karincake/apem v0.0.16-g h1:jPIr/YiaJhVSftdA1PyB2tlDiQtFeTVZohO1qf0qpw0= +github.com/karincake/apem v0.0.16-g/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= +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/lepet v0.0.1 h1:eq/cwn5BBg0jWZ1c/MmvhFIBma0zBpVs2LwkfDOncy4= github.com/karincake/lepet v0.0.1/go.mod h1:U84w7olXO3BPJw2Hu6MBonFmJmPKaFjtyAj1HTu3z1A= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= diff --git a/internal/use-case/_use-case-template/crud/case.go b/internal/use-case/_use-case-template/crud/case.go index 6312c950..e5800c43 100644 --- a/internal/use-case/_use-case-template/crud/case.go +++ b/internal/use-case/_use-case-template/crud/case.go @@ -5,11 +5,14 @@ Any functions that are available to be used externally. package crud import ( + "fmt" "strconv" dg "github.com/karincake/apem/db-gorm-pg" - lo "github.com/karincake/apem/logero" d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + "gorm.io/gorm" e "simrs-vx/internal/domain/_template/single" @@ -21,24 +24,74 @@ func Create(input e.Createdto) (*d.Data, error) { data := e.Single{} setData(&data, &input) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + event.Action = "Create" + event.Status = "started" + pl.SetLogInfo(event, input) err := dg.I.Transaction(func(tx *gorm.DB) error { - lo.I. for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + event.Action = mwName + event.Status = "started" + pl.SetLogInfo(event, data) + if err := createPreMw[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: mwErr, + } + return pl.SetLogError(event, data) } - } - slog. - if result, err := CreateData(&data, tx).Error; err != nil { - return nil + + event.Status = "completed" + pl.SetLogInfo(event, nil) } + event.Action = "DBCreate" + event.Status = "started" + pl.SetLogInfo(event, data) + if result, err := CreateData(&data, tx).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + event.Status = "completed" + pl.SetLogInfo(event, nil) + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + event.Action = mwName + event.Status = "started" + pl.SetLogInfo(event, input) if err := createPostMw[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: mwErr, + } + return pl.SetLogError(event, input) } } + event.Status = "completed" + pl.SetLogInfo(event, nil) + return nil }) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go new file mode 100644 index 00000000..2a9047ca --- /dev/null +++ b/pkg/logger/logger.go @@ -0,0 +1,66 @@ +// Package logger provides helper functions for logging +package logger + +import ( + "encoding/json" + + lz "github.com/karincake/apem/logger-zerolog" + d "github.com/karincake/dodol" + l "github.com/karincake/lepet" +) + +type Event struct { + // Context about the operation + Feature string // Feature area, e.g. "Create" + Action string // Action being performed, e.g. "DBCreate" + Source string // Source of event, usually present in each use case + Status string // e.g. "started", "failed", "success" + + // Error context + ErrInfo ErrorInfo +} + +type ErrorInfo struct { + Code string // used in lang json + Detail string + Raw error +} + +func SetLogInfo(e Event, data any) { + dataString, _ := json.Marshal(data) + lz.O.Info(). + String("source", e.Source). + String("feature", e.Feature). + String("action", e.Action). + String("status", "started"). + String("input", string(dataString)). + Send() +} + +func SetLogError(e Event, data any) error { + dataString, _ := json.Marshal(data) + msg := l.I.Msg(e.ErrInfo.Code) + + lz.O.Error(). + String("message", msg). + String("source", e.Source). + String("feature", e.Feature). + String("action", e.Action). + String("status", e.Status). + String("error_code", e.ErrInfo.Code). + String("error_detail", e.ErrInfo.Detail). + String("data", string(dataString)). + Send() + + if err, ok := e.ErrInfo.Raw.(d.FieldError); ok { + return err + } + if err, ok := e.ErrInfo.Raw.(d.FieldErrors); ok { + return err + } + + if e.ErrInfo.Detail != "" { + return d.FieldError{Code: e.ErrInfo.Code, Message: e.ErrInfo.Detail} + } + return d.FieldError{Code: e.ErrInfo.Code, Message: msg} +} From 7fe95b028294366d229f5b8ce3da4df518c15be3 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Tue, 12 Aug 2025 15:05:48 +0700 Subject: [PATCH 08/75] pre-dev: add logger --- internal/use-case/_use-case-template/crud/case.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/use-case/_use-case-template/crud/case.go b/internal/use-case/_use-case-template/crud/case.go index e5800c43..75adb080 100644 --- a/internal/use-case/_use-case-template/crud/case.go +++ b/internal/use-case/_use-case-template/crud/case.go @@ -85,7 +85,7 @@ func Create(input e.Createdto) (*d.Data, error) { Detail: fmt.Sprintf("Post-middleware %s failed", mwName), Raw: mwErr, } - return pl.SetLogError(event, input) + return pl.SetLogError(event, data) } } From 2e88eaf793fa47f089da5d8c297e0b03cd54b329 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 13 Aug 2025 14:23:51 +0700 Subject: [PATCH 09/75] pre-dev: add migration --- cmd/migration/config.yml-example | 47 ++++++++++++ cmd/migration/migration.go | 9 +++ go.mod | 7 +- go.sum | 2 + internal/interface/migration/migration.go | 93 +++++++++++++++++++++++ 5 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 cmd/migration/config.yml-example create mode 100644 cmd/migration/migration.go create mode 100644 internal/interface/migration/migration.go diff --git a/cmd/migration/config.yml-example b/cmd/migration/config.yml-example new file mode 100644 index 00000000..19893fd7 --- /dev/null +++ b/cmd/migration/config.yml-example @@ -0,0 +1,47 @@ +appCfg: + fullName: BPJS Bridge + codeName: simrs-vx + version: 0.1.0 + env: development + lang: en + +httpCfg: + host: + port: + +dbCfg: + dsn: + maxOpenConns: 5 + maxIdleConns: 5 + maxIdleTime: 100 + +loggerCfg: + hideTime: + hideLevel: + +msCfg: + dsn: + +langCfg: + active: + path: + fileName: + +minioCfg: + endpoint: + region: + accessKey: + secretKey: + useSsl: + bucketName: + - patient + +corsCfg: + allowedOrigin: + allowedMethod: + +satuSehatCfg: + host: localhsot:8200 + +bpjsCfg: + host: localhsot:8200 diff --git a/cmd/migration/migration.go b/cmd/migration/migration.go new file mode 100644 index 00000000..c225edf1 --- /dev/null +++ b/cmd/migration/migration.go @@ -0,0 +1,9 @@ +package main + +import ( + m "simrs-vx/internal/interface/migration" +) + +func main() { + m.Migrate() +} diff --git a/go.mod b/go.mod index ba9efe29..3d7e86f5 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,11 @@ toolchain go1.23.11 require ( github.com/karincake/apem v0.0.16-g github.com/karincake/dodol v0.0.1 + github.com/karincake/getuk v0.1.0 github.com/karincake/lepet v0.0.1 + golang.org/x/crypto v0.40.0 + gopkg.in/yaml.v3 v3.0.1 + gorm.io/driver/postgres v1.5.7 gorm.io/gorm v1.25.10 ) @@ -24,11 +28,8 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/nxadm/tail v1.4.11 // indirect github.com/rs/zerolog v1.33.0 // indirect - golang.org/x/crypto v0.40.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect golang.org/x/net v0.42.0 // indirect golang.org/x/sys v0.34.0 // indirect golang.org/x/text v0.27.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - gorm.io/driver/postgres v1.5.7 // indirect ) diff --git a/go.sum b/go.sum index cd5f268c..1550a098 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ github.com/karincake/apem v0.0.16-g h1:jPIr/YiaJhVSftdA1PyB2tlDiQtFeTVZohO1qf0qp github.com/karincake/apem v0.0.16-g/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= 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/lepet v0.0.1 h1:eq/cwn5BBg0jWZ1c/MmvhFIBma0zBpVs2LwkfDOncy4= github.com/karincake/lepet v0.0.1/go.mod h1:U84w7olXO3BPJw2Hu6MBonFmJmPKaFjtyAj1HTu3z1A= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go new file mode 100644 index 00000000..13abe812 --- /dev/null +++ b/internal/interface/migration/migration.go @@ -0,0 +1,93 @@ +package migration + +import ( + "flag" + "fmt" + "log" + "os" + "reflect" + + "gopkg.in/yaml.v3" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +type DbConf struct { + Dsn string + Dialect string +} + +// Migrate all tables at once, one time only for exam purpose +func Migrate() { + // use default config file location or use flat + cfgFile := "./config.yml" + flag.StringVar(&cfgFile, "config-file", "./config.yml", "Configuration path (default=./config.yaml)") + flag.Parse() + + // read the config file + yamlFile, err := os.ReadFile(cfgFile) + if err != nil { + log.Fatalf("%v", err) + } + + // parse into config struct + var dbConf DbConf + err = yaml.Unmarshal(yamlFile, &dbConf) + if err != nil { + log.Fatal(err) + } + log.Print("config is loaded successfully") + + // create database connection + db, err := gorm.Open(postgres.Open(dbConf.Dsn), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + SingularTable: true, + NoLowerCase: true, + }, + }) + if err != nil { + log.Fatal(err) + } + log.Print("database-connection is established successfully") + + // migrate all the tables + modelList := []any{ + // &single.Single{}}, // example + + } + + argsWithProg := os.Args + if len(argsWithProg) > 1 { + if argsWithProg[1] == "gradually" { + for _, v := range modelList { + name := "" + if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { + name = "*" + t.Elem().Name() + } else { + name = t.Name() + } + fmt.Println("Migrating ", name) + db.AutoMigrate(v) + } + } else { + for _, v := range modelList { + name := "" + if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { + name = "*" + t.Elem().Name() + } else { + name = t.Name() + } + if name == argsWithProg[1] { + fmt.Println("Migrating ", name) + db.AutoMigrate(v) + } + } + } + } else { + fmt.Println("Migrating all tables") + db.AutoMigrate(modelList...) + } + + log.Printf("migration is complete") +} From 7577c87f273c1a1589016d03aa74897cf5c75828 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 13 Aug 2025 14:26:14 +0700 Subject: [PATCH 10/75] feat (user): add create --- internal/domain/_template/single/dto.go | 4 +- internal/domain/main-entities/user/dto.go | 38 +++++++ internal/domain/main-entities/user/entity.go | 14 +++ .../use-case/_use-case-template/crud/case.go | 9 +- .../_use-case-template/crud/helper.go | 2 +- .../use-case/_use-case-template/crud/lib.go | 2 +- .../_use-case-template/crud/tycovar.go | 2 +- internal/use-case/main-use-case/user/case.go | 106 ++++++++++++++++++ .../use-case/main-use-case/user/helper.go | 24 ++++ internal/use-case/main-use-case/user/lib.go | 101 +++++++++++++++++ .../use-case/main-use-case/user/tycovar.go | 32 ++++++ pkg/password/password.go | 17 +++ 12 files changed, 342 insertions(+), 9 deletions(-) create mode 100644 internal/domain/main-entities/user/dto.go create mode 100644 internal/domain/main-entities/user/entity.go create mode 100644 internal/use-case/main-use-case/user/case.go create mode 100644 internal/use-case/main-use-case/user/helper.go create mode 100644 internal/use-case/main-use-case/user/lib.go create mode 100644 internal/use-case/main-use-case/user/tycovar.go create mode 100644 pkg/password/password.go diff --git a/internal/domain/_template/single/dto.go b/internal/domain/_template/single/dto.go index 472137a4..401ab571 100644 --- a/internal/domain/_template/single/dto.go +++ b/internal/domain/_template/single/dto.go @@ -1,6 +1,6 @@ package single -type Createdto struct { +type CreateDto struct { Code string `json:"code"` Name string `json:"name"` Description string `json:"description"` @@ -23,7 +23,7 @@ type ReadDetailDto struct { type Updatedto struct { Id uint `json:"id"` - Createdto + CreateDto } type Deletedto struct { diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go new file mode 100644 index 00000000..b1335f1d --- /dev/null +++ b/internal/domain/main-entities/user/dto.go @@ -0,0 +1,38 @@ +package user + +import erc "simrs-vx/internal/domain/references/common" + +type CreateDto struct { + Name string `json:"name"` + Password string `json:"password"` + Status_Code erc.StatusCode `json:"status_code"` +} + +type ReadListDto struct { + Name string `json:"name"` + 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 uint `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 int64 `json:"count"` +} diff --git a/internal/domain/main-entities/user/entity.go b/internal/domain/main-entities/user/entity.go new file mode 100644 index 00000000..ac83a6b2 --- /dev/null +++ b/internal/domain/main-entities/user/entity.go @@ -0,0 +1,14 @@ +package user + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" +) + +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 uint `json:"failedLoginCount"` +} diff --git a/internal/use-case/_use-case-template/crud/case.go b/internal/use-case/_use-case-template/crud/case.go index 75adb080..89036fb7 100644 --- a/internal/use-case/_use-case-template/crud/case.go +++ b/internal/use-case/_use-case-template/crud/case.go @@ -23,7 +23,7 @@ const source = "crud" func Create(input e.Createdto) (*d.Data, error) { data := e.Single{} - setData(&data, &input) + setData(input, &data) event := pl.Event{ Feature: "Create", @@ -47,7 +47,7 @@ func Create(input e.Createdto) (*d.Data, error) { event.ErrInfo = pl.ErrorInfo{ Code: "MW_PRE_FAILED", // TODO: add to lang json Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), - Raw: mwErr, + Raw: err, } return pl.SetLogError(event, data) } @@ -59,7 +59,8 @@ func Create(input e.Createdto) (*d.Data, error) { event.Action = "DBCreate" event.Status = "started" pl.SetLogInfo(event, data) - if result, err := CreateData(&data, tx).Error; err != nil { + result, err := CreateData(&data, tx) + if err != nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-create-fail", @@ -83,7 +84,7 @@ func Create(input e.Createdto) (*d.Data, error) { event.ErrInfo = pl.ErrorInfo{ Code: "MW_POST_FAILED", // TODO: add to lang json Detail: fmt.Sprintf("Post-middleware %s failed", mwName), - Raw: mwErr, + Raw: err, } return pl.SetLogError(event, data) } diff --git a/internal/use-case/_use-case-template/crud/helper.go b/internal/use-case/_use-case-template/crud/helper.go index 0d09eb8f..c1f2e6aa 100644 --- a/internal/use-case/_use-case-template/crud/helper.go +++ b/internal/use-case/_use-case-template/crud/helper.go @@ -5,7 +5,7 @@ Any functions that are used internally by the use-case package crud import ( - e "simrs-vx/internal/domain/main-entities/single" + e "simrs-vx/internal/domain/_template/single" ) func setData(src e.Createdto, dst *e.Single) { diff --git a/internal/use-case/_use-case-template/crud/lib.go b/internal/use-case/_use-case-template/crud/lib.go index 24ee2398..aa26c48d 100644 --- a/internal/use-case/_use-case-template/crud/lib.go +++ b/internal/use-case/_use-case-template/crud/lib.go @@ -16,7 +16,7 @@ func CreateData(input *e.Single, dbx ...*gorm.DB) (*e.Single, error) { tx = dg.I } - if err := tx.Create(&data).Error; err != nil { + if err := tx.Create(&input).Error; err != nil { return nil, err } diff --git a/internal/use-case/_use-case-template/crud/tycovar.go b/internal/use-case/_use-case-template/crud/tycovar.go index 17945a31..0a5c27fd 100644 --- a/internal/use-case/_use-case-template/crud/tycovar.go +++ b/internal/use-case/_use-case-template/crud/tycovar.go @@ -14,7 +14,7 @@ import ( e "simrs-vx/internal/domain/main-entities/single" ) -type createMw func(input *e.Createdto, data *e.Single, tx *gorm.DB) error +type createMw func(input *e.CreateDto, data *e.Single, tx *gorm.DB) error type readListMw func(input *e.ReadListDto, data *e.Single, tx *gorm.DB) error type readDetailMw func(input *e.ReadDetailDto, data *e.Single, tx *gorm.DB) error type updateMw func(input *e.ReadDetailDto, data *e.Single, tx *gorm.DB) error diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go new file mode 100644 index 00000000..779b344c --- /dev/null +++ b/internal/use-case/main-use-case/user/case.go @@ -0,0 +1,106 @@ +package user + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/user" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +const source = "user" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.User{} + + setData(input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + event.Action = "Create" + event.Status = "started" + pl.SetLogInfo(event, input) + + 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) + + 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) + } + + event.Status = "completed" + pl.SetLogInfo(event, nil) + } + + event.Action = "DBCreate" + event.Status = "started" + pl.SetLogInfo(event, data) + _, 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) + } + + event.Status = "completed" + pl.SetLogInfo(event, nil) + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + event.Action = mwName + event.Status = "started" + pl.SetLogInfo(event, input) + 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) + } + } + + event.Status = "completed" + pl.SetLogInfo(event, nil) + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "type": "list", + "status": "created", + }, + 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 new file mode 100644 index 00000000..e16c080c --- /dev/null +++ b/internal/use-case/main-use-case/user/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package user + +import ( + e "simrs-vx/internal/domain/main-entities/user" + + p "simrs-vx/pkg/password" +) + +func setData(src e.CreateDto, dst *e.User) error { + pass, err := p.Hash(src.Password) + if err != nil { + return err + } + + dst.Name = src.Name + dst.Password = pass + 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 new file mode 100644 index 00000000..27bbf221 --- /dev/null +++ b/internal/use-case/main-use-case/user/lib.go @@ -0,0 +1,101 @@ +package user + +import ( + e "simrs-vx/internal/domain/main-entities/user" + + 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) { + 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.User, *e.MetaDto, error) { + data := []e.User{} + 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.User{}). + // 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.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = count + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.User, error) { + data := e.User{} + + 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 err == gorm.ErrRecordNotFound { + return nil, nil + } + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.User, 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.User, 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/user/tycovar.go b/internal/use-case/main-use-case/user/tycovar.go new file mode 100644 index 00000000..6169fba5 --- /dev/null +++ b/internal/use-case/main-use-case/user/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 user + +import ( + "gorm.io/gorm" + + 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 + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var udpatePreMw []readDetailMw +var udpatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/pkg/password/password.go b/pkg/password/password.go new file mode 100644 index 00000000..fa506338 --- /dev/null +++ b/pkg/password/password.go @@ -0,0 +1,17 @@ +package password + +import ( + "golang.org/x/crypto/bcrypt" +) + +var Cost = 10 // can be set by consumer + +func Hash(password string) (string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), Cost) + return string(bytes), err +} + +func Check(password, hash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} From e364c742b2d0e04065d5bb96578da7ae1e2c21a3 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 13 Aug 2025 14:26:41 +0700 Subject: [PATCH 11/75] add domain references --- internal/domain/references/common/common.go | 40 +++ .../digital-signature/digital-signature.go | 26 ++ .../references/examination/examination.go | 44 +++ internal/domain/references/finance/finance.go | 67 +++++ .../references/organization/organization.go | 46 ++++ internal/domain/references/patient/patient.go | 85 ++++++ internal/domain/references/person/person.go | 252 ++++++++++++++++++ internal/domain/references/queue/queue.go | 3 + internal/domain/references/xtime/xtime.go | 31 +++ 9 files changed, 594 insertions(+) create mode 100644 internal/domain/references/common/common.go create mode 100644 internal/domain/references/digital-signature/digital-signature.go create mode 100644 internal/domain/references/examination/examination.go create mode 100644 internal/domain/references/finance/finance.go create mode 100644 internal/domain/references/organization/organization.go create mode 100644 internal/domain/references/patient/patient.go create mode 100644 internal/domain/references/person/person.go create mode 100644 internal/domain/references/queue/queue.go create mode 100644 internal/domain/references/xtime/xtime.go diff --git a/internal/domain/references/common/common.go b/internal/domain/references/common/common.go new file mode 100644 index 00000000..3382267a --- /dev/null +++ b/internal/domain/references/common/common.go @@ -0,0 +1,40 @@ +package common + +type ( + YaTidakCode byte + SudahBelumCode byte + AktifSimpelCode byte + AktifAdvanceCode byte + TersediaCode byte + StatusCode string +) + +const ( + TTTidak YaTidakCode = iota + TTYa +) + +const ( + BSBelum SudahBelumCode = iota + BSSudah +) +const ( + ASCInaktif AktifSimpelCode = iota + ASCAktif +) +const ( + AACBaru AktifAdvanceCode = iota + AACAktif + AACBlokir + AACHapus +) + +const ( + TCTidakTersedia TersediaCode = iota + TCTersedia +) + +const ( + SCActive StatusCode = "active" + SCInactive StatusCode = "inactive" +) diff --git a/internal/domain/references/digital-signature/digital-signature.go b/internal/domain/references/digital-signature/digital-signature.go new file mode 100644 index 00000000..4c8f2fe9 --- /dev/null +++ b/internal/domain/references/digital-signature/digital-signature.go @@ -0,0 +1,26 @@ +package digitalsignature + +type ( + RMEType string + SignType string +) + +const ( + // modules + RMETypePrescription RMEType = "prescription" + RMETypeExamination RMEType = "examination" + RMETypeRadiology RMEType = "radiology" + RMETypeSick RMEType = "sick" + RMETypeReferral RMEType = "referral" + RMETypeEndOfLife RMEType = "endoflife" + RMETypeChangeDpjp RMEType = "changedpjp" + + // employee + SignTypeEmployee SignType = "employee" + + // doctor + SignTypeDoctor SignType = "doctor" + + // patient + SignTypePatient SignType = "patient" +) diff --git a/internal/domain/references/examination/examination.go b/internal/domain/references/examination/examination.go new file mode 100644 index 00000000..4ca227db --- /dev/null +++ b/internal/domain/references/examination/examination.go @@ -0,0 +1,44 @@ +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/domain/references/finance/finance.go b/internal/domain/references/finance/finance.go new file mode 100644 index 00000000..bbf405e7 --- /dev/null +++ b/internal/domain/references/finance/finance.go @@ -0,0 +1,67 @@ +package finance + +type ( + PaymentMethodCode string + TaxCode string + PaymentStatusCode string + ServiceType string +) + +const ( + PMCCash PaymentMethodCode = "cash" + PMCBPJS PaymentMethodCode = "bpjs" + PMCInsurance PaymentMethodCode = "insurance" + PMCMembership PaymentMethodCode = "membership" + PMCDebit PaymentMethodCode = "debit" + PMCCredit PaymentMethodCode = "credit" + PMCOther PaymentMethodCode = "other" +) + +const ( + TCCountry TaxCode = "country" +) + +const ( + PaymentStatusNew PaymentStatusCode = "new" + PaymentStatusUnpaid PaymentStatusCode = "unpaid" + PaymentStatusPaid PaymentStatusCode = "paid" + PaymentStatusCancel PaymentStatusCode = "cancel" + PaymentStatusFailed PaymentStatusCode = "failed" +) + +func GetTaxeCodes() map[TaxCode]float32 { + return map[TaxCode]float32{ + TCCountry: 0.11, + } +} + +var NonInsurancePaymentMethods = map[PaymentMethodCode]bool{ + PMCCash: true, + PMCDebit: true, + PMCCredit: true, +} + +func (p PaymentMethodCode) IsInsurance() bool { + switch p { + case PMCCash, PMCDebit, PMCCredit, PMCBPJS: + return true + default: + return false + } +} + +const ( + STInpatient = "Rawat Inap" + STAmbulatory = "Rawat Jalan" + STEmergency = "IGD" + STPonek = "PONEK" + STLab = "Laboratorium" + STRadiology = "Radiologi" +) + +const ( + AdminEmergencyFee = "Biaya Administrasi IGD" + DoctorEmergencyFee = "Biaya Dokter IGD" + AdminPediatricInternalFee = "Biaya Administrasi Poli Anak/Penyakit Dalam" + AdminGeneralPolyFee = "Biaya Administrasi Poli" +) diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go new file mode 100644 index 00000000..f8c7879e --- /dev/null +++ b/internal/domain/references/organization/organization.go @@ -0,0 +1,46 @@ +package organization + +type ( + PositionCode string + QueuePositionCode 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" +) diff --git a/internal/domain/references/patient/patient.go b/internal/domain/references/patient/patient.go new file mode 100644 index 00000000..4332eca0 --- /dev/null +++ b/internal/domain/references/patient/patient.go @@ -0,0 +1,85 @@ +package patient + +type ( + ConsciousLevelCode string + StatusCode string + PaymentMethodCode string + EndAssessmentCode string + VisitTypeJknCode uint8 +) + +const ( + CLCAlert ConsciousLevelCode = "alert" + CLCVoice ConsciousLevelCode = "voice" + CLCPain ConsciousLevelCode = "pain" + CLCUnresponsive ConsciousLevelCode = "unresponsive" + CLCAnxious ConsciousLevelCode = "anxious" + CLCAcuteConfusional ConsciousLevelCode = "acute-confuncional" + + PMCCash PaymentMethodCode = "cash" + PMCDebit PaymentMethodCode = "debit" + PMCCredit PaymentMethodCode = "credit" + PMCBpjs PaymentMethodCode = "bpjs" + PMCMembership PaymentMethodCode = "membership" + PMCInsurance PaymentMethodCode = "insurance" + + SCDraft StatusCode = "draft" + SCActive StatusCode = "active" + SCInactive StatusCode = "inactive" + SCBlocked StatusCode = "blocked" + SCDead StatusCode = "dead" + + EACHomeRecom EndAssessmentCode = "home recommendation" + EACHomeReq EndAssessmentCode = "home request" + EACOtherPoly EndAssessmentCode = "others poly" + EACRefInt EndAssessmentCode = "referral internal" + EACRefExt EndAssessmentCode = "referral external" + EACDecease EndAssessmentCode = "decease" + + VTJCReference VisitTypeJknCode = 1 + VTJCInternalReference VisitTypeJknCode = 2 + VTJCControl VisitTypeJknCode = 3 + VTJCExternalReference VisitTypeJknCode = 4 +) + +func GetStatusCodes() map[StatusCode]string { + return map[StatusCode]string{ + SCDraft: "Draft", + SCActive: "Aktif", + SCInactive: "Tidak Aktif", + SCBlocked: "Diblokir", + SCDead: "Meninggal", + } +} + +func GetConsciousLevelCodes() map[ConsciousLevelCode]string { + return map[ConsciousLevelCode]string{ + CLCAlert: "Sadar Baik / Alert", + CLCVoice: "Berespon dengan kata-kata / Voice", + CLCPain: "Hanya beresponse jika dirangsang nyeri / pain", + CLCUnresponsive: "Pasien tidak sadar / unresponsive", + CLCAnxious: "Gelisah atau bingung", + CLCAcuteConfusional: "Acute Confusional States", + } +} + +func GetPaymentMethodCodes() map[PaymentMethodCode]string { + return map[PaymentMethodCode]string{ + PMCCash: "cash", + PMCDebit: "debit", + PMCCredit: "credit", + PMCBpjs: "bpjs", + PMCMembership: "membership", + PMCInsurance: "insurance"} +} + +func GetEndAssessments() map[EndAssessmentCode]string { + return map[EndAssessmentCode]string{ + EACHomeRecom: "home-recommendation", + EACHomeReq: "home-request", + EACOtherPoly: "other-poly", + EACRefInt: "referral-internal", + EACRefExt: "referral-external", + EACDecease: "decease", + } +} diff --git a/internal/domain/references/person/person.go b/internal/domain/references/person/person.go new file mode 100644 index 00000000..fdd1a30b --- /dev/null +++ b/internal/domain/references/person/person.go @@ -0,0 +1,252 @@ +package person + +type ( + GenderCode string + BloodTypeCode string + MaritalStatusCode string + ReligionCode string + EducationCode string + ProfessionCode string + AgeGroupCode string + AgeGroupForMedicineCode string + RelativeCode string +) + +const ( + GCMale GenderCode = "male" + GCFemale GenderCode = "female" + GCOther GenderCode = "other" + GCUnknown GenderCode = "unknown" +) + +const ( + BTCAPositive BloodTypeCode = "A+" + BTCANegative BloodTypeCode = "A-" + BTCBPositive BloodTypeCode = "B+" + BTCBNegative BloodTypeCode = "B-" + BTCABPositive BloodTypeCode = "AB+" + BTCABNegative BloodTypeCode = "AB-" + BTCOPositive BloodTypeCode = "O+" + BTCONegative BloodTypeCode = "O-" +) + +const ( + MSCBelumKawin MaritalStatusCode = "S" + MSCKawin MaritalStatusCode = "M" + MSCCeraiHidup MaritalStatusCode = "D" + MSCCeraiMati MaritalStatusCode = "W" +) + +const ( + RCIslam ReligionCode = "islam" + RCProtestan ReligionCode = "protestan" + RCKatolik ReligionCode = "katolik" + RCHindu ReligionCode = "hindu" + RCBudha ReligionCode = "budha" + RCKonghucu ReligionCode = "konghucu" + RCPenghayat ReligionCode = "penghayat" +) + +const ( + ECTidakSekolah EducationCode = "TS" + ECTK EducationCode = "TK" + ECSD EducationCode = "SD" + ECSLTP EducationCode = "SMP" + ECSLTA EducationCode = "SMA" + ECD1 EducationCode = "D1" + ECD2 EducationCode = "D2" + ECD3 EducationCode = "D3" + ECD4 EducationCode = "D4" + ECS1 EducationCode = "S1" + ECS2 EducationCode = "S2" + ECS3 EducationCode = "S3" +) + +const ( + PCTidakBekerja ProfessionCode = "-" + PCPns ProfessionCode = "pns" + PCTniPolri ProfessionCode = "tni-polri" + PCBumn ProfessionCode = "bumn" + PCWiraswasta ProfessionCode = "wiraswasta" + PCLainlain ProfessionCode = "lainnya" +) + +const ( + AGCEUnknown AgeGroupCode = "unkown" + AGCLTE5 AgeGroupCode = "LT5" + AGCEU19 AgeGroupCode = "UE19" + AGCEU29 AgeGroupCode = "UE29" + AGCEU39 AgeGroupCode = "UE39" + AGCEU49 AgeGroupCode = "UE49" + AGCEU59 AgeGroupCode = "UE50" + AGCGE60 AgeGroupCode = "E60" +) + +const ( + AGMCNew AgeGroupForMedicineCode = "new-born" + AGMCInfant AgeGroupForMedicineCode = "infant" + AGMCToddler AgeGroupForMedicineCode = "toddler" + AGMCKid AgeGroupForMedicineCode = "kid" + AGMCAdult AgeGroupForMedicineCode = "adult" +) + +const ( + RCMSuami RelativeCode = "suami" + RCMIstri RelativeCode = "istri" + RCMAnak RelativeCode = "anak" + RCMMenantu RelativeCode = "menantu" + RCMCucu RelativeCode = "cucu" + RCMOrangTua RelativeCode = "orang-tua" + RCMMertua RelativeCode = "mertua" + RCMAdik RelativeCode = "adik" + RCMKeponakan RelativeCode = "keponakan" + RCMKakak RelativeCode = "kakak" + RCMPaman RelativeCode = "paman" + RCMBibi RelativeCode = "bibi" + RCMPamanKakek RelativeCode = "kakek" + RCMPamanNenek RelativeCode = "nenek" +) + +func GetGenderCodes() map[GenderCode]string { + return map[GenderCode]string{ + GCMale: "Laki-laki", + GCFemale: "Perempuan", + GCOther: "Lainnya", + GCUnknown: "Tidak diketahui", + } +} + +func GetBloodTypeCodes() map[BloodTypeCode]string { + return map[BloodTypeCode]string{ + BTCAPositive: "A Positive", + BTCANegative: "A Negative", + BTCABPositive: "AB Positive", + BTCABNegative: "AB Negative", + BTCBPositive: "B Positive", + BTCBNegative: "B Negative", + BTCOPositive: "O Positive", + BTCONegative: "O Negative", + } +} + +func GetMaritalStatusCodes() map[MaritalStatusCode]string { + return map[MaritalStatusCode]string{ + MSCBelumKawin: "Belum Kawin", + MSCKawin: "Kawin", + MSCCeraiHidup: "Cerai Hidup", + MSCCeraiMati: "Cerai Mati", + } +} + +func GetReligionCodes() map[ReligionCode]string { + return map[ReligionCode]string{ + RCIslam: "Islam", + RCProtestan: "Kristen (Protestan)", + RCKatolik: "Katolik", + RCHindu: "Hindu", + RCBudha: "Budha", + RCKonghucu: "Konghucu", + RCPenghayat: "Penghayat", + } +} + +func GetEducationCodes() map[EducationCode]string { + return map[EducationCode]string{ + ECTidakSekolah: "Tidak Sekolah", + ECTK: "TK", + ECSD: "SD", + ECSLTP: "SMP sederajat", + ECSLTA: "SMP sederajat", + ECD1: "D1 sederajat", + ECD2: "D2 sederajat", + ECD3: "D3 sederajat", + ECD4: "D4 sederajat", + ECS1: "S1", + ECS2: "S3", + ECS3: "S3", + } +} + +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 GetAgeGroupCodes() map[AgeGroupCode]string { + return map[AgeGroupCode]string{ + AGCEUnknown: "unknown", + AGCLTE5: "<=5", + AGCEU19: "6-19", + AGCEU29: "20-29", + AGCEU39: "30-39", + AGCEU49: "40-49", + AGCEU59: "50-59", + AGCGE60: ">=60", + } +} + +func GetAgeGroupForMedicineCodes() map[AgeGroupForMedicineCode]string { + return map[AgeGroupForMedicineCode]string{ + AGMCNew: "new-born", + AGMCInfant: "infant", + AGMCToddler: "toddler", + AGMCKid: "kid", + AGMCAdult: "adult", + } +} + +func GetRelativeCodes() map[RelativeCode]string { + return map[RelativeCode]string{ + RCMSuami: "Suami", + RCMIstri: "Istri", + RCMAnak: "Anak", + RCMMenantu: "Menantu", + RCMCucu: "Cucu", + RCMOrangTua: "Orang Tua", + RCMMertua: "Mertua", + RCMAdik: "Adik", + RCMKeponakan: "Keponakan", + RCMKakak: "Kakak", + RCMPaman: "Paman", + RCMBibi: "Bibi", + RCMPamanKakek: "Kakek", + RCMPamanNenek: "Nenek", + } +} + +func (obj GenderCode) String() string { + return GetGenderCodes()[obj] +} + +func (obj BloodTypeCode) String() string { + return GetBloodTypeCodes()[obj] +} + +func (obj MaritalStatusCode) String() string { + return GetMaritalStatusCodes()[obj] +} + +func (obj ReligionCode) String() string { + return GetReligionCodes()[obj] +} +func (obj EducationCode) String() string { + return GetEducationCodes()[obj] +} + +func (obj ProfessionCode) String() string { + return GetProfessions()[obj] +} + +func (obj AgeGroupCode) String() string { + return GetAgeGroupCodes()[obj] +} + +func (obj RelativeCode) String() string { + return GetRelativeCodes()[obj] +} diff --git a/internal/domain/references/queue/queue.go b/internal/domain/references/queue/queue.go new file mode 100644 index 00000000..b36aa415 --- /dev/null +++ b/internal/domain/references/queue/queue.go @@ -0,0 +1,3 @@ +package queue + +const QueueName = "SABBI-QUEUE-" diff --git a/internal/domain/references/xtime/xtime.go b/internal/domain/references/xtime/xtime.go new file mode 100644 index 00000000..ae15bd32 --- /dev/null +++ b/internal/domain/references/xtime/xtime.go @@ -0,0 +1,31 @@ +package xtime + +type ( + DayCode byte +) + +const ( + DCMinggu DayCode = iota + DCSenin + DCSelasa + DCRabu + DCKamis + DCJumat + DCSabtu +) + +func GetDayCodes() map[DayCode]string { + return map[DayCode]string{ + DCMinggu: "Minggu", + DCSenin: "Senin", + DCSelasa: "Selasa", + DCRabu: "Rabu", + DCKamis: "Kamis", + DCJumat: "Jumat", + DCSabtu: "Sabtu", + } +} + +func (obj DayCode) String() string { + return GetDayCodes()[obj] +} From 389fd8e3ece47ccac5f2e337467883929b9111fa Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 14 Aug 2025 10:40:31 +0700 Subject: [PATCH 12/75] pre-dev: add gorm setting into extracalls --- go.mod | 5 +++-- go.sum | 4 ---- internal/infra/gorm-setting/gorm-setting.go | 19 +++++++++++++++++++ .../interface/main-handler/main-handler.go | 10 ++++++++-- 4 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 internal/infra/gorm-setting/gorm-setting.go diff --git a/go.mod b/go.mod index 3d7e86f5..21d0e33e 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,7 @@ toolchain go1.23.11 require ( github.com/karincake/apem v0.0.16-g github.com/karincake/dodol v0.0.1 - github.com/karincake/getuk v0.1.0 github.com/karincake/lepet v0.0.1 - golang.org/x/crypto v0.40.0 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/postgres v1.5.7 gorm.io/gorm v1.25.10 @@ -28,8 +26,11 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/nxadm/tail v1.4.11 // indirect github.com/rs/zerolog v1.33.0 // indirect + golang.org/x/crypto v0.40.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect golang.org/x/net v0.42.0 // indirect golang.org/x/sys v0.34.0 // indirect golang.org/x/text v0.27.0 // indirect ) + +replace github.com/karincake/apem => D:/Kuli/Sabbi/external/apem diff --git a/go.sum b/go.sum index 1550a098..7d1e7a14 100644 --- a/go.sum +++ b/go.sum @@ -20,12 +20,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/karincake/apem v0.0.16-g h1:jPIr/YiaJhVSftdA1PyB2tlDiQtFeTVZohO1qf0qpw0= -github.com/karincake/apem v0.0.16-g/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= 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/lepet v0.0.1 h1:eq/cwn5BBg0jWZ1c/MmvhFIBma0zBpVs2LwkfDOncy4= github.com/karincake/lepet v0.0.1/go.mod h1:U84w7olXO3BPJw2Hu6MBonFmJmPKaFjtyAj1HTu3z1A= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= diff --git a/internal/infra/gorm-setting/gorm-setting.go b/internal/infra/gorm-setting/gorm-setting.go new file mode 100644 index 00000000..95f18f0e --- /dev/null +++ b/internal/infra/gorm-setting/gorm-setting.go @@ -0,0 +1,19 @@ +package gormsetting + +import ( + dg "github.com/karincake/apem/db-gorm-pg" + // "gorm.io/gorm" + + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +func Adjust() { + dg.GormConfig = &gorm.Config{ + // Logger: logger.Default.LogMode(logger.Error), + NamingStrategy: schema.NamingStrategy{ + SingularTable: true, + NoLowerCase: true, + }, + } +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index b959178b..56c5b656 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -3,7 +3,13 @@ package handler import ( "net/http" - ///// PKG + /******************** external ********************/ + a "github.com/karincake/apem" + + /******************** infra ********************/ + gs "simrs-vx/internal/infra/gorm-setting" + + /******************** pkg ********************/ handlerlogger "simrs-vx/pkg/middleware/handler-logger" ///// Internal @@ -13,7 +19,7 @@ import ( // One place route to relatively easier to manage, ESPECIALLY in tracking func SetRoutes() http.Handler { ///// - // a.RegisterExtCall(gs.Adjust) + a.RegisterExtCall(gs.Adjust) r := http.NewServeMux() From 8bcf668013bd25b2cbdab8184dd575f3e70fe17a Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 14 Aug 2025 10:41:01 +0700 Subject: [PATCH 13/75] feat (infra-ss-db): add into extracalls --- cmd/main-api/config.yml-example | 6 ++++ internal/infra/ss-db/ss-db.go | 36 +++++++++++++++++++ internal/infra/ss-db/tycovar.go | 13 +++++++ .../interface/main-handler/main-handler.go | 2 ++ 4 files changed, 57 insertions(+) create mode 100644 internal/infra/ss-db/ss-db.go create mode 100644 internal/infra/ss-db/tycovar.go diff --git a/cmd/main-api/config.yml-example b/cmd/main-api/config.yml-example index 19893fd7..dfe3cb7e 100644 --- a/cmd/main-api/config.yml-example +++ b/cmd/main-api/config.yml-example @@ -15,6 +15,12 @@ dbCfg: maxIdleConns: 5 maxIdleTime: 100 +ssDbCfg: + dsn: + maxOpenConns: 5 + maxIdleConns: 5 + maxIdleTime: 100 + loggerCfg: hideTime: hideLevel: diff --git a/internal/infra/ss-db/ss-db.go b/internal/infra/ss-db/ss-db.go new file mode 100644 index 00000000..3c239540 --- /dev/null +++ b/internal/infra/ss-db/ss-db.go @@ -0,0 +1,36 @@ +package ssdb + +import ( + "log" + + a "github.com/karincake/apem" + lo "github.com/karincake/apem/loggero" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "gorm.io/gorm/schema" +) + +func Init() { + SetConfig() + NewInstance() +} + +func SetConfig() { + a.ParseSingleCfg(&Cfg) +} + +func NewInstance() { + // create database connection + db, err := gorm.Open(postgres.Open(Cfg.Dsn), &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + SingularTable: true, + NoLowerCase: true, + }, + }) + if err != nil { + log.Fatal(err) + } + + SSDb = db + lo.I.Println("Instantiation for satu-sehat database-connetion using db-gorm-pg, status: DONE!!") +} diff --git a/internal/infra/ss-db/tycovar.go b/internal/infra/ss-db/tycovar.go new file mode 100644 index 00000000..ff084508 --- /dev/null +++ b/internal/infra/ss-db/tycovar.go @@ -0,0 +1,13 @@ +package ssdb + +import "gorm.io/gorm" + +type SsDbCfg struct { + Dsn string + MaxOpenConns int `yaml:"maxOpenConns"` + MaxIdleConns int `yaml:"maxIdleConns"` + MaxIdleTime int `yaml:"maxIdleTime"` +} + +var Cfg SsDbCfg = SsDbCfg{} +var SSDb *gorm.DB diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 56c5b656..ef390c43 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -8,6 +8,7 @@ import ( /******************** infra ********************/ gs "simrs-vx/internal/infra/gorm-setting" + ssdb "simrs-vx/internal/infra/ss-db" /******************** pkg ********************/ handlerlogger "simrs-vx/pkg/middleware/handler-logger" @@ -20,6 +21,7 @@ import ( func SetRoutes() http.Handler { ///// a.RegisterExtCall(gs.Adjust) + a.RegisterExtCall(ssdb.Init) r := http.NewServeMux() From aa871a95bb2e300d47fafb77b21ad2013294fa21 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Thu, 14 Aug 2025 16:09:31 +0700 Subject: [PATCH 14/75] wip --- .vscode/launch.json | 14 +- atlas.hcl | 7 + .../20250814082958_auto_migration.sql | 12 ++ .../20250814083106_auto_migration.sql | 2 + .../20250814085334_auto_migration.sql | 2 + cmd/migration/migrations/atlas.sum | 4 + go.mod | 5 +- go.sum | 4 + internal/domain/base-entities/core/entity.go | 11 +- internal/domain/main-entities/user/entity.go | 4 +- internal/interface/migration/migration.go | 154 ++++++++++++------ 11 files changed, 153 insertions(+), 66 deletions(-) create mode 100644 atlas.hcl create mode 100644 cmd/migration/migrations/20250814082958_auto_migration.sql create mode 100644 cmd/migration/migrations/20250814083106_auto_migration.sql create mode 100644 cmd/migration/migrations/20250814085334_auto_migration.sql create mode 100644 cmd/migration/migrations/atlas.sum diff --git a/.vscode/launch.json b/.vscode/launch.json index e542bfc3..7098c42c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,12 +7,12 @@ "mode": "auto", "program": "${workspaceFolder}/cmd/main-api" }, - // { - // "name": "Launch Package excel migrator", - // "type": "go", - // "request": "launch", - // "mode": "auto", - // "program": "${workspaceFolder}/cmd/excelmigrator" - // } + { + "name": "Launch Package migratioon", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/migration" + } ] } \ No newline at end of file diff --git a/atlas.hcl b/atlas.hcl new file mode 100644 index 00000000..d00e8155 --- /dev/null +++ b/atlas.hcl @@ -0,0 +1,7 @@ +env "dev" { + url = "postgres://moko:password@localhost:5432/simrs_vx1?sslmode=disable" + dev = "docker://postgres/17/dev?search_path=public" + migration { + dir = "file://migrations" + } +} \ No newline at end of file diff --git a/cmd/migration/migrations/20250814082958_auto_migration.sql b/cmd/migration/migrations/20250814082958_auto_migration.sql new file mode 100644 index 00000000..e69f151c --- /dev/null +++ b/cmd/migration/migrations/20250814082958_auto_migration.sql @@ -0,0 +1,12 @@ +-- Create "User" table +CREATE TABLE "User" ( + "Id" bigserial NOT NULL, + "CreatedAt" text NULL, + "UpdatedAt" text NULL, + "DeteledAt" timestamptz NULL, + "Name" character varying(25) NOT NULL, + "Password" character varying(255) NOT NULL, + "Status_Code" character varying(10) NOT NULL, + "FailedLoginCount" smallint NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/migration/migrations/20250814083106_auto_migration.sql b/cmd/migration/migrations/20250814083106_auto_migration.sql new file mode 100644 index 00000000..1e80bf43 --- /dev/null +++ b/cmd/migration/migrations/20250814083106_auto_migration.sql @@ -0,0 +1,2 @@ +-- Modify "User" table +ALTER TABLE "User" ALTER COLUMN "Status_Code" TYPE character varying(11); diff --git a/cmd/migration/migrations/20250814085334_auto_migration.sql b/cmd/migration/migrations/20250814085334_auto_migration.sql new file mode 100644 index 00000000..e2b2a560 --- /dev/null +++ b/cmd/migration/migrations/20250814085334_auto_migration.sql @@ -0,0 +1,2 @@ +-- Modify "User" table +ALTER TABLE "User" ALTER COLUMN "CreatedAt" TYPE timestamptz; diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum new file mode 100644 index 00000000..493c211f --- /dev/null +++ b/cmd/migration/migrations/atlas.sum @@ -0,0 +1,4 @@ +h1:6uh16WKu8m2VzaFju4mLFjCrEA9FJmxEYP/bKU9bLV4= +20250814082958_auto_migration.sql h1:r1gxPLhQuUmRZhfBomI2gGVA1hR7B4eXF3bYJGA9uVE= +20250814083106_auto_migration.sql h1:CeUsjDrrfxEl+VGDX+azPCXSu88HKZr+VTzAba4p/Vk= +20250814085334_auto_migration.sql h1:RokGeINUPr9iFKuQRyx9HHVVm5HS6fxyTN91gcG1Hgc= diff --git a/go.mod b/go.mod index 21d0e33e..3d7e86f5 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,9 @@ toolchain go1.23.11 require ( github.com/karincake/apem v0.0.16-g github.com/karincake/dodol v0.0.1 + github.com/karincake/getuk v0.1.0 github.com/karincake/lepet v0.0.1 + golang.org/x/crypto v0.40.0 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/postgres v1.5.7 gorm.io/gorm v1.25.10 @@ -26,11 +28,8 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/nxadm/tail v1.4.11 // indirect github.com/rs/zerolog v1.33.0 // indirect - golang.org/x/crypto v0.40.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect golang.org/x/net v0.42.0 // indirect golang.org/x/sys v0.34.0 // indirect golang.org/x/text v0.27.0 // indirect ) - -replace github.com/karincake/apem => D:/Kuli/Sabbi/external/apem diff --git a/go.sum b/go.sum index 7d1e7a14..1550a098 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,12 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/karincake/apem v0.0.16-g h1:jPIr/YiaJhVSftdA1PyB2tlDiQtFeTVZohO1qf0qpw0= +github.com/karincake/apem v0.0.16-g/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= 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/lepet v0.0.1 h1:eq/cwn5BBg0jWZ1c/MmvhFIBma0zBpVs2LwkfDOncy4= github.com/karincake/lepet v0.0.1/go.mod h1:U84w7olXO3BPJw2Hu6MBonFmJmPKaFjtyAj1HTu3z1A= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= diff --git a/internal/domain/base-entities/core/entity.go b/internal/domain/base-entities/core/entity.go index 6a88e7af..fc8ab1f9 100644 --- a/internal/domain/base-entities/core/entity.go +++ b/internal/domain/base-entities/core/entity.go @@ -1,14 +1,17 @@ package core -import "gorm.io/gorm" +import ( + "time" + + "gorm.io/gorm" +) type Base struct { - CreatedAt string `json:"createdAt"` - UpdatedAt string `json:"updatedAt"` + CreatedAt time.Time `json:"createdAt" gorm:"type:timestamptz"` + UpdatedAt string `json:"updatedAt" gorm:"type:timestamptz"` DeteledAt gorm.DeletedAt `json:"deletedAt,omitempty"` } -// type Main struct { Id uint `json:"id" gorm:"primaryKey"` // depends on the system architecture Base diff --git a/internal/domain/main-entities/user/entity.go b/internal/domain/main-entities/user/entity.go index ac83a6b2..58aea3af 100644 --- a/internal/domain/main-entities/user/entity.go +++ b/internal/domain/main-entities/user/entity.go @@ -9,6 +9,6 @@ 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 uint `json:"failedLoginCount"` + Status_Code erc.StatusCode `json:"status_code" gorm:"not null;size:12"` + FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` } diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 13abe812..4de7d5d2 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -2,45 +2,124 @@ package migration import ( "flag" - "fmt" "log" "os" - "reflect" + "os/exec" "gopkg.in/yaml.v3" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/schema" + + eu "simrs-vx/internal/domain/main-entities/user" ) -type DbConf struct { - Dsn string - Dialect string +type Config struct { + DbCfg DbConf `yaml:"dbCfg"` +} + +type DbConf struct { + DSN string `yaml:"dsn"` + MaxOpenConns int `yaml:"maxOpenConns"` + MaxIdleConns int `yaml:"maxIdleConns"` + MaxIdleTime int `yaml:"maxIdleTime"` } -// Migrate all tables at once, one time only for exam purpose func Migrate() { - // use default config file location or use flat + // Your existing config loading code... cfgFile := "./config.yml" flag.StringVar(&cfgFile, "config-file", "./config.yml", "Configuration path (default=./config.yaml)") flag.Parse() - // read the config file yamlFile, err := os.ReadFile(cfgFile) if err != nil { log.Fatalf("%v", err) } - // parse into config struct - var dbConf DbConf - err = yaml.Unmarshal(yamlFile, &dbConf) + var cfg Config + err = yaml.Unmarshal(yamlFile, &cfg) if err != nil { log.Fatal(err) } - log.Print("config is loaded successfully") - // create database connection - db, err := gorm.Open(postgres.Open(dbConf.Dsn), &gorm.Config{ + argsWithProg := os.Args + if len(argsWithProg) > 1 { + switch argsWithProg[1] { + case "apply": + atlasApply(cfg.DbCfg.DSN) + case "generate": + atlasGenerate(cfg.DbCfg.DSN) + case "status": + atlasStatus(cfg.DbCfg.DSN) + case "gorm": + // Fallback to GORM if needed + gormMigrate(cfg.DbCfg) + default: + log.Println("Unknown command. Use: apply, generate, status, or gorm") + } + } else { + // Default: apply Atlas migrations + atlasApply(cfg.DbCfg.DSN) + } +} + +func atlasApply(url string) { + log.Println("Applying Atlas migrations...") + cmd := exec.Command("atlas", "migrate", "apply", + "--dir", "file://migrations", + "--url", url) + + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + log.Printf("Atlas migration failed: %v", err) + log.Println("Try running 'go run migration.go generate' first") + } else { + log.Println("Atlas migrations applied successfully") + } +} + +func atlasGenerate(url string) { + log.Println("Generating Atlas migration from GORM models...") + + // First, create tables with GORM to get the schema + log.Println("Step 1: Creating schema with GORM...") + gormCreateSchema(url) + + // Then inspect and create migration + log.Println("Step 2: Generating Atlas migration...") + cmd := exec.Command("atlas", "migrate", "diff", "auto_migration", + "--dir", "file://migrations", + "--dev-url", "docker://postgres/17/dev?search_path=public", + "--to", url) + + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + log.Printf("Atlas generation failed: %v", err) + } else { + log.Println("Atlas migration generated successfully") + } +} + +func atlasStatus(url string) { + log.Println("Checking Atlas migration status...") + cmd := exec.Command("atlas", "migrate", "status", + "--dir", "file://migrations", + "--url", url) + + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + log.Printf("Atlas status failed: %v", err) + } +} + +func gormCreateSchema(dsn string) { + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ NamingStrategy: schema.NamingStrategy{ SingularTable: true, NoLowerCase: true, @@ -49,45 +128,20 @@ func Migrate() { if err != nil { log.Fatal(err) } - log.Print("database-connection is established successfully") - // migrate all the tables modelList := []any{ - // &single.Single{}}, // example - + &eu.User{}, + // Add other models here } - argsWithProg := os.Args - if len(argsWithProg) > 1 { - if argsWithProg[1] == "gradually" { - for _, v := range modelList { - name := "" - if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { - name = "*" + t.Elem().Name() - } else { - name = t.Name() - } - fmt.Println("Migrating ", name) - db.AutoMigrate(v) - } - } else { - for _, v := range modelList { - name := "" - if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { - name = "*" + t.Elem().Name() - } else { - name = t.Name() - } - if name == argsWithProg[1] { - fmt.Println("Migrating ", name) - db.AutoMigrate(v) - } - } - } - } else { - fmt.Println("Migrating all tables") - db.AutoMigrate(modelList...) + if err := db.AutoMigrate(modelList...); err != nil { + log.Fatal(err) } - - log.Printf("migration is complete") + log.Println("Schema created with GORM") +} + +func gormMigrate(dbConf DbConf) { + // Your original GORM migrate code as fallback + log.Println("Using GORM AutoMigrate...") + // ... your existing GORM code here } From 848f7d5a03e70e4796f00e83599559b30cbc3535 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 15 Aug 2025 10:18:41 +0700 Subject: [PATCH 15/75] wip --- cmd/migration/atlas.hcl | 21 +++++++++++++++++++ .../20250814082958_auto_migration.sql | 12 ----------- .../20250814083106_auto_migration.sql | 2 -- .../20250814085334_auto_migration.sql | 2 -- cmd/migration/migrations/atlas.sum | 4 ---- 5 files changed, 21 insertions(+), 20 deletions(-) create mode 100644 cmd/migration/atlas.hcl delete mode 100644 cmd/migration/migrations/20250814082958_auto_migration.sql delete mode 100644 cmd/migration/migrations/20250814083106_auto_migration.sql delete mode 100644 cmd/migration/migrations/20250814085334_auto_migration.sql delete mode 100644 cmd/migration/migrations/atlas.sum diff --git a/cmd/migration/atlas.hcl b/cmd/migration/atlas.hcl new file mode 100644 index 00000000..220737ce --- /dev/null +++ b/cmd/migration/atlas.hcl @@ -0,0 +1,21 @@ +data "external_schema" "gorm" { + program = [ + "go", + "run", + "-mod=mod", + ".", + ] +} + +env "gorm" { + src = data.external_schema.gorm.url + dev = "postgres://moko:password@localhost:5432/simrs_vx1?sslmode=disable" + migration { + dir = "file://migrations" + } + format { + migrate { + diff = "{{ sql . \" \" }}" + } + } +} \ No newline at end of file diff --git a/cmd/migration/migrations/20250814082958_auto_migration.sql b/cmd/migration/migrations/20250814082958_auto_migration.sql deleted file mode 100644 index e69f151c..00000000 --- a/cmd/migration/migrations/20250814082958_auto_migration.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Create "User" table -CREATE TABLE "User" ( - "Id" bigserial NOT NULL, - "CreatedAt" text NULL, - "UpdatedAt" text NULL, - "DeteledAt" timestamptz NULL, - "Name" character varying(25) NOT NULL, - "Password" character varying(255) NOT NULL, - "Status_Code" character varying(10) NOT NULL, - "FailedLoginCount" smallint NULL, - PRIMARY KEY ("Id") -); diff --git a/cmd/migration/migrations/20250814083106_auto_migration.sql b/cmd/migration/migrations/20250814083106_auto_migration.sql deleted file mode 100644 index 1e80bf43..00000000 --- a/cmd/migration/migrations/20250814083106_auto_migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Modify "User" table -ALTER TABLE "User" ALTER COLUMN "Status_Code" TYPE character varying(11); diff --git a/cmd/migration/migrations/20250814085334_auto_migration.sql b/cmd/migration/migrations/20250814085334_auto_migration.sql deleted file mode 100644 index e2b2a560..00000000 --- a/cmd/migration/migrations/20250814085334_auto_migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Modify "User" table -ALTER TABLE "User" ALTER COLUMN "CreatedAt" TYPE timestamptz; diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum deleted file mode 100644 index 493c211f..00000000 --- a/cmd/migration/migrations/atlas.sum +++ /dev/null @@ -1,4 +0,0 @@ -h1:6uh16WKu8m2VzaFju4mLFjCrEA9FJmxEYP/bKU9bLV4= -20250814082958_auto_migration.sql h1:r1gxPLhQuUmRZhfBomI2gGVA1hR7B4eXF3bYJGA9uVE= -20250814083106_auto_migration.sql h1:CeUsjDrrfxEl+VGDX+azPCXSu88HKZr+VTzAba4p/Vk= -20250814085334_auto_migration.sql h1:RokGeINUPr9iFKuQRyx9HHVVm5HS6fxyTN91gcG1Hgc= From 61d0f91c3f05a213e86e5d5e4884a0f56d66a8bb Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 15 Aug 2025 10:21:59 +0700 Subject: [PATCH 16/75] wip --- atlas.hcl | 7 - go.mod | 34 ++-- go.sum | 178 +++++++++++++++++-- internal/domain/main-entities/user/entity.go | 2 +- internal/interface/migration/migration.go | 131 ++------------ 5 files changed, 195 insertions(+), 157 deletions(-) delete mode 100644 atlas.hcl diff --git a/atlas.hcl b/atlas.hcl deleted file mode 100644 index d00e8155..00000000 --- a/atlas.hcl +++ /dev/null @@ -1,7 +0,0 @@ -env "dev" { - url = "postgres://moko:password@localhost:5432/simrs_vx1?sslmode=disable" - dev = "docker://postgres/17/dev?search_path=public" - migration { - dir = "file://migrations" - } -} \ No newline at end of file diff --git a/go.mod b/go.mod index 3d7e86f5..f80d3909 100644 --- a/go.mod +++ b/go.mod @@ -1,35 +1,45 @@ module simrs-vx -go 1.23.0 +go 1.24 -toolchain go1.23.11 +toolchain go1.24.6 require ( - github.com/karincake/apem v0.0.16-g + ariga.io/atlas-provider-gorm v0.5.6 + 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/lepet v0.0.1 - golang.org/x/crypto v0.40.0 - gopkg.in/yaml.v3 v3.0.1 - gorm.io/driver/postgres v1.5.7 - gorm.io/gorm v1.25.10 + golang.org/x/crypto v0.41.0 + gorm.io/driver/postgres v1.5.11 + gorm.io/gorm v1.25.12 ) require ( + ariga.io/atlas v0.36.2-0.20250806044935-5bb51a0a956e // indirect github.com/go-redis/redis v6.15.9+incompatible // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.4.3 // indirect + github.com/jackc/pgx/v5 v5.5.5 // indirect + 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/kr/text v0.2.0 // 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 + 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/net v0.42.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.27.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.7 // indirect + gorm.io/driver/sqlite v1.5.7 // indirect + gorm.io/driver/sqlserver v1.5.4 // indirect ) diff --git a/go.sum b/go.sum index 1550a098..36a81d0f 100644 --- a/go.sum +++ b/go.sum @@ -1,27 +1,74 @@ +ariga.io/atlas v0.36.2-0.20250806044935-5bb51a0a956e h1:7upp27oOT/fmM5Dz3z9k8cmYwKJ2NAzuTqfT/rEP+50= +ariga.io/atlas v0.36.2-0.20250806044935-5bb51a0a956e/go.mod h1:Ex5l1xHsnWQUc3wYnrJ9gD7RUEzG76P7ZRQp8wNr0wc= +ariga.io/atlas-provider-gorm v0.5.6 h1:poMRZgIRvx/qIFtartefgOjCfgNIPBCdrVfkb5pIBQc= +ariga.io/atlas-provider-gorm v0.5.6/go.mod h1:9UmIoNjSAB6CHOrshEmR6sXUmqpLpIGWffBQigjQYDs= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +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/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= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= -github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= +github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/karincake/apem v0.0.16-g h1:jPIr/YiaJhVSftdA1PyB2tlDiQtFeTVZohO1qf0qpw0= -github.com/karincake/apem v0.0.16-g/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= +github.com/karincake/apem v0.0.16-h h1:rfO444oDG4cWFf0PjUshA+0U8KI/u067Va273WeJhpU= +github.com/karincake/apem v0.0.16-h/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM= 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= @@ -32,17 +79,28 @@ 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= +github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= +github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -52,33 +110,121 @@ github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM= -gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= -gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= -gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= +gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I= +gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= +gorm.io/driver/sqlserver v1.5.4 h1:xA+Y1KDNspv79q43bPyjDMUgHoYHLhXYmdFcYPobg8g= +gorm.io/driver/sqlserver v1.5.4/go.mod h1:+frZ/qYmuna11zHPlh5oc2O6ZA/lS88Keb0XSH1Zh/g= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/internal/domain/main-entities/user/entity.go b/internal/domain/main-entities/user/entity.go index 58aea3af..078c0577 100644 --- a/internal/domain/main-entities/user/entity.go +++ b/internal/domain/main-entities/user/entity.go @@ -9,6 +9,6 @@ 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:12"` + Status_Code erc.StatusCode `json:"status_code" gorm:"not null;size:10"` FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` } diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 4de7d5d2..15c214cb 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -1,17 +1,12 @@ package migration import ( - "flag" - "log" + "fmt" + "io" "os" - "os/exec" - - "gopkg.in/yaml.v3" - "gorm.io/driver/postgres" - "gorm.io/gorm" - "gorm.io/gorm/schema" - eu "simrs-vx/internal/domain/main-entities/user" + + "ariga.io/atlas-provider-gorm/gormschema" ) type Config struct { @@ -26,122 +21,16 @@ type DbConf struct { } func Migrate() { - // Your existing config loading code... - cfgFile := "./config.yml" - flag.StringVar(&cfgFile, "config-file", "./config.yml", "Configuration path (default=./config.yaml)") - flag.Parse() - - yamlFile, err := os.ReadFile(cfgFile) + stmts, err := gormschema.New("postgres").Load(getEntities()...) if err != nil { - log.Fatalf("%v", err) - } - - var cfg Config - err = yaml.Unmarshal(yamlFile, &cfg) - if err != nil { - log.Fatal(err) - } - - argsWithProg := os.Args - if len(argsWithProg) > 1 { - switch argsWithProg[1] { - case "apply": - atlasApply(cfg.DbCfg.DSN) - case "generate": - atlasGenerate(cfg.DbCfg.DSN) - case "status": - atlasStatus(cfg.DbCfg.DSN) - case "gorm": - // Fallback to GORM if needed - gormMigrate(cfg.DbCfg) - default: - log.Println("Unknown command. Use: apply, generate, status, or gorm") - } - } else { - // Default: apply Atlas migrations - atlasApply(cfg.DbCfg.DSN) + fmt.Fprintf(os.Stderr, "failed to load gorm schema: %v\n", err) + os.Exit(1) } + _, _ = io.WriteString(os.Stdout, stmts) } -func atlasApply(url string) { - log.Println("Applying Atlas migrations...") - cmd := exec.Command("atlas", "migrate", "apply", - "--dir", "file://migrations", - "--url", url) - - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if err := cmd.Run(); err != nil { - log.Printf("Atlas migration failed: %v", err) - log.Println("Try running 'go run migration.go generate' first") - } else { - log.Println("Atlas migrations applied successfully") - } -} - -func atlasGenerate(url string) { - log.Println("Generating Atlas migration from GORM models...") - - // First, create tables with GORM to get the schema - log.Println("Step 1: Creating schema with GORM...") - gormCreateSchema(url) - - // Then inspect and create migration - log.Println("Step 2: Generating Atlas migration...") - cmd := exec.Command("atlas", "migrate", "diff", "auto_migration", - "--dir", "file://migrations", - "--dev-url", "docker://postgres/17/dev?search_path=public", - "--to", url) - - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if err := cmd.Run(); err != nil { - log.Printf("Atlas generation failed: %v", err) - } else { - log.Println("Atlas migration generated successfully") - } -} - -func atlasStatus(url string) { - log.Println("Checking Atlas migration status...") - cmd := exec.Command("atlas", "migrate", "status", - "--dir", "file://migrations", - "--url", url) - - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if err := cmd.Run(); err != nil { - log.Printf("Atlas status failed: %v", err) - } -} - -func gormCreateSchema(dsn string) { - db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ - NamingStrategy: schema.NamingStrategy{ - SingularTable: true, - NoLowerCase: true, - }, - }) - if err != nil { - log.Fatal(err) - } - - modelList := []any{ +func getEntities() []any { + return []any{ &eu.User{}, - // Add other models here } - - if err := db.AutoMigrate(modelList...); err != nil { - log.Fatal(err) - } - log.Println("Schema created with GORM") -} - -func gormMigrate(dbConf DbConf) { - // Your original GORM migrate code as fallback - log.Println("Using GORM AutoMigrate...") - // ... your existing GORM code here } From db6af776a3e6ddc87b4cdca496bacc4bc7a07677 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 15 Aug 2025 12:12:33 +0700 Subject: [PATCH 17/75] done --- .gitignore | 1 + cmd/migration/atlas.hcl | 3 +- cmd/migration/atlas.hcl.example | 22 ++++++++++++ internal/interface/migration/migration.go | 43 +++++++++++++++++++++-- 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 cmd/migration/atlas.hcl.example diff --git a/.gitignore b/.gitignore index 904cf795..286b9405 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ go.work.sum # env file .env config.yml +cmd/migration/atlas.hcl # Editor/IDE # .idea/ diff --git a/cmd/migration/atlas.hcl b/cmd/migration/atlas.hcl index 220737ce..3372fb2d 100644 --- a/cmd/migration/atlas.hcl +++ b/cmd/migration/atlas.hcl @@ -9,10 +9,11 @@ data "external_schema" "gorm" { env "gorm" { src = data.external_schema.gorm.url - dev = "postgres://moko:password@localhost:5432/simrs_vx1?sslmode=disable" + 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 . \" \" }}" diff --git a/cmd/migration/atlas.hcl.example b/cmd/migration/atlas.hcl.example new file mode 100644 index 00000000..857d1352 --- /dev/null +++ b/cmd/migration/atlas.hcl.example @@ -0,0 +1,22 @@ +data "external_schema" "gorm" { + program = [ + "go", + "run", + "-mod=mod", + ".", + ] +} + +env "gorm" { + src = data.external_schema.gorm.url + dev = "" // dsn db to check the diff + migration { + dir = "file://migrations" + } + url = "" // dsn db to apply + format { + migrate { + diff = "{{ sql . \" \" }}" + } + } +} \ No newline at end of file diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 15c214cb..8a22efb0 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -4,9 +4,12 @@ import ( "fmt" "io" "os" + "os/exec" eu "simrs-vx/internal/domain/main-entities/user" "ariga.io/atlas-provider-gorm/gormschema" + "gorm.io/gorm" + "gorm.io/gorm/schema" ) type Config struct { @@ -20,8 +23,14 @@ type DbConf struct { MaxIdleTime int `yaml:"maxIdleTime"` } -func Migrate() { - stmts, err := gormschema.New("postgres").Load(getEntities()...) +func Loader() { + gormCfg := &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + SingularTable: true, + NoLowerCase: true, + }, + } + stmts, err := gormschema.New("postgres", gormschema.WithConfig(gormCfg)).Load(GetEntities()...) if err != nil { fmt.Fprintf(os.Stderr, "failed to load gorm schema: %v\n", err) os.Exit(1) @@ -29,8 +38,36 @@ func Migrate() { _, _ = io.WriteString(os.Stdout, stmts) } -func getEntities() []any { +func GetEntities() []any { return []any{ &eu.User{}, } } + +func runAtlas(args ...string) error { + cmd := exec.Command("atlas", args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func logMsg(msg string) { + fmt.Fprintln(os.Stderr, msg) +} + +func Migrate() { + Loader() + logMsg("Running atlas migrate diff...") + if err := runAtlas("migrate", "diff", "--env", "gorm"); err != nil { + logMsg(fmt.Sprintf("Failed to run diff: %v", err)) + return + } + + logMsg("Running atlas migrate apply...") + if err := runAtlas("migrate", "apply", "--env", "gorm"); err != nil { + logMsg(fmt.Sprintf("Failed to run apply: %v", err)) + return + } + + logMsg("Migration complete") +} From 0c5aa0becf90a4032a61176ccf460a297ed8bc85 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 18 Aug 2025 13:02:14 +0700 Subject: [PATCH 18/75] 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 19/75] 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 20/75] 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 21/75] 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 22/75] 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 23/75] 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 24/75] 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 25/75] 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 26/75] 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 27/75] 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 28/75] 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 29/75] 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 30/75] 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 31/75] 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 32/75] 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 33/75] 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 34/75] 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 35/75] 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 36/75] 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 37/75] 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 38/75] 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 39/75] 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 40/75] 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 41/75] 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 42/75] 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 43/75] 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 44/75] 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 45/75] 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 46/75] 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 47/75] 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 48/75] 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 49/75] 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 50/75] 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 51/75] 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 52/75] 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 53/75] 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 54/75] 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 55/75] 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 56/75] 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 57/75] 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 } From 0fa7e8ccde3d4124a891886926f278154b453742 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 14:27:25 +0700 Subject: [PATCH 58/75] fix reference/constlist --- cmd/migration/migrations/atlas.sum | 4 +- .../domain/main-entities/doctor-fee/dto.go | 10 +-- .../domain/main-entities/doctor-fee/entity.go | 4 +- internal/domain/main-entities/employee/dto.go | 8 +- .../domain/main-entities/employee/entity.go | 2 +- .../domain/main-entities/installation/dto.go | 26 +++--- .../main-entities/installation/entity.go | 8 +- .../main-entities/mcu-src-category/dto.go | 10 +-- .../main-entities/mcu-src-category/entity.go | 4 +- .../main-entities/practice-schedule/dto.go | 10 +-- .../main-entities/practice-schedule/entity.go | 4 +- internal/domain/main-entities/user/dto.go | 20 ++--- internal/domain/main-entities/user/entity.go | 16 ++-- .../domain/references/clinical/clinical.go | 40 ++++++--- internal/domain/references/common/common.go | 79 ++++++++++++++--- .../digital-signature/digital-signature.go | 26 ------ .../domain/references/encounter/encounter.go | 78 +++++++++++------ internal/domain/references/finance/finance.go | 67 --------------- .../references/organization/organization.go | 46 ++++++++-- internal/domain/references/patient/patient.go | 85 ------------------- internal/domain/references/person/person.go | 52 ++++++------ internal/domain/references/queue/queue.go | 3 - internal/domain/references/xtime/xtime.go | 31 ------- .../main-use-case/authentication/case.go | 4 +- internal/use-case/main-use-case/user/case.go | 4 +- 25 files changed, 281 insertions(+), 360 deletions(-) delete mode 100644 internal/domain/references/digital-signature/digital-signature.go delete mode 100644 internal/domain/references/finance/finance.go delete mode 100644 internal/domain/references/patient/patient.go delete mode 100644 internal/domain/references/queue/queue.go delete mode 100644 internal/domain/references/xtime/xtime.go diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index d3527869..65ea4bd7 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,2 +1,2 @@ -h1:MMNuESyEk0KZHA2z+7AukfG/ATboITROipz2wK3YNPg= -20250828092003.sql h1:Rr221/6KN53t0eoEHK5+sPeMaVsnKjN4322WLulN8AQ= +h1:kBvWq4ulyP8Gz3UPNE/UdpYtWBIpEQskVnanFmaFCRc= +20250828092003.sql h1:ZxYlga6zF0PsTCMisoQo5yUVNwilr0njJQF8mZuVS64= diff --git a/internal/domain/main-entities/doctor-fee/dto.go b/internal/domain/main-entities/doctor-fee/dto.go index 4d35d903..6052f984 100644 --- a/internal/domain/main-entities/doctor-fee/dto.go +++ b/internal/domain/main-entities/doctor-fee/dto.go @@ -4,19 +4,19 @@ 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" + ero "simrs-vx/internal/domain/references/organization" ) type CreateDto struct { Doctor_Id *uint `json:"doctor_id"` - FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code"` + FeeType_Code *ero.DoctorFeeTypeCode `json:"feeType_code"` Price *float64 `json:"price"` Item_Id *uint `json:"item_id"` } type ReadListDto struct { Doctor_Id *uint `json:"doctor_id"` - FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code"` + FeeType_Code *ero.DoctorFeeTypeCode `json:"feeType_code"` Price *float64 `json:"price"` Item_Id *uint `json:"item_id"` @@ -28,7 +28,7 @@ type ReadListDto struct { type ReadDetailDto struct { Id uint16 `json:"id"` Doctor_Id *uint `json:"doctor_id"` - FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code"` + FeeType_Code *ero.DoctorFeeTypeCode `json:"feeType_code"` Price *float64 `json:"price"` Item_Id *uint `json:"item_id"` } @@ -52,7 +52,7 @@ type ResponseDto struct { ecore.Main Doctor_Id *uint `json:"doctor_id"` Doctor *ed.Doctor `json:"doctor,omitempty"` - FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code"` + FeeType_Code *ero.DoctorFeeTypeCode `json:"feeType_code"` Price *float64 `json:"price"` Item_Id *uint `json:"item_id"` Item *ei.Item `json:"item,omitempty"` diff --git a/internal/domain/main-entities/doctor-fee/entity.go b/internal/domain/main-entities/doctor-fee/entity.go index af15173b..211e4148 100644 --- a/internal/domain/main-entities/doctor-fee/entity.go +++ b/internal/domain/main-entities/doctor-fee/entity.go @@ -4,14 +4,14 @@ 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" + ero "simrs-vx/internal/domain/references/organization" ) 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"` - FeeType_Code *erc.DoctorFeeTypeCode `json:"feeType_code" gorm:"size:11"` + FeeType_Code *ero.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/employee/dto.go b/internal/domain/main-entities/employee/dto.go index ff650793..eb7432ec 100644 --- a/internal/domain/main-entities/employee/dto.go +++ b/internal/domain/main-entities/employee/dto.go @@ -13,7 +13,7 @@ type CreateDto struct { Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Number *string `json:"number"` - Status_Code erc.StatusCode `json:"status_code"` + Status_Code erc.ActiveStatusCode `json:"status_code"` } type ReadListDto struct { @@ -22,7 +22,7 @@ type ReadListDto struct { Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Number *string `json:"number"` - Status_Code erc.StatusCode `json:"status_code"` + Status_Code erc.ActiveStatusCode `json:"status_code"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -36,7 +36,7 @@ type ReadDetailDto struct { Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Number *string `json:"number"` - Status_Code erc.StatusCode `json:"status_code"` + Status_Code erc.ActiveStatusCode `json:"status_code"` } type UpdateDto struct { @@ -62,7 +62,7 @@ type ResponseDto struct { Division_Code *string `json:"division_code"` Division *ed.Division `json:"division,omitempty"` Number *string `json:"number"` - Status_Code erc.StatusCode `json:"status_code"` + Status_Code erc.ActiveStatusCode `json:"status_code"` } func (d Employee) ToResponse() ResponseDto { diff --git a/internal/domain/main-entities/employee/entity.go b/internal/domain/main-entities/employee/entity.go index 55b829fa..15ca4ce9 100644 --- a/internal/domain/main-entities/employee/entity.go +++ b/internal/domain/main-entities/employee/entity.go @@ -15,5 +15,5 @@ type Employee struct { 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"` + Status_Code erc.ActiveStatusCode `json:"status_code" gorm:"not null;size:10"` } diff --git a/internal/domain/main-entities/installation/dto.go b/internal/domain/main-entities/installation/dto.go index 66ce57ff..d3691c03 100644 --- a/internal/domain/main-entities/installation/dto.go +++ b/internal/domain/main-entities/installation/dto.go @@ -6,15 +6,15 @@ import ( ) type CreateDto struct { - Code string `json:"code"` - Name string `json:"name"` - EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code"` } type ReadListDto struct { - Code string `json:"code"` - Name string `json:"name"` - EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -22,10 +22,10 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code"` } type UpdateDto struct { @@ -45,9 +45,9 @@ type MetaDto struct { type ResponseDto struct { ecore.SmallMain - Code string `json:"code"` - Name string `json:"name"` - EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code"` } func (d Installation) ToResponse() ResponseDto { diff --git a/internal/domain/main-entities/installation/entity.go b/internal/domain/main-entities/installation/entity.go index 203b231c..0cd5b7dd 100644 --- a/internal/domain/main-entities/installation/entity.go +++ b/internal/domain/main-entities/installation/entity.go @@ -6,8 +6,8 @@ import ( ) type Installation struct { - ecore.SmallMain // adjust this according to the needs - 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"` + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"unique;size:10"` + Name string `json:"name" gorm:"size:50"` + EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code" gorm:"size:10"` } diff --git a/internal/domain/main-entities/mcu-src-category/dto.go b/internal/domain/main-entities/mcu-src-category/dto.go index f78eb6a9..6c48beb3 100644 --- a/internal/domain/main-entities/mcu-src-category/dto.go +++ b/internal/domain/main-entities/mcu-src-category/dto.go @@ -2,19 +2,19 @@ package division import ( ecore "simrs-vx/internal/domain/base-entities/core" - erc "simrs-vx/internal/domain/references/clinical" + ere "simrs-vx/internal/domain/references/encounter" ) type CreateDto struct { Code string `json:"code"` Name string `json:"name"` - Scope_Code *erc.CheckupScopeCode `json:"scope_code"` + Scope_Code *ere.CheckupScopeCode `json:"scope_code"` } type ReadListDto struct { Code string `json:"code"` Name string `json:"name"` - Scope_Code *erc.CheckupScopeCode `json:"scope_code"` + Scope_Code *ere.CheckupScopeCode `json:"scope_code"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -25,7 +25,7 @@ type ReadDetailDto struct { Id uint16 `json:"id"` Code string `json:"code"` Name string `json:"name"` - Scope_Code *erc.CheckupScopeCode `json:"scope_code"` + Scope_Code *ere.CheckupScopeCode `json:"scope_code"` } type UpdateDto struct { @@ -47,7 +47,7 @@ type ResponseDto struct { ecore.SmallMain Code string `json:"code"` Name string `json:"name"` - Scope_Code *erc.CheckupScopeCode `json:"scope_code"` + Scope_Code *ere.CheckupScopeCode `json:"scope_code"` } func (d McuSrcCategory) ToResponse() ResponseDto { diff --git a/internal/domain/main-entities/mcu-src-category/entity.go b/internal/domain/main-entities/mcu-src-category/entity.go index 61921168..21c266e3 100644 --- a/internal/domain/main-entities/mcu-src-category/entity.go +++ b/internal/domain/main-entities/mcu-src-category/entity.go @@ -2,12 +2,12 @@ package division import ( ecore "simrs-vx/internal/domain/base-entities/core" - erc "simrs-vx/internal/domain/references/clinical" + ere "simrs-vx/internal/domain/references/encounter" ) 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"` + Scope_Code *ere.CheckupScopeCode `json:"scope_code" gorm:"size:10"` } diff --git a/internal/domain/main-entities/practice-schedule/dto.go b/internal/domain/main-entities/practice-schedule/dto.go index 2f6cda94..ea09c0d9 100644 --- a/internal/domain/main-entities/practice-schedule/dto.go +++ b/internal/domain/main-entities/practice-schedule/dto.go @@ -2,13 +2,13 @@ package practiceschedule import ( ecore "simrs-vx/internal/domain/base-entities/core" - erx "simrs-vx/internal/domain/references/xtime" + erc "simrs-vx/internal/domain/references/common" ) type CreateDto struct { Doctor_Id *uint `json:"doctor_id"` Unit_Code *string `json:"unit_code"` - Day_Code *erx.DayCode `json:"day_code"` + Day_Code *erc.DayCode `json:"day_code"` StartTime *string `json:"startTime"` EndTime *string `json:"endTime"` } @@ -16,7 +16,7 @@ type CreateDto struct { type ReadListDto struct { Doctor_Id *uint `json:"doctor_id"` Unit_Code *string `json:"unit_code"` - Day_Code *erx.DayCode `json:"day_code"` + Day_Code *erc.DayCode `json:"day_code"` StartTime *string `json:"startTime"` EndTime *string `json:"endTime"` @@ -29,7 +29,7 @@ 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"` + Day_Code *erc.DayCode `json:"day_code"` StartTime *string `json:"startTime"` EndTime *string `json:"endTime"` } @@ -53,7 +53,7 @@ type ResponseDto struct { ecore.Main Doctor_Id *uint `json:"doctor_id"` Unit_Code *string `json:"unit_code"` - Day_Code *erx.DayCode `json:"day_code"` + Day_Code *erc.DayCode `json:"day_code"` StartTime *string `json:"startTime"` EndTime *string `json:"endTime"` } diff --git a/internal/domain/main-entities/practice-schedule/entity.go b/internal/domain/main-entities/practice-schedule/entity.go index 5bd1c006..524867c8 100644 --- a/internal/domain/main-entities/practice-schedule/entity.go +++ b/internal/domain/main-entities/practice-schedule/entity.go @@ -4,7 +4,7 @@ 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" + erc "simrs-vx/internal/domain/references/common" ) type PracticeSchedule struct { @@ -13,7 +13,7 @@ type PracticeSchedule struct { 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"` + Day_Code *erc.DayCode `json:"day_code"` StartTime *string `json:"startTime" gorm:"size:5"` EndTime *string `json:"endTime" gorm:"size:5"` } diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index 98c3a2d1..7ac5715c 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -7,14 +7,14 @@ import ( ) type CreateDto struct { - Name string `json:"name"` - Password string `json:"password"` - Status_Code erc.StatusCode `json:"status_code"` + Name string `json:"name"` + Password string `json:"password"` + Status_Code erc.UserStatusCode `json:"status_code"` } type ReadListDto struct { - Name string `json:"name"` - Status_Code erc.StatusCode `json:"status_code"` + Name string `json:"name"` + Status_Code erc.UserStatusCode `json:"status_code"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -49,11 +49,11 @@ type LoginDto struct { 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"` + Name string `json:"name"` + Status_Code erc.UserStatusCode `json:"status_code"` + FailedLoginCount uint8 `json:"failedLoginCount"` + LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"` + LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` } func (d *User) ToResponse() ResponseDto { diff --git a/internal/domain/main-entities/user/entity.go b/internal/domain/main-entities/user/entity.go index f69e03ca..0db3beea 100644 --- a/internal/domain/main-entities/user/entity.go +++ b/internal/domain/main-entities/user/entity.go @@ -7,12 +7,12 @@ import ( ) 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"` - LoginAttemptCount int `json:"-"` - LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"` - LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"` + 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.UserStatusCode `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/clinical/clinical.go b/internal/domain/references/clinical/clinical.go index f1be0605..3998811b 100644 --- a/internal/domain/references/clinical/clinical.go +++ b/internal/domain/references/clinical/clinical.go @@ -1,18 +1,38 @@ package clinical type ( - CheckupScopeCode string - DoctorFeeTypeCode string + SubjectCode string + ObjectCode string + AssessmentCode string + InstructionCode string ) const ( - CSCLab CheckupScopeCode = "lab" // Laboratorium - CSCMLab CheckupScopeCode = "mic-lab" // Microbacterial Laboratorium - CSCPLab CheckupScopeCode = "pa-lab" // Patology Anatomy Laboratorium - CSCRad CheckupScopeCode = "radiology" // Radiology + SCPrimaryComplaint SubjectCode = "pri-compl" // Keluhan Utama + SCSecComplaint SubjectCode = "sec-compl" // Secondary Complaint + SCCurrentDiseaseHistory SubjectCode = "cur-disea-hist" // Current Disease History + SCPastDiseaseHistory SubjectCode = "pas-disea-hist" // Past Disease History + SCFamilyDiseaseHistory SubjectCode = "fam-disea-hist" // Family Disease History + SCAllergyHistory SubjectCode = "alg-hist" // Allergic History + SCAllergyReaction SubjectCode = "alg-react" // Allergic Reaction + SCMedicationHistory SubjectCode = "med-hist" // Medication History - DFTCOut DoctorFeeTypeCode = "outpatient" // Rawat Jalan - DFTCInp DoctorFeeTypeCode = "inpatient" // Rawat Inap - DFTCEme DoctorFeeTypeCode = "emergency" // Darurat - DFTCReh DoctorFeeTypeCode = "medic-rehab" // Rehab Medik + OCConsciousnessLevel ObjectCode = "consc-level" // Tingkat Kesadaran + OCConsciousnessLevelDet ObjectCode = "consc-level-det" // Detail Tingkat Kesadaran + OCSystolicBloodPressure ObjectCode = "syst-bp" // Tekanan Darah Systolic + OCDiastolicBloodPressure ObjectCode = "diast-bp" // Tekanan Darah Diastolic + OCHeartRate ObjectCode = "hear-rt" // Detak Jantung + OCTemperature ObjectCode = "temp" // Suhu + OCSpO2 ObjectCode = "spo2" // SpO2 + OCWeight ObjectCode = "weight" // Berat Badan + OCHeight ObjectCode = "height" // Tinggi Badan + + ACEarlyDiag AssessmentCode = "early-diag" // Diagnosis Awal + ACLateDiag AssessmentCode = "late-diag" // Diagnosis Akhir + ACSecDiag AssessmentCode = "sec-diag" // Diagnosis Sekunder + + ICDetail InstructionCode = "detail" // Detail instruksi + ICMedAct InstructionCode = "med-act" // Tindakan medis + ICMedication InstructionCode = "medication" // Obat + ICMaterial InstructionCode = "material" // BMHP ) diff --git a/internal/domain/references/common/common.go b/internal/domain/references/common/common.go index 7f6fed2b..d60ee8a3 100644 --- a/internal/domain/references/common/common.go +++ b/internal/domain/references/common/common.go @@ -1,12 +1,17 @@ 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 + DayCode byte + ActiveStatusCode string + DataStatusCode string + UserStatusCode string + TimeUnitCode string + PaymentMethodCode string ) const ( @@ -35,9 +40,61 @@ const ( ) const ( - SCNew StatusCode = "new" - SCActive StatusCode = "active" - SCInactive StatusCode = "inactive" - SCBlocked StatusCode = "blocked" - SCSuspended StatusCode = "suspended" + DCMinggu DayCode = iota + DCSenin + DCSelasa + DCRabu + DCKamis + DCJumat + DCSabtu ) + +const ( + SCActive ActiveStatusCode = "active" // Aktif + SCInactive ActiveStatusCode = "inactive" // Tidak aktif + + DSCNew DataStatusCode = "new" // Baru + DSCReview DataStatusCode = "review" // Review + DSCProcess DataStatusCode = "process" // Proses + DSCDone DataStatusCode = "done" // Selesai + DSCCancel DataStatusCode = "cancel" // Dibatalkan + DSCRejected DataStatusCode = "rejected" // Ditolak + DSCSkipped DataStatusCode = "skipped" // Dilewati + + USCNew UserStatusCode = "new" // Baru + USCActive UserStatusCode = "active" // Aktif + USCInactive UserStatusCode = "inactive" // Tidak aktif + USCBlocked UserStatusCode = "blocked" // Diblokir + USCSuspended UserStatusCode = "suspended" // Dibekukan + + TUCSec TimeUnitCode = "sec" // Detik + TUCMin TimeUnitCode = "min" // Menit + TUCHour TimeUnitCode = "hour" // Jam + TUCDay TimeUnitCode = "day" // Hari + TUCWeek TimeUnitCode = "week" // Minggu + TUCMonth TimeUnitCode = "month" // Bulan + TUCYear TimeUnitCode = "year" // Tahun + + PMCCash PaymentMethodCode = "cash" // Tunai + PMCDebit PaymentMethodCode = "debit" // Debet + PMCCredit PaymentMethodCode = "credit" // Kredit + PMCInsurance PaymentMethodCode = "insurance" // Asuransi + PMCMembership PaymentMethodCode = "membership" // Member + +) + +func GetDayCodes() map[DayCode]string { + return map[DayCode]string{ + DCMinggu: "Minggu", + DCSenin: "Senin", + DCSelasa: "Selasa", + DCRabu: "Rabu", + DCKamis: "Kamis", + DCJumat: "Jumat", + DCSabtu: "Sabtu", + } +} + +func (obj DayCode) String() string { + return GetDayCodes()[obj] +} diff --git a/internal/domain/references/digital-signature/digital-signature.go b/internal/domain/references/digital-signature/digital-signature.go deleted file mode 100644 index 4c8f2fe9..00000000 --- a/internal/domain/references/digital-signature/digital-signature.go +++ /dev/null @@ -1,26 +0,0 @@ -package digitalsignature - -type ( - RMEType string - SignType string -) - -const ( - // modules - RMETypePrescription RMEType = "prescription" - RMETypeExamination RMEType = "examination" - RMETypeRadiology RMEType = "radiology" - RMETypeSick RMEType = "sick" - RMETypeReferral RMEType = "referral" - RMETypeEndOfLife RMEType = "endoflife" - RMETypeChangeDpjp RMEType = "changedpjp" - - // employee - SignTypeEmployee SignType = "employee" - - // doctor - SignTypeDoctor SignType = "doctor" - - // patient - SignTypePatient SignType = "patient" -) diff --git a/internal/domain/references/encounter/encounter.go b/internal/domain/references/encounter/encounter.go index 941b0cae..00b01236 100644 --- a/internal/domain/references/encounter/encounter.go +++ b/internal/domain/references/encounter/encounter.go @@ -1,32 +1,63 @@ package encounter type ( - EncounterStatus string - EncounterClass string - EmergencyClass string - InpatientClass string + EncounterClassCode string + QueueStatusCode string + DischargeMethodCode string + TransportationCode string + PersonConditionCode string + EmergencyClassCode string + OutpatientClassCode string + CheckupScopeCode 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" - ECOutpatient EncounterClass = "outpatient" - ECInpatient EncounterClass = "inpatient" - ECEmergency EncounterClass = "emergency" - ECRadiology EncounterClass = "radiology" + ECOutpatient EncounterClassCode = "outpatient" + ECAmbulatory EncounterClassCode = "ambulatory" + ECEmergency EncounterClassCode = "emergency" + ECInpatient EncounterClassCode = "inpatient" + ECDraft EncounterClassCode = "draft" + ECDone EncounterClassCode = "done" + ECCancel EncounterClassCode = "cancel" + ECSkip EncounterClassCode = "skip" + + QSCWait QueueStatusCode = "wait" // Tunggu + QSCProc QueueStatusCode = "proc" // Proses + QSCDone QueueStatusCode = "done" // Selesai + QSCCancel QueueStatusCode = "cancel" // Dibatalkan + QSCSkip QueueStatusCode = "skip" // Dilewati + + DMCHome DischargeMethodCode = "home" // Rumah + DMCHomeReq DischargeMethodCode = "home-request" // Rumah (Dibutuhkan) + + TCAmbulance TransportationCode = "ambulance" + TCCar TransportationCode = "car" + TCMotorCycle TransportationCode = "motor-cycle" + TCOther TransportationCode = "other" + + PCCRes PersonConditionCode = "res" // Resutiasi + PCCEmg PersonConditionCode = "emg" // Darurat + PCCUrg PersonConditionCode = "urg" // Mendesak + PCCLurg PersonConditionCode = "lurg" // Kurang mendesak + PCCNurg PersonConditionCode = "nurg" // + PCCDoa PersonConditionCode = "doa" // Meninggal saat tiba + + ECCEmg EmergencyClassCode = "emg" // Darurat/Emergency biasa + ECCEon EmergencyClassCode = "eon" // Ponek/Emergency obstetri neonatal + + OCCOp OutpatientClassCode = "op" // Rawat Jalan + OCCIcu OutpatientClassCode = "icu" // ICU + OCCHcu OutpatientClassCode = "hcu" // HCU + OCCVk OutpatientClassCode = "vk" // Verlos kamer + + CSCLab CheckupScopeCode = "lab" // Laboratorium + CSCMLab CheckupScopeCode = "mic-lab" // Microbacterial Laboratorium + CSCPLab CheckupScopeCode = "pa-lab" // Patology Anatomy Laboratorium + CSCRad CheckupScopeCode = "radiology" // Radiology + ) -func (ec EncounterClass) Code() string { +func (ec EncounterClassCode) Code() string { switch ec { case ECAmbulatory, ECOutpatient: return "AMB" @@ -38,8 +69,3 @@ func (ec EncounterClass) Code() string { return "UNKNOWN" } } - -const ( - ICU InpatientClass = "ICU" - NonICU InpatientClass = "non ICU" -) diff --git a/internal/domain/references/finance/finance.go b/internal/domain/references/finance/finance.go deleted file mode 100644 index bbf405e7..00000000 --- a/internal/domain/references/finance/finance.go +++ /dev/null @@ -1,67 +0,0 @@ -package finance - -type ( - PaymentMethodCode string - TaxCode string - PaymentStatusCode string - ServiceType string -) - -const ( - PMCCash PaymentMethodCode = "cash" - PMCBPJS PaymentMethodCode = "bpjs" - PMCInsurance PaymentMethodCode = "insurance" - PMCMembership PaymentMethodCode = "membership" - PMCDebit PaymentMethodCode = "debit" - PMCCredit PaymentMethodCode = "credit" - PMCOther PaymentMethodCode = "other" -) - -const ( - TCCountry TaxCode = "country" -) - -const ( - PaymentStatusNew PaymentStatusCode = "new" - PaymentStatusUnpaid PaymentStatusCode = "unpaid" - PaymentStatusPaid PaymentStatusCode = "paid" - PaymentStatusCancel PaymentStatusCode = "cancel" - PaymentStatusFailed PaymentStatusCode = "failed" -) - -func GetTaxeCodes() map[TaxCode]float32 { - return map[TaxCode]float32{ - TCCountry: 0.11, - } -} - -var NonInsurancePaymentMethods = map[PaymentMethodCode]bool{ - PMCCash: true, - PMCDebit: true, - PMCCredit: true, -} - -func (p PaymentMethodCode) IsInsurance() bool { - switch p { - case PMCCash, PMCDebit, PMCCredit, PMCBPJS: - return true - default: - return false - } -} - -const ( - STInpatient = "Rawat Inap" - STAmbulatory = "Rawat Jalan" - STEmergency = "IGD" - STPonek = "PONEK" - STLab = "Laboratorium" - STRadiology = "Radiologi" -) - -const ( - AdminEmergencyFee = "Biaya Administrasi IGD" - DoctorEmergencyFee = "Biaya Dokter IGD" - AdminPediatricInternalFee = "Biaya Administrasi Poli Anak/Penyakit Dalam" - AdminGeneralPolyFee = "Biaya Administrasi Poli" -) diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index bad128d6..de9cff1c 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -2,15 +2,45 @@ package organization type ( EmployeePosisitionCode string + ItemGroupCoode string + InfraGroupCode string + UnitTypeCode string + DoctorFeeTypeCode string ) 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" + EPCDoc EmployeePosisitionCode = "doctor" // Dokter + EPCNur EmployeePosisitionCode = "nurse" // Perawat + EPCNut EmployeePosisitionCode = "nutritionist" // Ahli gizi + EPCLab EmployeePosisitionCode = "laborant" // Laboran + EPCPha EmployeePosisitionCode = "pharmacy" // Farmasi + EPCPay EmployeePosisitionCode = "payment" // Pembayaran + EPCPav EmployeePosisitionCode = "payment-verificator" // Konfirmasi pembayaran + EPCMan EmployeePosisitionCode = "management" // Manajemen + + ITGCInfra ItemGroupCoode = "infra" + ITGCMedicine ItemGroupCoode = "medicine" + ITGCDevice ItemGroupCoode = "device" + ITGCMaterial ItemGroupCoode = "material" + ITGCEmpFee ItemGroupCoode = "employee-fee" + ITGCDocFee ItemGroupCoode = "doctor-fee" + + IFGCBuilding InfraGroupCode = "building" + IFGCFloor InfraGroupCode = "floor" + IFGCRoom InfraGroupCode = "room" + IFGCChamber InfraGroupCode = "chamber" + IFGCBed InfraGroupCode = "bed" + IFGCWarehouse InfraGroupCode = "warehouse" + + UTCReg UnitTypeCode = "reg" // Registrasi + UTCExa UnitTypeCode = "exa" // Pemeriksaan + UTCPay UnitTypeCode = "pay" // Pembayaran + UTCPha UnitTypeCode = "pha" // Farmasi + UTCLab UnitTypeCode = "lab" // Laboratorium + UTCRad UnitTypeCode = "rad" // Radiologi + + DFTCOut DoctorFeeTypeCode = "outpatient" // Rawat Jalan + DFTCInp DoctorFeeTypeCode = "inpatient" // Rawat Inap + DFTCEme DoctorFeeTypeCode = "emergency" // Darurat + DFTCReh DoctorFeeTypeCode = "medic-rehab" // Rehab Medik ) diff --git a/internal/domain/references/patient/patient.go b/internal/domain/references/patient/patient.go deleted file mode 100644 index 4332eca0..00000000 --- a/internal/domain/references/patient/patient.go +++ /dev/null @@ -1,85 +0,0 @@ -package patient - -type ( - ConsciousLevelCode string - StatusCode string - PaymentMethodCode string - EndAssessmentCode string - VisitTypeJknCode uint8 -) - -const ( - CLCAlert ConsciousLevelCode = "alert" - CLCVoice ConsciousLevelCode = "voice" - CLCPain ConsciousLevelCode = "pain" - CLCUnresponsive ConsciousLevelCode = "unresponsive" - CLCAnxious ConsciousLevelCode = "anxious" - CLCAcuteConfusional ConsciousLevelCode = "acute-confuncional" - - PMCCash PaymentMethodCode = "cash" - PMCDebit PaymentMethodCode = "debit" - PMCCredit PaymentMethodCode = "credit" - PMCBpjs PaymentMethodCode = "bpjs" - PMCMembership PaymentMethodCode = "membership" - PMCInsurance PaymentMethodCode = "insurance" - - SCDraft StatusCode = "draft" - SCActive StatusCode = "active" - SCInactive StatusCode = "inactive" - SCBlocked StatusCode = "blocked" - SCDead StatusCode = "dead" - - EACHomeRecom EndAssessmentCode = "home recommendation" - EACHomeReq EndAssessmentCode = "home request" - EACOtherPoly EndAssessmentCode = "others poly" - EACRefInt EndAssessmentCode = "referral internal" - EACRefExt EndAssessmentCode = "referral external" - EACDecease EndAssessmentCode = "decease" - - VTJCReference VisitTypeJknCode = 1 - VTJCInternalReference VisitTypeJknCode = 2 - VTJCControl VisitTypeJknCode = 3 - VTJCExternalReference VisitTypeJknCode = 4 -) - -func GetStatusCodes() map[StatusCode]string { - return map[StatusCode]string{ - SCDraft: "Draft", - SCActive: "Aktif", - SCInactive: "Tidak Aktif", - SCBlocked: "Diblokir", - SCDead: "Meninggal", - } -} - -func GetConsciousLevelCodes() map[ConsciousLevelCode]string { - return map[ConsciousLevelCode]string{ - CLCAlert: "Sadar Baik / Alert", - CLCVoice: "Berespon dengan kata-kata / Voice", - CLCPain: "Hanya beresponse jika dirangsang nyeri / pain", - CLCUnresponsive: "Pasien tidak sadar / unresponsive", - CLCAnxious: "Gelisah atau bingung", - CLCAcuteConfusional: "Acute Confusional States", - } -} - -func GetPaymentMethodCodes() map[PaymentMethodCode]string { - return map[PaymentMethodCode]string{ - PMCCash: "cash", - PMCDebit: "debit", - PMCCredit: "credit", - PMCBpjs: "bpjs", - PMCMembership: "membership", - PMCInsurance: "insurance"} -} - -func GetEndAssessments() map[EndAssessmentCode]string { - return map[EndAssessmentCode]string{ - EACHomeRecom: "home-recommendation", - EACHomeReq: "home-request", - EACOtherPoly: "other-poly", - EACRefInt: "referral-internal", - EACRefExt: "referral-external", - EACDecease: "decease", - } -} diff --git a/internal/domain/references/person/person.go b/internal/domain/references/person/person.go index eef0a7a2..74afbb8d 100644 --- a/internal/domain/references/person/person.go +++ b/internal/domain/references/person/person.go @@ -48,18 +48,18 @@ const ( ) const ( - ECTidakSekolah EducationCode = "TS" - ECTK EducationCode = "TK" - ECSD EducationCode = "SD" - ECSLTP EducationCode = "SMP" - ECSLTA EducationCode = "SMA" - ECD1 EducationCode = "D1" - ECD2 EducationCode = "D2" - ECD3 EducationCode = "D3" - ECD4 EducationCode = "D4" - ECS1 EducationCode = "S1" - ECS2 EducationCode = "S2" - ECS3 EducationCode = "S3" + ECTS EducationCode = "TS" + ECTK EducationCode = "TK" + ECSD EducationCode = "SD" + ECSLTP EducationCode = "SMP" + ECSLTA EducationCode = "SMA" + ECD1 EducationCode = "D1" + ECD2 EducationCode = "D2" + ECD3 EducationCode = "D3" + ECD4 EducationCode = "D4" + ECS1 EducationCode = "S1" + ECS2 EducationCode = "S2" + ECS3 EducationCode = "S3" ) const ( @@ -160,22 +160,22 @@ func GetReligionCodes() map[ReligionCode]string { func GetEducationCodes() map[EducationCode]string { return map[EducationCode]string{ - ECTidakSekolah: "Tidak Sekolah", - ECTK: "TK", - ECSD: "SD", - ECSLTP: "SMP sederajat", - ECSLTA: "SMP sederajat", - ECD1: "D1 sederajat", - ECD2: "D2 sederajat", - ECD3: "D3 sederajat", - ECD4: "D4 sederajat", - ECS1: "S1", - ECS2: "S3", - ECS3: "S3", + ECTS: "Tidak Sekolah", + ECTK: "TK", + ECSD: "SD", + ECSLTP: "SMP sederajat", + ECSLTA: "SMP sederajat", + ECD1: "D1 sederajat", + ECD2: "D2 sederajat", + ECD3: "D3 sederajat", + ECD4: "D4 sederajat", + ECS1: "S1", + ECS2: "S3", + ECS3: "S3", } } -func GetProfessions() map[OcupationCode]string { +func GetOcupationCodes() map[OcupationCode]string { return map[OcupationCode]string{ OCTidakBekerja: "Tidak Bekerja", OCPns: "PNS", @@ -259,7 +259,7 @@ func (obj EducationCode) String() string { } func (obj OcupationCode) String() string { - return GetProfessions()[obj] + return GetOcupationCodes()[obj] } func (obj AgeGroupCode) String() string { diff --git a/internal/domain/references/queue/queue.go b/internal/domain/references/queue/queue.go deleted file mode 100644 index b36aa415..00000000 --- a/internal/domain/references/queue/queue.go +++ /dev/null @@ -1,3 +0,0 @@ -package queue - -const QueueName = "SABBI-QUEUE-" diff --git a/internal/domain/references/xtime/xtime.go b/internal/domain/references/xtime/xtime.go deleted file mode 100644 index ae15bd32..00000000 --- a/internal/domain/references/xtime/xtime.go +++ /dev/null @@ -1,31 +0,0 @@ -package xtime - -type ( - DayCode byte -) - -const ( - DCMinggu DayCode = iota - DCSenin - DCSelasa - DCRabu - DCKamis - DCJumat - DCSabtu -) - -func GetDayCodes() map[DayCode]string { - return map[DayCode]string{ - DCMinggu: "Minggu", - DCSenin: "Senin", - DCSelasa: "Selasa", - DCRabu: "Rabu", - DCKamis: "Kamis", - DCJumat: "Jumat", - DCSabtu: "Sabtu", - } -} - -func (obj DayCode) String() string { - return GetDayCodes()[obj] -} diff --git a/internal/use-case/main-use-case/authentication/case.go b/internal/use-case/main-use-case/authentication/case.go index 069958c7..70925827 100644 --- a/internal/use-case/main-use-case/authentication/case.go +++ b/internal/use-case/main-use-case/authentication/case.go @@ -65,9 +65,9 @@ func GenToken(input mu.LoginDto) (*d.Data, error) { 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 { + } else if user.Status_Code == erc.USCBlocked { return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-blocked", Message: el.GenMessage("auth-login-blocked")}} - } else if user.Status_Code == erc.SCNew { + } else if user.Status_Code == erc.USCNew { return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-unverified", Message: el.GenMessage("auth-login-unverified")}} } diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index fd252bac..c4f55985 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -297,7 +297,7 @@ func Block(input e.ReadDetailDto) (*d.Data, error) { if data != nil { pl.SetLogInfo(&event, rdDto, "started", "DBUpdate") - data.Status_Code = erc.SCBlocked + data.Status_Code = erc.USCBlocked if err := tx.Save(&data).Error; err != nil { return err } @@ -343,7 +343,7 @@ func Active(input e.ReadDetailDto) (*d.Data, error) { if data != nil { pl.SetLogInfo(&event, rdDto, "started", "DBUpdate") - data.Status_Code = erc.SCActive + data.Status_Code = erc.USCActive if err := tx.Save(&data).Error; err != nil { return err } From faf6134caf7a034f8ff0ed253c42c9b70be4daea Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 14:35:20 +0700 Subject: [PATCH 59/75] feat (medicine): adjust medicine --- internal/domain/main-entities/medicine/dto.go | 19 +++++++++---------- .../use-case/main-use-case/medicine/helper.go | 13 +++++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/internal/domain/main-entities/medicine/dto.go b/internal/domain/main-entities/medicine/dto.go index a0ed5d1b..9e505b8b 100644 --- a/internal/domain/main-entities/medicine/dto.go +++ b/internal/domain/main-entities/medicine/dto.go @@ -10,16 +10,15 @@ 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"` - InsuranceCompany_Code *string `json:"insuranceCompany_code"` + 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 { diff --git a/internal/use-case/main-use-case/medicine/helper.go b/internal/use-case/main-use-case/medicine/helper.go index 1414b966..94a8a514 100644 --- a/internal/use-case/main-use-case/medicine/helper.go +++ b/internal/use-case/main-use-case/medicine/helper.go @@ -12,6 +12,8 @@ import ( ui "simrs-vx/internal/use-case/main-use-case/item" uip "simrs-vx/internal/use-case/main-use-case/item-price" + ero "simrs-vx/internal/domain/references/organization" + pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" @@ -39,7 +41,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Medicine) { } func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { - igcMed := "Medicine" + igcMed := string(ero.ITGCMedicine) itemCreate := ei.CreateDto{ Code: pu.AddPrefix("med-", input.Code), Name: input.Name, @@ -57,11 +59,10 @@ func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { return nil } -func createItemPrice(input *e.CreateDto, event *pl.Event, tx *gorm.DB, item_id *uint) error { +func createItemPrice(event *pl.Event, tx *gorm.DB, item_id *uint) error { itemPriceCreate := eip.CreateDto{ - Item_Id: item_id, - Price: 0, - InsuranceCompany_Code: input.InsuranceCompany_Code, + Item_Id: item_id, + Price: 0, } _, err := uip.CreateData(itemPriceCreate, event, tx) return err @@ -72,7 +73,7 @@ func createItemWithDefaultPrice(input *e.CreateDto, event *pl.Event, tx *gorm.DB return err } - if err := createItemPrice(input, event, tx, input.Item_Id); err != nil { + if err := createItemPrice(event, tx, input.Item_Id); err != nil { return err } From 2fa3de8c53c6b440d53d829ab79e530591f0c2f4 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 14:59:19 +0700 Subject: [PATCH 60/75] adjust after references fixed --- ...{20250828092003.sql => 20250829075746.sql} | 121 +++----- cmd/migration/migrations/atlas.sum | 4 +- .../domain/main-entities/infra-group/dto.go | 68 ----- .../main-entities/infra-group/entity.go | 12 - internal/domain/main-entities/infra/dto.go | 49 ++-- internal/domain/main-entities/infra/entity.go | 18 +- .../domain/main-entities/item-group/dto.go | 63 ---- .../domain/main-entities/item-group/entity.go | 11 - internal/domain/main-entities/item/dto.go | 56 ++-- internal/domain/main-entities/item/entity.go | 20 +- .../references/organization/organization.go | 14 +- .../main-handler/infra-group/handler.go | 71 ----- .../main-handler/item-group/handler.go | 71 ----- .../interface/main-handler/main-handler.go | 4 - internal/interface/migration/migration.go | 4 - .../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 --- .../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 --- .../use-case/main-use-case/medicine/helper.go | 13 +- 28 files changed, 134 insertions(+), 1669 deletions(-) rename cmd/migration/migrations/{20250828092003.sql => 20250829075746.sql} (95%) delete mode 100644 internal/domain/main-entities/infra-group/dto.go delete mode 100644 internal/domain/main-entities/infra-group/entity.go delete mode 100644 internal/domain/main-entities/item-group/dto.go delete mode 100644 internal/domain/main-entities/item-group/entity.go delete mode 100644 internal/interface/main-handler/infra-group/handler.go delete mode 100644 internal/interface/main-handler/item-group/handler.go delete mode 100644 internal/use-case/main-use-case/infra-group/case.go delete mode 100644 internal/use-case/main-use-case/infra-group/helper.go delete mode 100644 internal/use-case/main-use-case/infra-group/lib.go delete mode 100644 internal/use-case/main-use-case/infra-group/middleware-runner.go delete mode 100644 internal/use-case/main-use-case/infra-group/middleware.go delete mode 100644 internal/use-case/main-use-case/infra-group/tycovar.go delete mode 100644 internal/use-case/main-use-case/item-group/case.go delete mode 100644 internal/use-case/main-use-case/item-group/helper.go delete mode 100644 internal/use-case/main-use-case/item-group/lib.go delete mode 100644 internal/use-case/main-use-case/item-group/middleware-runner.go delete mode 100644 internal/use-case/main-use-case/item-group/middleware.go delete mode 100644 internal/use-case/main-use-case/item-group/tycovar.go diff --git a/cmd/migration/migrations/20250828092003.sql b/cmd/migration/migrations/20250829075746.sql similarity index 95% rename from cmd/migration/migrations/20250828092003.sql rename to cmd/migration/migrations/20250829075746.sql index 175129a6..11267986 100644 --- a/cmd/migration/migrations/20250828092003.sql +++ b/cmd/migration/migrations/20250829075746.sql @@ -1,3 +1,18 @@ +-- 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 "DiagnoseSrc" table CREATE TABLE "public"."DiagnoseSrc" ( "Id" bigserial NOT NULL, @@ -10,52 +25,16 @@ CREATE TABLE "public"."DiagnoseSrc" ( 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" ( +-- Create "Uom" table +CREATE TABLE "public"."Uom" ( "Id" serial NOT NULL, "CreatedAt" timestamptz NULL, "UpdatedAt" timestamptz NULL, "DeletedAt" timestamptz NULL, - "Code" character varying(20) NULL, + "Code" character varying(10) 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") + CONSTRAINT "uni_Uom_Code" UNIQUE ("Code") ); -- Create "Counter" table CREATE TABLE "public"."Counter" ( @@ -72,31 +51,41 @@ CREATE TABLE "public"."Counter" ( 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" ( +-- Create "McuSrcCategory" table +CREATE TABLE "public"."McuSrcCategory" ( "Id" serial NOT NULL, "CreatedAt" timestamptz NULL, "UpdatedAt" timestamptz NULL, "DeletedAt" timestamptz NULL, - "Code" character varying(10) NULL, + "Code" character varying(20) NULL, "Name" character varying(50) NULL, + "Scope_Code" character varying(10) NULL, PRIMARY KEY ("Id"), - CONSTRAINT "uni_Uom_Code" UNIQUE ("Code") + CONSTRAINT "uni_McuSrcCategory_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 "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 "Item" table CREATE TABLE "public"."Item" ( @@ -112,7 +101,6 @@ CREATE TABLE "public"."Item" ( "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 @@ -251,18 +239,6 @@ CREATE TABLE "public"."DoctorFee" ( 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, @@ -276,7 +252,6 @@ CREATE TABLE "public"."Infra" ( "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 diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index 65ea4bd7..cd54143a 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,2 +1,2 @@ -h1:kBvWq4ulyP8Gz3UPNE/UdpYtWBIpEQskVnanFmaFCRc= -20250828092003.sql h1:ZxYlga6zF0PsTCMisoQo5yUVNwilr0njJQF8mZuVS64= +h1:EYDfTQ6odgD5wgHGPw24RCXeKOoI17X2Bdn5MiCcftM= +20250829075746.sql h1:HZRqrJLqG8GB8W5gpmCR4Itds/Ya51xJdY57nHuXSac= diff --git a/internal/domain/main-entities/infra-group/dto.go b/internal/domain/main-entities/infra-group/dto.go deleted file mode 100644 index e33e92b1..00000000 --- a/internal/domain/main-entities/infra-group/dto.go +++ /dev/null @@ -1,68 +0,0 @@ -package infragroup - -import ( - ecore "simrs-vx/internal/domain/base-entities/core" -) - -type CreateDto struct { - Code string `json:"code"` - Name string `json:"name"` - Level uint8 `json:"level"` -} - -type ReadListDto struct { - Code string `json:"code"` - Name string `json:"name"` - Level uint8 `json:"level"` - - 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"` - Level uint8 `json:"level"` -} - -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"` - Level uint8 `json:"level"` -} - -func (d InfraGroup) ToResponse() ResponseDto { - resp := ResponseDto{ - Code: d.Code, - Name: d.Name, - Level: d.Level, - } - 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 deleted file mode 100644 index 812c27f1..00000000 --- a/internal/domain/main-entities/infra-group/entity.go +++ /dev/null @@ -1,12 +0,0 @@ -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:10"` - Name string `json:"name" gorm:"size:50"` - Level uint8 `json:"level"` -} diff --git a/internal/domain/main-entities/infra/dto.go b/internal/domain/main-entities/infra/dto.go index 801883d1..abc3c014 100644 --- a/internal/domain/main-entities/infra/dto.go +++ b/internal/domain/main-entities/infra/dto.go @@ -2,24 +2,25 @@ 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" + + ero "simrs-vx/internal/domain/references/organization" ) 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"` + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code *ero.InfraGroupCode `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"` + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code *ero.InfraGroupCode `json:"infraGroup_code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -27,12 +28,12 @@ type ReadListDto struct { } 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"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code *ero.InfraGroupCode `json:"infraGroup_code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { @@ -52,13 +53,12 @@ type MetaDto struct { 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"` + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code *ero.InfraGroupCode `json:"infraGroup_code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` } func (d Infra) ToResponse() ResponseDto { @@ -66,7 +66,6 @@ func (d Infra) ToResponse() 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, diff --git a/internal/domain/main-entities/infra/entity.go b/internal/domain/main-entities/infra/entity.go index 7cb2001e..5a3f5730 100644 --- a/internal/domain/main-entities/infra/entity.go +++ b/internal/domain/main-entities/infra/entity.go @@ -2,17 +2,17 @@ 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" + + ero "simrs-vx/internal/domain/references/organization" ) 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"` + 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 *ero.InfraGroupCode `json:"infraGroup_code" gorm:"size:10"` + 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-group/dto.go b/internal/domain/main-entities/item-group/dto.go deleted file mode 100644 index 99681811..00000000 --- a/internal/domain/main-entities/item-group/dto.go +++ /dev/null @@ -1,63 +0,0 @@ -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 deleted file mode 100644 index 24ee3331..00000000 --- a/internal/domain/main-entities/item-group/entity.go +++ /dev/null @@ -1,11 +0,0 @@ -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/item/dto.go b/internal/domain/main-entities/item/dto.go index c157b541..f9cf0b6d 100644 --- a/internal/domain/main-entities/item/dto.go +++ b/internal/domain/main-entities/item/dto.go @@ -2,26 +2,26 @@ 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" + ero "simrs-vx/internal/domain/references/organization" ) 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 *uint16 `json:"infra_id"` - Stock *int `json:"stock"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *ero.ItemGroupCode `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *uint16 `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 *uint16 `json:"infra_id"` - Stock *int `json:"stock"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *ero.ItemGroupCode `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *uint16 `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 *int `json:"stock"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *ero.ItemGroupCode `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *int16 `json:"infra_id"` + Stock *int `json:"stock"` } type UpdateDto struct { @@ -55,14 +55,13 @@ type MetaDto struct { 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 *uint16 `json:"infra_id"` - Stock *int `json:"stock"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code *ero.ItemGroupCode `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Uom *eu.Uom `json:"uom,omitempty"` + Infra_Id *uint16 `json:"infra_id"` + Stock *int `json:"stock"` } func (d Item) ToResponse() ResponseDto { @@ -70,7 +69,6 @@ func (d Item) ToResponse() 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, diff --git a/internal/domain/main-entities/item/entity.go b/internal/domain/main-entities/item/entity.go index c6cb0b8f..129a7f46 100644 --- a/internal/domain/main-entities/item/entity.go +++ b/internal/domain/main-entities/item/entity.go @@ -2,18 +2,18 @@ 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" + + ero "simrs-vx/internal/domain/references/organization" ) 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 *uint16 `json:"infra_id"` - Stock *int `json:"stock"` + 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 *ero.ItemGroupCode `json:"itemGroup_code" gorm:"size:10"` + Uom_Code *string `json:"uom_code" gorm:"size:10"` + Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` + Infra_Id *uint16 `json:"infra_id"` + Stock *int `json:"stock"` } diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index de9cff1c..5c86ba51 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -2,7 +2,7 @@ package organization type ( EmployeePosisitionCode string - ItemGroupCoode string + ItemGroupCode string InfraGroupCode string UnitTypeCode string DoctorFeeTypeCode string @@ -18,12 +18,12 @@ const ( EPCPav EmployeePosisitionCode = "payment-verificator" // Konfirmasi pembayaran EPCMan EmployeePosisitionCode = "management" // Manajemen - ITGCInfra ItemGroupCoode = "infra" - ITGCMedicine ItemGroupCoode = "medicine" - ITGCDevice ItemGroupCoode = "device" - ITGCMaterial ItemGroupCoode = "material" - ITGCEmpFee ItemGroupCoode = "employee-fee" - ITGCDocFee ItemGroupCoode = "doctor-fee" + ITGCInfra ItemGroupCode = "infra" + ITGCMedicine ItemGroupCode = "medicine" + ITGCDevice ItemGroupCode = "device" + ITGCMaterial ItemGroupCode = "material" + ITGCEmpFee ItemGroupCode = "employee-fee" + ITGCDocFee ItemGroupCode = "doctor-fee" IFGCBuilding InfraGroupCode = "building" IFGCFloor InfraGroupCode = "floor" diff --git a/internal/interface/main-handler/infra-group/handler.go b/internal/interface/main-handler/infra-group/handler.go deleted file mode 100644 index 9b3c090a..00000000 --- a/internal/interface/main-handler/infra-group/handler.go +++ /dev/null @@ -1,71 +0,0 @@ -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 deleted file mode 100644 index 71eb8b60..00000000 --- a/internal/interface/main-handler/item-group/handler.go +++ /dev/null @@ -1,71 +0,0 @@ -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 4b5fd1f1..0c47e420 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -44,11 +44,9 @@ import ( 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" 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" material "simrs-vx/internal/interface/main-handler/material" mcusrc "simrs-vx/internal/interface/main-handler/mcu-src" @@ -120,8 +118,6 @@ func SetRoutes() http.Handler { 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/uom", uom.O) hc.RegCrud(r, "/v1/item", item.O) hc.RegCrud(r, "/v1/item-price", itemprice.O) diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 6122597c..353120d3 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -16,11 +16,9 @@ import ( 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" material "simrs-vx/internal/domain/main-entities/material" mcusrc "simrs-vx/internal/domain/main-entities/mcu-src" @@ -96,9 +94,7 @@ func GetEntities() []any { &pharmacycompany.PharmacyCompany{}, &diagnosesrc.DiagnoseSrc{}, &proceduresrc.ProcedureSrc{}, - &infragroup.InfraGroup{}, &employee.Employee{}, - &itemgroup.ItemGroup{}, &doctor.Doctor{}, &nurse.Nurse{}, &nutritionist.Nutritionist{}, diff --git a/internal/use-case/main-use-case/infra-group/case.go b/internal/use-case/main-use-case/infra-group/case.go deleted file mode 100644 index 9366114b..00000000 --- a/internal/use-case/main-use-case/infra-group/case.go +++ /dev/null @@ -1,275 +0,0 @@ -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 deleted file mode 100644 index 653c0c36..00000000 --- a/internal/use-case/main-use-case/infra-group/helper.go +++ /dev/null @@ -1,22 +0,0 @@ -/* -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 - data.Level = inputSrc.Level -} diff --git a/internal/use-case/main-use-case/infra-group/lib.go b/internal/use-case/main-use-case/infra-group/lib.go deleted file mode 100644 index ba738d71..00000000 --- a/internal/use-case/main-use-case/infra-group/lib.go +++ /dev/null @@ -1,149 +0,0 @@ -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 deleted file mode 100644 index 50b8fb7a..00000000 --- a/internal/use-case/main-use-case/infra-group/middleware-runner.go +++ /dev/null @@ -1,103 +0,0 @@ -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 deleted file mode 100644 index b811bbe8..00000000 --- a/internal/use-case/main-use-case/infra-group/middleware.go +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index cd5a9925..00000000 --- a/internal/use-case/main-use-case/infra-group/tycovar.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -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/item-group/case.go b/internal/use-case/main-use-case/item-group/case.go deleted file mode 100644 index 91cd05c7..00000000 --- a/internal/use-case/main-use-case/item-group/case.go +++ /dev/null @@ -1,275 +0,0 @@ -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 deleted file mode 100644 index 98af4a89..00000000 --- a/internal/use-case/main-use-case/item-group/helper.go +++ /dev/null @@ -1,22 +0,0 @@ -/* -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 deleted file mode 100644 index 9e86970a..00000000 --- a/internal/use-case/main-use-case/item-group/lib.go +++ /dev/null @@ -1,149 +0,0 @@ -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 deleted file mode 100644 index 0fa678be..00000000 --- a/internal/use-case/main-use-case/item-group/middleware-runner.go +++ /dev/null @@ -1,103 +0,0 @@ -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 deleted file mode 100644 index ab8a3227..00000000 --- a/internal/use-case/main-use-case/item-group/middleware.go +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index 17ad5bc0..00000000 --- a/internal/use-case/main-use-case/item-group/tycovar.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -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/medicine/helper.go b/internal/use-case/main-use-case/medicine/helper.go index 1414b966..3a389b18 100644 --- a/internal/use-case/main-use-case/medicine/helper.go +++ b/internal/use-case/main-use-case/medicine/helper.go @@ -12,6 +12,8 @@ import ( ui "simrs-vx/internal/use-case/main-use-case/item" uip "simrs-vx/internal/use-case/main-use-case/item-price" + ero "simrs-vx/internal/domain/references/organization" + pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" @@ -39,7 +41,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Medicine) { } func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { - igcMed := "Medicine" + igcMed := ero.ITGCMedicine itemCreate := ei.CreateDto{ Code: pu.AddPrefix("med-", input.Code), Name: input.Name, @@ -57,11 +59,10 @@ func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { return nil } -func createItemPrice(input *e.CreateDto, event *pl.Event, tx *gorm.DB, item_id *uint) error { +func createItemPrice(event *pl.Event, tx *gorm.DB, item_id *uint) error { itemPriceCreate := eip.CreateDto{ - Item_Id: item_id, - Price: 0, - InsuranceCompany_Code: input.InsuranceCompany_Code, + Item_Id: item_id, + Price: 0, } _, err := uip.CreateData(itemPriceCreate, event, tx) return err @@ -72,7 +73,7 @@ func createItemWithDefaultPrice(input *e.CreateDto, event *pl.Event, tx *gorm.DB return err } - if err := createItemPrice(input, event, tx, input.Item_Id); err != nil { + if err := createItemPrice(event, tx, input.Item_Id); err != nil { return err } From c62bc414a986712bedfb9aabde7b6a347b788f6e Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 15:14:40 +0700 Subject: [PATCH 61/75] add infra id into device and material --- ...{20250829075746.sql => 20250829081406.sql} | 86 ++++++++++--------- cmd/migration/migrations/atlas.sum | 4 +- internal/domain/main-entities/device/dto.go | 46 ++++++---- .../domain/main-entities/device/entity.go | 17 ++-- internal/domain/main-entities/material/dto.go | 54 +++++++----- .../domain/main-entities/material/entity.go | 19 ++-- 6 files changed, 126 insertions(+), 100 deletions(-) rename cmd/migration/migrations/{20250829075746.sql => 20250829081406.sql} (98%) diff --git a/cmd/migration/migrations/20250829075746.sql b/cmd/migration/migrations/20250829081406.sql similarity index 98% rename from cmd/migration/migrations/20250829075746.sql rename to cmd/migration/migrations/20250829081406.sql index 11267986..c74cb017 100644 --- a/cmd/migration/migrations/20250829075746.sql +++ b/cmd/migration/migrations/20250829081406.sql @@ -1,18 +1,3 @@ --- 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 "DiagnoseSrc" table CREATE TABLE "public"."DiagnoseSrc" ( "Id" bigserial NOT NULL, @@ -25,17 +10,6 @@ CREATE TABLE "public"."DiagnoseSrc" ( PRIMARY KEY ("Id"), CONSTRAINT "uni_DiagnoseSrc_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 "Counter" table CREATE TABLE "public"."Counter" ( "Id" serial NOT NULL, @@ -75,6 +49,17 @@ CREATE TABLE "public"."McuSrc" ( PRIMARY KEY ("Id"), CONSTRAINT "uni_McuSrc_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 "PharmacyCompany" table CREATE TABLE "public"."PharmacyCompany" ( "Id" bigserial NOT NULL, @@ -87,6 +72,21 @@ CREATE TABLE "public"."PharmacyCompany" ( PRIMARY KEY ("Id"), CONSTRAINT "uni_PharmacyCompany_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 "Item" table CREATE TABLE "public"."Item" ( "Id" bigserial NOT NULL, @@ -103,6 +103,21 @@ CREATE TABLE "public"."Item" ( CONSTRAINT "uni_Item_Code" UNIQUE ("Code"), 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_Item" FOREIGN KEY ("Item_Id") REFERENCES "public"."Item" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); -- Create "Device" table CREATE TABLE "public"."Device" ( "Id" bigserial NOT NULL, @@ -112,9 +127,11 @@ CREATE TABLE "public"."Device" ( "Code" character varying(10) NULL, "Name" character varying(50) NULL, "Uom_Code" character varying(10) NULL, + "Infra_Id" integer NULL, "Item_Id" bigint NULL, PRIMARY KEY ("Id"), CONSTRAINT "uni_Device_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Device_Infra" FOREIGN KEY ("Infra_Id") REFERENCES "public"."Infra" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, 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 ); @@ -239,21 +256,6 @@ CREATE TABLE "public"."DoctorFee" ( 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 "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_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, @@ -291,10 +293,12 @@ CREATE TABLE "public"."Material" ( "Code" character varying(10) NULL, "Name" character varying(50) NULL, "Uom_Code" character varying(10) NULL, + "Infra_Id" integer NULL, "Stock" bigint NULL, "Item_Id" bigint NULL, PRIMARY KEY ("Id"), CONSTRAINT "uni_Material_Code" UNIQUE ("Code"), + CONSTRAINT "fk_Material_Infra" FOREIGN KEY ("Infra_Id") REFERENCES "public"."Infra" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, 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 ); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index cd54143a..c58a11d6 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,2 +1,2 @@ -h1:EYDfTQ6odgD5wgHGPw24RCXeKOoI17X2Bdn5MiCcftM= -20250829075746.sql h1:HZRqrJLqG8GB8W5gpmCR4Itds/Ya51xJdY57nHuXSac= +h1:GkE3HIJ9M82/ti7zJNqapdIZW4D9hFb21ii0uzbb5Es= +20250829081406.sql h1:ZLNXBAoMVVK0zib9NcgF49Ctv/f/pNrf3ciGgae8JVQ= diff --git a/internal/domain/main-entities/device/dto.go b/internal/domain/main-entities/device/dto.go index 0a9aba7a..6d21f63c 100644 --- a/internal/domain/main-entities/device/dto.go +++ b/internal/domain/main-entities/device/dto.go @@ -2,22 +2,25 @@ package device import ( ecore "simrs-vx/internal/domain/base-entities/core" + ein "simrs-vx/internal/domain/main-entities/infra" 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"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Infra_Id *uint16 `json:"infra_id"` + 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"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Infra_Id *uint16 `json:"infra_id"` + Item_Id *uint `json:"item_id"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -25,11 +28,12 @@ type ReadListDto struct { } 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"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Infra_Id *uint16 `json:"infra_id"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { @@ -49,12 +53,14 @@ type MetaDto struct { 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"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Uom *eu.Uom `json:"uom,omitempty"` + Infra_Id *uint16 `json:"infra_id"` + Infra *ein.Infra `json:"infra,omitempty"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` } func (d Device) ToResponse() ResponseDto { @@ -63,6 +69,8 @@ func (d Device) ToResponse() ResponseDto { Name: d.Name, Uom_Code: d.Uom_Code, Uom: d.Uom, + Infra_Id: d.Infra_Id, + Infra: d.Infra, Item_Id: d.Item_Id, Item: d.Item, } diff --git a/internal/domain/main-entities/device/entity.go b/internal/domain/main-entities/device/entity.go index bf75c746..c9f8fdd7 100644 --- a/internal/domain/main-entities/device/entity.go +++ b/internal/domain/main-entities/device/entity.go @@ -2,16 +2,19 @@ package device import ( ecore "simrs-vx/internal/domain/base-entities/core" + ein "simrs-vx/internal/domain/main-entities/infra" 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"` + 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"` + Infra_Id *uint16 `json:"infra_id"` + Infra *ein.Infra `json:"infra,omitempty" gorm:"foreignKey:Infra_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/material/dto.go b/internal/domain/main-entities/material/dto.go index ec565e59..ce4311d4 100644 --- a/internal/domain/main-entities/material/dto.go +++ b/internal/domain/main-entities/material/dto.go @@ -2,24 +2,27 @@ package material import ( ecore "simrs-vx/internal/domain/base-entities/core" + ein "simrs-vx/internal/domain/main-entities/infra" 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"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + 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"` - Uom_Code string `json:"uom_code"` - Stock *int `json:"stock"` - Item_Id *uint `json:"item_id"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + 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"` @@ -27,12 +30,13 @@ type ReadListDto struct { } 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"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Infra_Id *uint16 `json:"infra_id"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { @@ -52,13 +56,15 @@ type MetaDto struct { 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"` + Code string `json:"code"` + Name string `json:"name"` + Uom_Code string `json:"uom_code"` + Uom *eu.Uom `json:"uom,omitempty"` + Infra_Id *uint16 `json:"infra_id"` + Infra *ein.Infra `json:"infra,omitempty"` + Stock *int `json:"stock"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` } func (d Material) ToResponse() ResponseDto { @@ -67,6 +73,8 @@ func (d Material) ToResponse() ResponseDto { Name: d.Name, Uom_Code: d.Uom_Code, Uom: d.Uom, + Infra_Id: d.Infra_Id, + Infra: d.Infra, Stock: d.Stock, Item_Id: d.Item_Id, Item: d.Item, diff --git a/internal/domain/main-entities/material/entity.go b/internal/domain/main-entities/material/entity.go index c14aac78..cdfd8bfd 100644 --- a/internal/domain/main-entities/material/entity.go +++ b/internal/domain/main-entities/material/entity.go @@ -2,17 +2,20 @@ package material import ( ecore "simrs-vx/internal/domain/base-entities/core" + ein "simrs-vx/internal/domain/main-entities/infra" 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"` + 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"` + 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 *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` } From 9546c88d1ad554cd4dc734f815b4c6b75c75eef0 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 15:17:12 +0700 Subject: [PATCH 62/75] wip --- .../use-case/main-use-case/medicine/case.go | 2 +- .../use-case/main-use-case/medicine/helper.go | 23 ------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/internal/use-case/main-use-case/medicine/case.go b/internal/use-case/main-use-case/medicine/case.go index 3775751e..40f49134 100644 --- a/internal/use-case/main-use-case/medicine/case.go +++ b/internal/use-case/main-use-case/medicine/case.go @@ -34,7 +34,7 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } - if err := createItemWithDefaultPrice(&input, &event, tx); err != nil { + if err := createItem(&input, &event, tx); err != nil { return err } if resData, err := CreateData(input, &event, tx); err != nil { diff --git a/internal/use-case/main-use-case/medicine/helper.go b/internal/use-case/main-use-case/medicine/helper.go index 3a389b18..07bc4098 100644 --- a/internal/use-case/main-use-case/medicine/helper.go +++ b/internal/use-case/main-use-case/medicine/helper.go @@ -6,11 +6,9 @@ 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" ero "simrs-vx/internal/domain/references/organization" @@ -58,24 +56,3 @@ func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { input.Item_Id = &item.Id return nil } - -func createItemPrice(event *pl.Event, tx *gorm.DB, item_id *uint) error { - itemPriceCreate := eip.CreateDto{ - Item_Id: item_id, - Price: 0, - } - _, 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(event, tx, input.Item_Id); err != nil { - return err - } - - return nil -} From 5231c177e312ca2601f6e064dc1603e844c6919f Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 15:23:17 +0700 Subject: [PATCH 63/75] feat (item, infra): remove pointer on group --- ...{20250829081406.sql => 20250829081952.sql} | 0 cmd/migration/migrations/atlas.sum | 4 +- internal/domain/main-entities/infra/dto.go | 44 ++++++++-------- internal/domain/main-entities/infra/entity.go | 14 ++--- internal/domain/main-entities/item/dto.go | 52 +++++++++---------- internal/domain/main-entities/item/entity.go | 16 +++--- .../use-case/main-use-case/medicine/helper.go | 3 +- 7 files changed, 66 insertions(+), 67 deletions(-) rename cmd/migration/migrations/{20250829081406.sql => 20250829081952.sql} (100%) diff --git a/cmd/migration/migrations/20250829081406.sql b/cmd/migration/migrations/20250829081952.sql similarity index 100% rename from cmd/migration/migrations/20250829081406.sql rename to cmd/migration/migrations/20250829081952.sql diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index c58a11d6..e818fb5f 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,2 +1,2 @@ -h1:GkE3HIJ9M82/ti7zJNqapdIZW4D9hFb21ii0uzbb5Es= -20250829081406.sql h1:ZLNXBAoMVVK0zib9NcgF49Ctv/f/pNrf3ciGgae8JVQ= +h1:UO+I1wZYLfwSyDcWbSN/dgiNfkPYW567Smq1CT+Xeng= +20250829081952.sql h1:WgG/R3VjMqxFwOaqOACdoDVM9UKQDcaKAq77LxfIDWo= diff --git a/internal/domain/main-entities/infra/dto.go b/internal/domain/main-entities/infra/dto.go index abc3c014..08314637 100644 --- a/internal/domain/main-entities/infra/dto.go +++ b/internal/domain/main-entities/infra/dto.go @@ -8,19 +8,19 @@ import ( ) type CreateDto struct { - Code string `json:"code"` - Name string `json:"name"` - InfraGroup_Code *ero.InfraGroupCode `json:"infraGroup_code"` - Parent_Id *int16 `json:"parent_id"` - Item_Id *uint `json:"item_id"` + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code ero.InfraGroupCode `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 *ero.InfraGroupCode `json:"infraGroup_code"` - Parent_Id *int16 `json:"parent_id"` - Item_Id *uint `json:"item_id"` + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` Page int `json:"page"` PageSize int `json:"page_size"` @@ -28,12 +28,12 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - InfraGroup_Code *ero.InfraGroupCode `json:"infraGroup_code"` - Parent_Id *int16 `json:"parent_id"` - Item_Id *uint `json:"item_id"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { @@ -53,12 +53,12 @@ type MetaDto struct { type ResponseDto struct { ecore.SmallMain - Code string `json:"code"` - Name string `json:"name"` - InfraGroup_Code *ero.InfraGroupCode `json:"infraGroup_code"` - Parent_Id *int16 `json:"parent_id"` - Item_Id *uint `json:"item_id"` - Item *ei.Item `json:"item,omitempty"` + Code string `json:"code"` + Name string `json:"name"` + InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code"` + Parent_Id *int16 `json:"parent_id"` + Item_Id *uint `json:"item_id"` + Item *ei.Item `json:"item,omitempty"` } func (d Infra) ToResponse() ResponseDto { diff --git a/internal/domain/main-entities/infra/entity.go b/internal/domain/main-entities/infra/entity.go index 5a3f5730..01ef24e3 100644 --- a/internal/domain/main-entities/infra/entity.go +++ b/internal/domain/main-entities/infra/entity.go @@ -8,11 +8,11 @@ import ( ) 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 *ero.InfraGroupCode `json:"infraGroup_code" gorm:"size:10"` - Parent_Id *int16 `json:"parent_id"` - Item_Id *uint `json:"item_id"` - Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` + 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 ero.InfraGroupCode `json:"infraGroup_code" gorm:"size:10"` + 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/dto.go b/internal/domain/main-entities/item/dto.go index f9cf0b6d..b90cbd58 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 *ero.ItemGroupCode `json:"itemGroup_code"` - Uom_Code *string `json:"uom_code"` - Infra_Id *uint16 `json:"infra_id"` - Stock *int `json:"stock"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code ero.ItemGroupCode `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *uint16 `json:"infra_id"` + Stock *int `json:"stock"` } type ReadListDto struct { - Code string `json:"code"` - Name string `json:"name"` - ItemGroup_Code *ero.ItemGroupCode `json:"itemGroup_code"` - Uom_Code *string `json:"uom_code"` - Infra_Id *uint16 `json:"infra_id"` - Stock *int `json:"stock"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code ero.ItemGroupCode `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *uint16 `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 *ero.ItemGroupCode `json:"itemGroup_code"` - Uom_Code *string `json:"uom_code"` - Infra_Id *int16 `json:"infra_id"` - Stock *int `json:"stock"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code ero.ItemGroupCode `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Infra_Id *int16 `json:"infra_id"` + Stock *int `json:"stock"` } type UpdateDto struct { @@ -55,13 +55,13 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Code string `json:"code"` - Name string `json:"name"` - ItemGroup_Code *ero.ItemGroupCode `json:"itemGroup_code"` - Uom_Code *string `json:"uom_code"` - Uom *eu.Uom `json:"uom,omitempty"` - Infra_Id *uint16 `json:"infra_id"` - Stock *int `json:"stock"` + Code string `json:"code"` + Name string `json:"name"` + ItemGroup_Code ero.ItemGroupCode `json:"itemGroup_code"` + Uom_Code *string `json:"uom_code"` + Uom *eu.Uom `json:"uom,omitempty"` + Infra_Id *uint16 `json:"infra_id"` + 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 129a7f46..9ac471ad 100644 --- a/internal/domain/main-entities/item/entity.go +++ b/internal/domain/main-entities/item/entity.go @@ -8,12 +8,12 @@ import ( ) 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 *ero.ItemGroupCode `json:"itemGroup_code" gorm:"size:10"` - Uom_Code *string `json:"uom_code" gorm:"size:10"` - Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` - Infra_Id *uint16 `json:"infra_id"` - Stock *int `json:"stock"` + 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 ero.ItemGroupCode `json:"itemGroup_code" gorm:"size:10"` + Uom_Code *string `json:"uom_code" gorm:"size:10"` + Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` + Infra_Id *uint16 `json:"infra_id"` + Stock *int `json:"stock"` } diff --git a/internal/use-case/main-use-case/medicine/helper.go b/internal/use-case/main-use-case/medicine/helper.go index 3a389b18..899758b7 100644 --- a/internal/use-case/main-use-case/medicine/helper.go +++ b/internal/use-case/main-use-case/medicine/helper.go @@ -41,11 +41,10 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Medicine) { } func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { - igcMed := ero.ITGCMedicine itemCreate := ei.CreateDto{ Code: pu.AddPrefix("med-", input.Code), Name: input.Name, - ItemGroup_Code: &igcMed, + ItemGroup_Code: ero.ITGCMedicine, Uom_Code: input.Uom_Code, Infra_Id: input.Infra_Id, Stock: input.Stock, From 2d8fcba59f006b907da9288e7379be72339b8570 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 15:36:37 +0700 Subject: [PATCH 64/75] feat (device, material): add create item --- .../use-case/main-use-case/device/case.go | 3 +++ .../use-case/main-use-case/device/helper.go | 27 +++++++++++++++++++ .../use-case/main-use-case/material/case.go | 3 +++ .../use-case/main-use-case/material/helper.go | 27 +++++++++++++++++++ 4 files changed, 60 insertions(+) diff --git a/internal/use-case/main-use-case/device/case.go b/internal/use-case/main-use-case/device/case.go index cb40c1eb..ad218571 100644 --- a/internal/use-case/main-use-case/device/case.go +++ b/internal/use-case/main-use-case/device/case.go @@ -34,6 +34,9 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + if err := createItem(&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/device/helper.go b/internal/use-case/main-use-case/device/helper.go index 137425b1..63d51664 100644 --- a/internal/use-case/main-use-case/device/helper.go +++ b/internal/use-case/main-use-case/device/helper.go @@ -6,6 +6,16 @@ package device import ( e "simrs-vx/internal/domain/main-entities/device" + ei "simrs-vx/internal/domain/main-entities/item" + + ui "simrs-vx/internal/use-case/main-use-case/item" + + ero "simrs-vx/internal/domain/references/organization" + + 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.Device) { @@ -22,3 +32,20 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Device) { data.Uom_Code = inputSrc.Uom_Code data.Item_Id = inputSrc.Item_Id } + +func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + itemCreate := ei.CreateDto{ + Code: pu.AddPrefix("dev-", input.Code), + Name: input.Name, + ItemGroup_Code: ero.ITGCDevice, + Uom_Code: &input.Uom_Code, + Infra_Id: input.Infra_Id, + } + item, err := ui.CreateData(itemCreate, event, tx) + if err != nil { + return err + } + + input.Item_Id = &item.Id + return nil +} diff --git a/internal/use-case/main-use-case/material/case.go b/internal/use-case/main-use-case/material/case.go index f855f044..ecf52cd1 100644 --- a/internal/use-case/main-use-case/material/case.go +++ b/internal/use-case/main-use-case/material/case.go @@ -34,6 +34,9 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + if err := createItem(&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/material/helper.go b/internal/use-case/main-use-case/material/helper.go index 11b4900c..ce0d8a2e 100644 --- a/internal/use-case/main-use-case/material/helper.go +++ b/internal/use-case/main-use-case/material/helper.go @@ -5,7 +5,16 @@ Any functions that are used internally by the use-case package material import ( + ei "simrs-vx/internal/domain/main-entities/item" e "simrs-vx/internal/domain/main-entities/material" + + ui "simrs-vx/internal/use-case/main-use-case/item" + + ero "simrs-vx/internal/domain/references/organization" + 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.Material) { @@ -23,3 +32,21 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Material) { data.Stock = inputSrc.Stock data.Item_Id = inputSrc.Item_Id } + +func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + itemCreate := ei.CreateDto{ + Code: pu.AddPrefix("mat-", input.Code), + Name: input.Name, + ItemGroup_Code: ero.ITGCMaterial, + 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 +} From 62608b5909b206d747bab00e198e14ec355c1f8c Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 15:36:46 +0700 Subject: [PATCH 65/75] infra wip --- .../use-case/main-use-case/infra/helper.go | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/internal/use-case/main-use-case/infra/helper.go b/internal/use-case/main-use-case/infra/helper.go index 93730033..8d320a7c 100644 --- a/internal/use-case/main-use-case/infra/helper.go +++ b/internal/use-case/main-use-case/infra/helper.go @@ -6,6 +6,12 @@ package infra import ( e "simrs-vx/internal/domain/main-entities/infra" + // ei "simrs-vx/internal/domain/main-entities/item" + // ui "simrs-vx/internal/use-case/main-use-case/item" + // ero "simrs-vx/internal/domain/references/organization" + // 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.Infra) { @@ -23,3 +29,19 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Infra) { data.Parent_Id = inputSrc.Parent_Id data.Item_Id = inputSrc.Item_Id } + +// func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { +// itemCreate := ei.CreateDto{ +// Code: pu.AddPrefix("inf-", input.Code), +// Name: input.Name, +// ItemGroup_Code: ero.ITGCInfra, +// Infra_Id: input, +// } +// item, err := ui.CreateData(itemCreate, event, tx) +// if err != nil { +// return err +// } + +// input.Item_Id = &item.Id +// return nil +// } From 2cacfc5f3337ecd9d1ebc227be3e834e27887164 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 15:38:12 +0700 Subject: [PATCH 66/75] feat (infra): change parent_id datatype --- internal/domain/main-entities/infra/dto.go | 8 ++++---- internal/domain/main-entities/infra/entity.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/domain/main-entities/infra/dto.go b/internal/domain/main-entities/infra/dto.go index 08314637..17f36ddf 100644 --- a/internal/domain/main-entities/infra/dto.go +++ b/internal/domain/main-entities/infra/dto.go @@ -11,7 +11,7 @@ type CreateDto struct { Code string `json:"code"` Name string `json:"name"` InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code"` - Parent_Id *int16 `json:"parent_id"` + Parent_Id *uint16 `json:"parent_id"` Item_Id *uint `json:"item_id"` } @@ -19,7 +19,7 @@ type ReadListDto struct { Code string `json:"code"` Name string `json:"name"` InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code"` - Parent_Id *int16 `json:"parent_id"` + Parent_Id *uint16 `json:"parent_id"` Item_Id *uint `json:"item_id"` Page int `json:"page"` @@ -32,7 +32,7 @@ type ReadDetailDto struct { Code string `json:"code"` Name string `json:"name"` InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code"` - Parent_Id *int16 `json:"parent_id"` + Parent_Id *uint16 `json:"parent_id"` Item_Id *uint `json:"item_id"` } @@ -56,7 +56,7 @@ type ResponseDto struct { Code string `json:"code"` Name string `json:"name"` InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code"` - Parent_Id *int16 `json:"parent_id"` + Parent_Id *uint16 `json:"parent_id"` Item_Id *uint `json:"item_id"` Item *ei.Item `json:"item,omitempty"` } diff --git a/internal/domain/main-entities/infra/entity.go b/internal/domain/main-entities/infra/entity.go index 01ef24e3..a7d2e6d4 100644 --- a/internal/domain/main-entities/infra/entity.go +++ b/internal/domain/main-entities/infra/entity.go @@ -12,7 +12,7 @@ type Infra struct { Code string `json:"code" gorm:"unique;size:10"` Name string `json:"name" gorm:"size:50"` InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code" gorm:"size:10"` - Parent_Id *int16 `json:"parent_id"` + Parent_Id *uint16 `json:"parent_id"` Item_Id *uint `json:"item_id"` Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Id;references:Id"` } From fae93e5158a49de163d7292638bda33dc3011e35 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Fri, 29 Aug 2025 15:44:52 +0700 Subject: [PATCH 67/75] feat (infra): add item on room infra group --- internal/use-case/main-use-case/infra/case.go | 18 ++++++++ .../use-case/main-use-case/infra/helper.go | 41 ++++++++++--------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/internal/use-case/main-use-case/infra/case.go b/internal/use-case/main-use-case/infra/case.go index afa0ec6a..074b0d17 100644 --- a/internal/use-case/main-use-case/infra/case.go +++ b/internal/use-case/main-use-case/infra/case.go @@ -1,12 +1,15 @@ package infra import ( + "errors" e "simrs-vx/internal/domain/main-entities/infra" "strconv" dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" + ero "simrs-vx/internal/domain/references/organization" + pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" @@ -34,6 +37,21 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + if input.InfraGroup_Code == ero.IFGCRoom { + if input.Parent_Id == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "parent_id is required", + Raw: errors.New("parent_id is required"), + } + return pl.SetLogError(&event, input) + + } + if err := createItem(&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/infra/helper.go b/internal/use-case/main-use-case/infra/helper.go index 8d320a7c..00057eee 100644 --- a/internal/use-case/main-use-case/infra/helper.go +++ b/internal/use-case/main-use-case/infra/helper.go @@ -6,12 +6,13 @@ package infra import ( e "simrs-vx/internal/domain/main-entities/infra" - // ei "simrs-vx/internal/domain/main-entities/item" - // ui "simrs-vx/internal/use-case/main-use-case/item" - // ero "simrs-vx/internal/domain/references/organization" - // pl "simrs-vx/pkg/logger" - // pu "simrs-vx/pkg/use-case-helper" - // "gorm.io/gorm" + ei "simrs-vx/internal/domain/main-entities/item" + ero "simrs-vx/internal/domain/references/organization" + ui "simrs-vx/internal/use-case/main-use-case/item" + 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.Infra) { @@ -30,18 +31,18 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Infra) { data.Item_Id = inputSrc.Item_Id } -// func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { -// itemCreate := ei.CreateDto{ -// Code: pu.AddPrefix("inf-", input.Code), -// Name: input.Name, -// ItemGroup_Code: ero.ITGCInfra, -// Infra_Id: input, -// } -// item, err := ui.CreateData(itemCreate, event, tx) -// if err != nil { -// return err -// } +func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + itemCreate := ei.CreateDto{ + Code: pu.AddPrefix("inf-", input.Code), + Name: input.Name, + ItemGroup_Code: ero.ITGCInfra, + Infra_Id: input.Parent_Id, + } + item, err := ui.CreateData(itemCreate, event, tx) + if err != nil { + return err + } -// input.Item_Id = &item.Id -// return nil -// } + input.Item_Id = &item.Id + return nil +} From 8aa34607b9c2ce3e9c3e85d10ad85e3bff1dd1d9 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 1 Sep 2025 14:28:34 +0700 Subject: [PATCH 68/75] remove unnecessary field in readdetail --- internal/domain/main-entities/device/dto.go | 8 +--- .../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 +-- .../domain/main-entities/doctor-fee/dto.go | 8 ++-- internal/domain/main-entities/doctor/dto.go | 1 - .../main-entities/employee copy/entity.go | 19 -------- internal/domain/main-entities/employee/dto.go | 27 +++++++++--- internal/domain/main-entities/ethnic/dto.go | 5 +-- internal/domain/main-entities/infra/dto.go | 9 ++-- .../domain/main-entities/installation/dto.go | 6 +-- .../main-entities/insurance-company/dto.go | 9 ++-- .../domain/main-entities/item-price/dto.go | 6 +-- internal/domain/main-entities/item/dto.go | 9 +--- internal/domain/main-entities/material/dto.go | 10 ++--- .../main-entities/mcu-src-category/dto.go | 6 +-- internal/domain/main-entities/mcu-src/dto.go | 6 +-- .../medical-action-src-item/dto.go | 5 +-- .../main-entities/medical-action-src/dto.go | 6 +-- .../main-entities/medicine-group/dto.go | 5 +-- .../main-entities/medicine-method/dto.go | 5 +-- .../main-entities/medicine-mix-item/dto.go | 5 +-- .../domain/main-entities/medicine-mix/dto.go | 3 +- internal/domain/main-entities/medicine/dto.go | 13 ++---- .../main-entities/person-address/dto.go | 8 +--- .../main-entities/person-contact/dto.go | 6 +-- internal/domain/main-entities/person/dto.go | 14 ++---- .../main-entities/pharmacy-company/dto.go | 6 +-- .../main-entities/practice-schedule/dto.go | 7 +-- .../domain/main-entities/procedure-src/dto.go | 6 +-- internal/domain/main-entities/province/dto.go | 5 +-- internal/domain/main-entities/regency/dto.go | 6 +-- internal/domain/main-entities/unit/dto.go | 5 +-- internal/domain/main-entities/uom/dto.go | 5 +-- internal/domain/main-entities/user/dto.go | 4 +- internal/domain/main-entities/village/dto.go | 6 +-- .../use-case/main-use-case/employee/case.go | 14 +++++- .../use-case/main-use-case/employee/helper.go | 44 +++++++++++++++++++ .../use-case/main-use-case/employee/lib.go | 8 +++- pkg/use-case-helper/use-case-helper.go | 21 +++++++++ 41 files changed, 175 insertions(+), 185 deletions(-) delete mode 100644 internal/domain/main-entities/employee copy/entity.go diff --git a/internal/domain/main-entities/device/dto.go b/internal/domain/main-entities/device/dto.go index 6d21f63c..cd299608 100644 --- a/internal/domain/main-entities/device/dto.go +++ b/internal/domain/main-entities/device/dto.go @@ -28,12 +28,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Uom_Code string `json:"uom_code"` - Infra_Id *uint16 `json:"infra_id"` - Item_Id *uint `json:"item_id"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/diagnose-src/dto.go b/internal/domain/main-entities/diagnose-src/dto.go index 9e8736a1..3cfe0152 100644 --- a/internal/domain/main-entities/diagnose-src/dto.go +++ b/internal/domain/main-entities/diagnose-src/dto.go @@ -21,10 +21,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - IndName string `json:"indName"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/district/dto.go b/internal/domain/main-entities/district/dto.go index 850d4649..57f41892 100644 --- a/internal/domain/main-entities/district/dto.go +++ b/internal/domain/main-entities/district/dto.go @@ -19,10 +19,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint32 `json:"id"` - Regency_Code string `json:"regency_code"` - Code string `json:"code"` - Name string `json:"name"` + Id uint32 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/division-position/dto.go b/internal/domain/main-entities/division-position/dto.go index 8dd18d0b..4011a47d 100644 --- a/internal/domain/main-entities/division-position/dto.go +++ b/internal/domain/main-entities/division-position/dto.go @@ -22,10 +22,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Division_Id *uint16 `json:"division_id"` - Code string `json:"code"` - Name string `json:"name"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/division/dto.go b/internal/domain/main-entities/division/dto.go index d9d7b606..890bd606 100644 --- a/internal/domain/main-entities/division/dto.go +++ b/internal/domain/main-entities/division/dto.go @@ -21,10 +21,8 @@ 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"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/doctor-fee/dto.go b/internal/domain/main-entities/doctor-fee/dto.go index 6052f984..b25d2ebd 100644 --- a/internal/domain/main-entities/doctor-fee/dto.go +++ b/internal/domain/main-entities/doctor-fee/dto.go @@ -26,11 +26,9 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Doctor_Id *uint `json:"doctor_id"` - FeeType_Code *ero.DoctorFeeTypeCode `json:"feeType_code"` - Price *float64 `json:"price"` - Item_Id *uint `json:"item_id"` + Id uint16 `json:"id"` + Doctor_Id *uint `json:"doctor_id"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/doctor/dto.go b/internal/domain/main-entities/doctor/dto.go index f251fe59..351cfdfd 100644 --- a/internal/domain/main-entities/doctor/dto.go +++ b/internal/domain/main-entities/doctor/dto.go @@ -29,7 +29,6 @@ type ReadDetailDto 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 UpdateDto struct { diff --git a/internal/domain/main-entities/employee copy/entity.go b/internal/domain/main-entities/employee copy/entity.go deleted file mode 100644 index 55b829fa..00000000 --- a/internal/domain/main-entities/employee copy/entity.go +++ /dev/null @@ -1,19 +0,0 @@ -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 eb7432ec..e12cf4d6 100644 --- a/internal/domain/main-entities/employee/dto.go +++ b/internal/domain/main-entities/employee/dto.go @@ -3,13 +3,17 @@ package employee import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/division" + ep "simrs-vx/internal/domain/main-entities/person" + eu "simrs-vx/internal/domain/main-entities/user" erc "simrs-vx/internal/domain/references/common" ero "simrs-vx/internal/domain/references/organization" ) type CreateDto struct { User_Id *uint `json:"user_id"` + UserRequest *eu.CreateDto `json:"user_request"` Person_Id *uint `json:"person_id"` + PersonRequest *ep.CreateDto `json:"person_request"` Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Number *string `json:"number"` @@ -17,6 +21,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { User_Id *uint `json:"user_id"` Person_Id *uint `json:"person_id"` Position_Code ero.EmployeePosisitionCode `json:"position_code"` @@ -30,13 +40,10 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - User_Id *uint `json:"user_id"` - Person_Id *uint `json:"person_id"` - Position_Code ero.EmployeePosisitionCode `json:"position_code"` - Division_Code *string `json:"division_code"` - Number *string `json:"number"` - Status_Code erc.ActiveStatusCode `json:"status_code"` + Id uint16 `json:"id"` + User_Id *uint `json:"user_id"` + Person_Id *uint `json:"person_id"` + Number *string `json:"number"` } type UpdateDto struct { @@ -86,3 +93,9 @@ func ToResponseList(data []Employee) []ResponseDto { } return resp } + +func (c CreateDto) Sanitize() CreateDto { + sanitized := c + sanitized.UserRequest.Password = "[REDACTED]" + return sanitized +} diff --git a/internal/domain/main-entities/ethnic/dto.go b/internal/domain/main-entities/ethnic/dto.go index 64e5ca85..f434e4ae 100644 --- a/internal/domain/main-entities/ethnic/dto.go +++ b/internal/domain/main-entities/ethnic/dto.go @@ -19,9 +19,8 @@ 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"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/infra/dto.go b/internal/domain/main-entities/infra/dto.go index 17f36ddf..9cfb076d 100644 --- a/internal/domain/main-entities/infra/dto.go +++ b/internal/domain/main-entities/infra/dto.go @@ -28,12 +28,9 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code"` - Parent_Id *uint16 `json:"parent_id"` - Item_Id *uint `json:"item_id"` + Id uint16 `json:"id"` + Code *string `json:"code"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/installation/dto.go b/internal/domain/main-entities/installation/dto.go index d3691c03..76b4084b 100644 --- a/internal/domain/main-entities/installation/dto.go +++ b/internal/domain/main-entities/installation/dto.go @@ -22,10 +22,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/insurance-company/dto.go b/internal/domain/main-entities/insurance-company/dto.go index 2cc36195..c541120f 100644 --- a/internal/domain/main-entities/insurance-company/dto.go +++ b/internal/domain/main-entities/insurance-company/dto.go @@ -26,12 +26,9 @@ type ReadListDto struct { } 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"` + Id uint16 `json:"id"` + Code *string `json:"code"` + PhoneNumber *string `json:"phoneNumber"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/item-price/dto.go b/internal/domain/main-entities/item-price/dto.go index 730284e0..ca8ab948 100644 --- a/internal/domain/main-entities/item-price/dto.go +++ b/internal/domain/main-entities/item-price/dto.go @@ -23,10 +23,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Item_Id *uint `json:"item_id"` - Price float64 `json:"price"` - InsuranceCompany_Code *string `json:"insuranceCompany_code"` + Id uint16 `json:"id"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/item/dto.go b/internal/domain/main-entities/item/dto.go index b90cbd58..a6ab4991 100644 --- a/internal/domain/main-entities/item/dto.go +++ b/internal/domain/main-entities/item/dto.go @@ -29,13 +29,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - ItemGroup_Code ero.ItemGroupCode `json:"itemGroup_code"` - Uom_Code *string `json:"uom_code"` - Infra_Id *int16 `json:"infra_id"` - Stock *int `json:"stock"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/material/dto.go b/internal/domain/main-entities/material/dto.go index ce4311d4..5ec82138 100644 --- a/internal/domain/main-entities/material/dto.go +++ b/internal/domain/main-entities/material/dto.go @@ -30,13 +30,9 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Uom_Code string `json:"uom_code"` - Infra_Id *uint16 `json:"infra_id"` - Stock *int `json:"stock"` - Item_Id *uint `json:"item_id"` + Id uint16 `json:"id"` + Code *string `json:"code"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/mcu-src-category/dto.go b/internal/domain/main-entities/mcu-src-category/dto.go index 6c48beb3..7058722f 100644 --- a/internal/domain/main-entities/mcu-src-category/dto.go +++ b/internal/domain/main-entities/mcu-src-category/dto.go @@ -22,10 +22,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Scope_Code *ere.CheckupScopeCode `json:"scope_code"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/mcu-src/dto.go b/internal/domain/main-entities/mcu-src/dto.go index f0c06a51..7f950979 100644 --- a/internal/domain/main-entities/mcu-src/dto.go +++ b/internal/domain/main-entities/mcu-src/dto.go @@ -21,10 +21,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - CheckupCategory_Code *string `json:"checkupCategory_code"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/medical-action-src-item/dto.go b/internal/domain/main-entities/medical-action-src-item/dto.go index 79ba260c..050af71b 100644 --- a/internal/domain/main-entities/medical-action-src-item/dto.go +++ b/internal/domain/main-entities/medical-action-src-item/dto.go @@ -24,10 +24,7 @@ type ReadListDto struct { } 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"` + Id uint16 `json:"id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/medical-action-src/dto.go b/internal/domain/main-entities/medical-action-src/dto.go index 85fdf003..32ad3e0d 100644 --- a/internal/domain/main-entities/medical-action-src/dto.go +++ b/internal/domain/main-entities/medical-action-src/dto.go @@ -22,10 +22,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Item_Id *uint `json:"item_id"` + Id uint16 `json:"id"` + Code string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/medicine-group/dto.go b/internal/domain/main-entities/medicine-group/dto.go index 3ae439a3..c4dfde6c 100644 --- a/internal/domain/main-entities/medicine-group/dto.go +++ b/internal/domain/main-entities/medicine-group/dto.go @@ -19,9 +19,8 @@ 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"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/medicine-method/dto.go b/internal/domain/main-entities/medicine-method/dto.go index 074f8caa..763a7c65 100644 --- a/internal/domain/main-entities/medicine-method/dto.go +++ b/internal/domain/main-entities/medicine-method/dto.go @@ -19,9 +19,8 @@ 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"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/medicine-mix-item/dto.go b/internal/domain/main-entities/medicine-mix-item/dto.go index fcc1865e..230347b7 100644 --- a/internal/domain/main-entities/medicine-mix-item/dto.go +++ b/internal/domain/main-entities/medicine-mix-item/dto.go @@ -23,10 +23,7 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - MedicineMix_Id *uint `json:"medicineMix_id"` - Medicine_Id *uint `json:"medicine_id"` - Dose *uint8 `json:"dose"` + Id uint16 `json:"id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/medicine-mix/dto.go b/internal/domain/main-entities/medicine-mix/dto.go index 1d21a635..39314051 100644 --- a/internal/domain/main-entities/medicine-mix/dto.go +++ b/internal/domain/main-entities/medicine-mix/dto.go @@ -17,8 +17,7 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Name string `json:"name"` + Id uint16 `json:"id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/medicine/dto.go b/internal/domain/main-entities/medicine/dto.go index 9e505b8b..bd17f253 100644 --- a/internal/domain/main-entities/medicine/dto.go +++ b/internal/domain/main-entities/medicine/dto.go @@ -38,16 +38,9 @@ type ReadListDto struct { } 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"` + Id uint16 `json:"id"` + Code *string `json:"code"` + Item_Id *uint `json:"item_id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/person-address/dto.go b/internal/domain/main-entities/person-address/dto.go index 73ae88ce..f88799f1 100644 --- a/internal/domain/main-entities/person-address/dto.go +++ b/internal/domain/main-entities/person-address/dto.go @@ -19,12 +19,8 @@ type ReadListDto struct { } 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"` + Id uint `json:"id"` + Person_Id uint `json:"person_id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/person-contact/dto.go b/internal/domain/main-entities/person-contact/dto.go index e6865191..036db7e7 100644 --- a/internal/domain/main-entities/person-contact/dto.go +++ b/internal/domain/main-entities/person-contact/dto.go @@ -18,10 +18,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint `json:"id"` - Person_Id uint `json:"person_id"` - Type_Code erp.ContactTypeCode `json:"type_code"` - Value string `json:"value"` + Id uint `json:"id"` + Person_Id uint `json:"person_id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/person/dto.go b/internal/domain/main-entities/person/dto.go index 296e23b6..2f8c54fd 100644 --- a/internal/domain/main-entities/person/dto.go +++ b/internal/domain/main-entities/person/dto.go @@ -29,17 +29,9 @@ type ReadListDto struct { } 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 *string `json:"ethnic_code"` + Id uint `json:"id"` + Name *string `json:"name"` + ResidentIdentityNumber *string `json:"residentIdentityNumber"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/pharmacy-company/dto.go b/internal/domain/main-entities/pharmacy-company/dto.go index d8f4dd27..eb7ce5e1 100644 --- a/internal/domain/main-entities/pharmacy-company/dto.go +++ b/internal/domain/main-entities/pharmacy-company/dto.go @@ -21,10 +21,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Regency_Code string `json:"regency_code"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/practice-schedule/dto.go b/internal/domain/main-entities/practice-schedule/dto.go index ea09c0d9..64ba3aef 100644 --- a/internal/domain/main-entities/practice-schedule/dto.go +++ b/internal/domain/main-entities/practice-schedule/dto.go @@ -26,12 +26,7 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Doctor_Id *uint `json:"doctor_id"` - Unit_Code *string `json:"unit_code"` - Day_Code *erc.DayCode `json:"day_code"` - StartTime *string `json:"startTime"` - EndTime *string `json:"endTime"` + Id uint16 `json:"id"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/procedure-src/dto.go b/internal/domain/main-entities/procedure-src/dto.go index c0ba8c30..a69a5244 100644 --- a/internal/domain/main-entities/procedure-src/dto.go +++ b/internal/domain/main-entities/procedure-src/dto.go @@ -21,10 +21,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - IndName string `json:"indName"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/province/dto.go b/internal/domain/main-entities/province/dto.go index bc1461e0..5bd519a8 100644 --- a/internal/domain/main-entities/province/dto.go +++ b/internal/domain/main-entities/province/dto.go @@ -15,9 +15,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id int16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` + Id int16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/regency/dto.go b/internal/domain/main-entities/regency/dto.go index 6cb850de..7fb7546b 100644 --- a/internal/domain/main-entities/regency/dto.go +++ b/internal/domain/main-entities/regency/dto.go @@ -19,10 +19,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` - Province_Code string `json:"province_code"` - Code string `json:"code"` - Name string `json:"name"` + Id uint16 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/unit/dto.go b/internal/domain/main-entities/unit/dto.go index 448d16ec..11782b74 100644 --- a/internal/domain/main-entities/unit/dto.go +++ b/internal/domain/main-entities/unit/dto.go @@ -22,10 +22,9 @@ type ReadListDto struct { } type ReadDetailDto struct { - Installation_Id *uint16 `json:"installation_id"` Id uint16 `json:"id"` - Code string `json:"code"` - Name string `json:"name"` + Installation_Id *uint16 `json:"installation_id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/uom/dto.go b/internal/domain/main-entities/uom/dto.go index 08055c12..597510a1 100644 --- a/internal/domain/main-entities/uom/dto.go +++ b/internal/domain/main-entities/uom/dto.go @@ -19,9 +19,8 @@ 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"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index 7ac5715c..102429b7 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -22,8 +22,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint `json:"id"` - Name string `json:"name"` + Id uint `json:"id"` + Name *string `json:"name"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/village/dto.go b/internal/domain/main-entities/village/dto.go index bdd1a323..968784ee 100644 --- a/internal/domain/main-entities/village/dto.go +++ b/internal/domain/main-entities/village/dto.go @@ -17,10 +17,8 @@ type ReadListDto struct { } type ReadDetailDto struct { - Id uint32 `json:"id"` - District_Code string `json:"district_code"` - Code string `json:"code"` - Name string `json:"name"` + Id uint32 `json:"id"` + Code *string `json:"code"` } type UpdateDto struct { diff --git a/internal/use-case/main-use-case/employee/case.go b/internal/use-case/main-use-case/employee/case.go index 68476e13..5d77ded2 100644 --- a/internal/use-case/main-use-case/employee/case.go +++ b/internal/use-case/main-use-case/employee/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) @@ -34,6 +34,15 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + if input.Person_Id == nil { + if err := createPerson(&input, &event, tx); err != nil { + return err + } + } + if err := createUser(&input, &event, tx); err != nil { + return err + } + if resData, err := CreateData(input, &event, tx); err != nil { return err } else { @@ -87,6 +96,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/employee/helper.go b/internal/use-case/main-use-case/employee/helper.go index 1660048f..8eca2b26 100644 --- a/internal/use-case/main-use-case/employee/helper.go +++ b/internal/use-case/main-use-case/employee/helper.go @@ -5,7 +5,14 @@ Any functions that are used internally by the use-case package employee import ( + "errors" e "simrs-vx/internal/domain/main-entities/employee" + pl "simrs-vx/pkg/logger" + + up "simrs-vx/internal/use-case/main-use-case/person" + uu "simrs-vx/internal/use-case/main-use-case/user" + + "gorm.io/gorm" ) func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Employee) { @@ -24,3 +31,40 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Employee) { data.Number = inputSrc.Number data.Status_Code = inputSrc.Status_Code } + +func createUser(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + if input.UserRequest == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "user request is required", + Raw: errors.New("user request is required"), + } + return pl.SetLogError(event, input) + } + user, err := uu.CreateData(*input.UserRequest, event, tx) + if err != nil { + return err + } + input.User_Id = &user.Id + return nil +} + +func createPerson(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + if input.PersonRequest == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "person request is required", + Raw: errors.New("person request is required"), + } + return pl.SetLogError(event, input) + } + person, err := up.CreateData(*input.PersonRequest, event, tx) + if err != nil { + return err + } + input.Person_Id = &person.Id + return nil + +} diff --git a/internal/use-case/main-use-case/employee/lib.go b/internal/use-case/main-use-case/employee/lib.go index 261acb56..18dc9d9a 100644 --- a/internal/use-case/main-use-case/employee/lib.go +++ b/internal/use-case/main-use-case/employee/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Em tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Employee{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/pkg/use-case-helper/use-case-helper.go b/pkg/use-case-helper/use-case-helper.go index fadfa373..beb369c1 100644 --- a/pkg/use-case-helper/use-case-helper.go +++ b/pkg/use-case-helper/use-case-helper.go @@ -80,3 +80,24 @@ func HandleMiddlewareError(event *pl.Event, mwType, mwName string, logData inter func AddPrefix(prefix string, str string) string { return prefix + str } + +func GetPreloads(input string) []string { + result := []string{} + parts := strings.Split(input, ",") + for _, p := range parts { + result = append(result, kebabToPascal(p)) + } + return result +} + +func kebabToPascal(input string) string { + parts := strings.Split(input, "-") + for i, p := range parts { + if len(p) > 0 { + r := []rune(p) + r[0] = []rune(strings.ToUpper(string(r[0])))[0] + parts[i] = string(r) + } + } + return strings.Join(parts, "") +} From ee160f877f1a6138294dc641cbfabbddf75d39be Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 1 Sep 2025 14:34:19 +0700 Subject: [PATCH 69/75] add user and person fk for employee --- cmd/migration/migrations/20250901073356.sql | 6 ++++++ cmd/migration/migrations/atlas.sum | 5 +++-- internal/domain/main-entities/employee/entity.go | 4 ++++ internal/domain/main-entities/user/entity.go | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 cmd/migration/migrations/20250901073356.sql diff --git a/cmd/migration/migrations/20250901073356.sql b/cmd/migration/migrations/20250901073356.sql new file mode 100644 index 00000000..4ffe005f --- /dev/null +++ b/cmd/migration/migrations/20250901073356.sql @@ -0,0 +1,6 @@ +-- Modify "Infra" table +ALTER TABLE "public"."Infra" ALTER COLUMN "Parent_Id" TYPE integer; +-- Modify "User" table +ALTER TABLE "public"."User" ADD CONSTRAINT "uni_User_Name" UNIQUE ("Name"); +-- Modify "Employee" table +ALTER TABLE "public"."Employee" ADD CONSTRAINT "fk_Employee_Person" FOREIGN KEY ("Person_Id") REFERENCES "public"."Person" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_Employee_User" FOREIGN KEY ("User_Id") REFERENCES "public"."User" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index e818fb5f..6da3d7a3 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,2 +1,3 @@ -h1:UO+I1wZYLfwSyDcWbSN/dgiNfkPYW567Smq1CT+Xeng= -20250829081952.sql h1:WgG/R3VjMqxFwOaqOACdoDVM9UKQDcaKAq77LxfIDWo= +h1:LmZ7NtbArHgEvza5276tSjY3D8/0w98RKEJYM3gxMZk= +20250829081952.sql h1:YMsYq3uPsx70EjWSGfYnVRR5GV0q1fRGIszYZAWzXNo= +20250901073356.sql h1:Me41GuoGLGDagM6claco/7G6I1aFBxZAQjdR3qhTxuQ= diff --git a/internal/domain/main-entities/employee/entity.go b/internal/domain/main-entities/employee/entity.go index 15ca4ce9..24687262 100644 --- a/internal/domain/main-entities/employee/entity.go +++ b/internal/domain/main-entities/employee/entity.go @@ -3,6 +3,8 @@ package employee import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/division" + ep "simrs-vx/internal/domain/main-entities/person" + eu "simrs-vx/internal/domain/main-entities/user" erc "simrs-vx/internal/domain/references/common" ero "simrs-vx/internal/domain/references/organization" ) @@ -10,7 +12,9 @@ import ( type Employee struct { ecore.Main // adjust this according to the needs User_Id *uint `json:"user_id"` + User *eu.User `json:"user,omitempty" gorm:"foreignKey:User_Id;references:Id"` Person_Id *uint `json:"person_id"` + Person *ep.Person `json:"person,omitempty" gorm:"foreignKey:Person_Id;references: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"` diff --git a/internal/domain/main-entities/user/entity.go b/internal/domain/main-entities/user/entity.go index 0db3beea..3ad46b9d 100644 --- a/internal/domain/main-entities/user/entity.go +++ b/internal/domain/main-entities/user/entity.go @@ -8,7 +8,7 @@ import ( type User struct { ecore.Main // adjust this according to the needs - Name string `json:"name" gorm:"not null;size:25"` + Name string `json:"name" gorm:"unique;not null;size:25"` Password string `json:"password" gorm:"not null;size:255"` Status_Code erc.UserStatusCode `json:"status_code" gorm:"not null;size:10"` FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"` From f25d7c1b090e812d3da30268a44cc7ba127bedf8 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 1 Sep 2025 14:58:55 +0700 Subject: [PATCH 70/75] filtering wip --- internal/domain/main-entities/device/dto.go | 6 ++++++ internal/domain/main-entities/division-position/dto.go | 6 ++++++ internal/domain/main-entities/doctor-fee/dto.go | 6 ++++++ internal/domain/main-entities/doctor/dto.go | 6 ++++++ internal/domain/main-entities/employee/dto.go | 3 +++ internal/domain/main-entities/infra/dto.go | 6 ++++++ internal/domain/main-entities/insurance-company/dto.go | 6 ++++++ internal/domain/main-entities/item-price/dto.go | 7 ++++++- internal/domain/main-entities/item/dto.go | 6 ++++++ internal/domain/main-entities/material/dto.go | 6 ++++++ internal/use-case/main-use-case/device/case.go | 3 +++ internal/use-case/main-use-case/device/lib.go | 8 +++++++- internal/use-case/main-use-case/division-position/case.go | 3 +++ internal/use-case/main-use-case/division-position/lib.go | 8 +++++++- internal/use-case/main-use-case/doctor-fee/case.go | 3 +++ internal/use-case/main-use-case/doctor-fee/lib.go | 8 +++++++- internal/use-case/main-use-case/doctor/case.go | 3 +++ internal/use-case/main-use-case/doctor/lib.go | 8 +++++++- internal/use-case/main-use-case/infra/case.go | 3 +++ internal/use-case/main-use-case/infra/lib.go | 8 +++++++- internal/use-case/main-use-case/insurance-company/case.go | 3 +++ internal/use-case/main-use-case/insurance-company/lib.go | 8 +++++++- internal/use-case/main-use-case/item-price/case.go | 3 +++ internal/use-case/main-use-case/item-price/lib.go | 8 +++++++- internal/use-case/main-use-case/item/case.go | 3 +++ internal/use-case/main-use-case/item/lib.go | 8 +++++++- internal/use-case/main-use-case/material/case.go | 3 +++ internal/use-case/main-use-case/material/lib.go | 8 +++++++- 28 files changed, 147 insertions(+), 10 deletions(-) diff --git a/internal/domain/main-entities/device/dto.go b/internal/domain/main-entities/device/dto.go index cd299608..921aae1b 100644 --- a/internal/domain/main-entities/device/dto.go +++ b/internal/domain/main-entities/device/dto.go @@ -16,6 +16,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Code string `json:"code"` Name string `json:"name"` Uom_Code string `json:"uom_code"` diff --git a/internal/domain/main-entities/division-position/dto.go b/internal/domain/main-entities/division-position/dto.go index 4011a47d..4bf75308 100644 --- a/internal/domain/main-entities/division-position/dto.go +++ b/internal/domain/main-entities/division-position/dto.go @@ -12,6 +12,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Division_Id *uint16 `json:"division_id"` Code string `json:"code"` Name string `json:"name"` diff --git a/internal/domain/main-entities/doctor-fee/dto.go b/internal/domain/main-entities/doctor-fee/dto.go index b25d2ebd..ae6c8d77 100644 --- a/internal/domain/main-entities/doctor-fee/dto.go +++ b/internal/domain/main-entities/doctor-fee/dto.go @@ -15,6 +15,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Doctor_Id *uint `json:"doctor_id"` FeeType_Code *ero.DoctorFeeTypeCode `json:"feeType_code"` Price *float64 `json:"price"` diff --git a/internal/domain/main-entities/doctor/dto.go b/internal/domain/main-entities/doctor/dto.go index 351cfdfd..7f506a40 100644 --- a/internal/domain/main-entities/doctor/dto.go +++ b/internal/domain/main-entities/doctor/dto.go @@ -14,6 +14,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Employee_Id *uint `json:"employee_id"` IHS_Number *string `json:"ihs_number"` SIP_Number *string `json:"sip_number"` diff --git a/internal/domain/main-entities/employee/dto.go b/internal/domain/main-entities/employee/dto.go index e12cf4d6..61b560db 100644 --- a/internal/domain/main-entities/employee/dto.go +++ b/internal/domain/main-entities/employee/dto.go @@ -64,7 +64,9 @@ type MetaDto struct { type ResponseDto struct { ecore.Main User_Id *uint `json:"user_id"` + User *eu.User `json:"user,omitempty"` Person_Id *uint `json:"person_id"` + Person *ep.Person `json:"person,omitempty"` Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Division *ed.Division `json:"division,omitempty"` @@ -75,6 +77,7 @@ type ResponseDto struct { func (d Employee) ToResponse() ResponseDto { resp := ResponseDto{ User_Id: d.User_Id, + User: d.User, Person_Id: d.Person_Id, Position_Code: d.Position_Code, Division_Code: d.Division_Code, diff --git a/internal/domain/main-entities/infra/dto.go b/internal/domain/main-entities/infra/dto.go index 9cfb076d..49a47073 100644 --- a/internal/domain/main-entities/infra/dto.go +++ b/internal/domain/main-entities/infra/dto.go @@ -16,6 +16,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Code string `json:"code"` Name string `json:"name"` InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code"` diff --git a/internal/domain/main-entities/insurance-company/dto.go b/internal/domain/main-entities/insurance-company/dto.go index c541120f..44728319 100644 --- a/internal/domain/main-entities/insurance-company/dto.go +++ b/internal/domain/main-entities/insurance-company/dto.go @@ -14,6 +14,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Code string `json:"code"` Name string `json:"name"` Regency_Code *string `json:"regency_code"` diff --git a/internal/domain/main-entities/item-price/dto.go b/internal/domain/main-entities/item-price/dto.go index ca8ab948..e9aa2e9b 100644 --- a/internal/domain/main-entities/item-price/dto.go +++ b/internal/domain/main-entities/item-price/dto.go @@ -13,6 +13,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Item_Id *uint `json:"item_id"` Price float64 `json:"price"` InsuranceCompany_Code *string `json:"insuranceCompany_code"` @@ -21,7 +27,6 @@ type ReadListDto struct { PageSize int `json:"page_size"` NoPagination int `json:"no_pagination"` } - type ReadDetailDto struct { Id uint16 `json:"id"` Item_Id *uint `json:"item_id"` diff --git a/internal/domain/main-entities/item/dto.go b/internal/domain/main-entities/item/dto.go index a6ab4991..301b759e 100644 --- a/internal/domain/main-entities/item/dto.go +++ b/internal/domain/main-entities/item/dto.go @@ -16,6 +16,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Code string `json:"code"` Name string `json:"name"` ItemGroup_Code ero.ItemGroupCode `json:"itemGroup_code"` diff --git a/internal/domain/main-entities/material/dto.go b/internal/domain/main-entities/material/dto.go index 5ec82138..27b0422b 100644 --- a/internal/domain/main-entities/material/dto.go +++ b/internal/domain/main-entities/material/dto.go @@ -17,6 +17,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Code string `json:"code"` Name string `json:"name"` Uom_Code string `json:"uom_code"` diff --git a/internal/use-case/main-use-case/device/case.go b/internal/use-case/main-use-case/device/case.go index ad218571..5c5c9b73 100644 --- a/internal/use-case/main-use-case/device/case.go +++ b/internal/use-case/main-use-case/device/case.go @@ -90,6 +90,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/device/lib.go b/internal/use-case/main-use-case/device/lib.go index ae369a58..22c233b6 100644 --- a/internal/use-case/main-use-case/device/lib.go +++ b/internal/use-case/main-use-case/device/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.De tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Device{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") 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 bc088fcc..2fbb0c3b 100644 --- a/internal/use-case/main-use-case/division-position/case.go +++ b/internal/use-case/main-use-case/division-position/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } 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 a09ec618..c59506c0 100644 --- a/internal/use-case/main-use-case/division-position/lib.go +++ b/internal/use-case/main-use-case/division-position/lib.go @@ -51,10 +51,16 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Di tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.DivisionPosition{}). Preload("Division"). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/doctor-fee/case.go b/internal/use-case/main-use-case/doctor-fee/case.go index 449349a1..cce2ae5f 100644 --- a/internal/use-case/main-use-case/doctor-fee/case.go +++ b/internal/use-case/main-use-case/doctor-fee/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/doctor-fee/lib.go b/internal/use-case/main-use-case/doctor-fee/lib.go index f34ab9d7..ef4629f5 100644 --- a/internal/use-case/main-use-case/doctor-fee/lib.go +++ b/internal/use-case/main-use-case/doctor-fee/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Do tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.DoctorFee{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/doctor/case.go b/internal/use-case/main-use-case/doctor/case.go index 72a60279..19088c61 100644 --- a/internal/use-case/main-use-case/doctor/case.go +++ b/internal/use-case/main-use-case/doctor/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/doctor/lib.go b/internal/use-case/main-use-case/doctor/lib.go index b75d9bb1..db5bd8b7 100644 --- a/internal/use-case/main-use-case/doctor/lib.go +++ b/internal/use-case/main-use-case/doctor/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Do tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Doctor{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/infra/case.go b/internal/use-case/main-use-case/infra/case.go index 074b0d17..e95e09d3 100644 --- a/internal/use-case/main-use-case/infra/case.go +++ b/internal/use-case/main-use-case/infra/case.go @@ -105,6 +105,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/infra/lib.go b/internal/use-case/main-use-case/infra/lib.go index 23c745db..d4ec76d0 100644 --- a/internal/use-case/main-use-case/infra/lib.go +++ b/internal/use-case/main-use-case/infra/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.In tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Infra{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/insurance-company/case.go b/internal/use-case/main-use-case/insurance-company/case.go index fafec031..a981339d 100644 --- a/internal/use-case/main-use-case/insurance-company/case.go +++ b/internal/use-case/main-use-case/insurance-company/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/insurance-company/lib.go b/internal/use-case/main-use-case/insurance-company/lib.go index 06438edb..15073715 100644 --- a/internal/use-case/main-use-case/insurance-company/lib.go +++ b/internal/use-case/main-use-case/insurance-company/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.In tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.InsuranceCompany{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/item-price/case.go b/internal/use-case/main-use-case/item-price/case.go index 6566f6e8..a40f9142 100644 --- a/internal/use-case/main-use-case/item-price/case.go +++ b/internal/use-case/main-use-case/item-price/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/item-price/lib.go b/internal/use-case/main-use-case/item-price/lib.go index 924752f0..8d61f2f8 100644 --- a/internal/use-case/main-use-case/item-price/lib.go +++ b/internal/use-case/main-use-case/item-price/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.It tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.ItemPrice{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/item/case.go b/internal/use-case/main-use-case/item/case.go index 77ca4d89..67027fa8 100644 --- a/internal/use-case/main-use-case/item/case.go +++ b/internal/use-case/main-use-case/item/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/item/lib.go b/internal/use-case/main-use-case/item/lib.go index a65f2da9..b62e1c3a 100644 --- a/internal/use-case/main-use-case/item/lib.go +++ b/internal/use-case/main-use-case/item/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.It tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Item{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/material/case.go b/internal/use-case/main-use-case/material/case.go index ecf52cd1..87b8be9c 100644 --- a/internal/use-case/main-use-case/material/case.go +++ b/internal/use-case/main-use-case/material/case.go @@ -90,6 +90,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/material/lib.go b/internal/use-case/main-use-case/material/lib.go index ab114241..f1a3f40b 100644 --- a/internal/use-case/main-use-case/material/lib.go +++ b/internal/use-case/main-use-case/material/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ma tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Material{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") From 9a0b37390df772d3be6ea99f0d3b3b5611490ad3 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 1 Sep 2025 15:01:02 +0700 Subject: [PATCH 71/75] add fk mcusrccategory for mcusrc --- cmd/migration/migrations/20250901080035.sql | 2 ++ cmd/migration/migrations/atlas.sum | 5 +++-- internal/domain/main-entities/mcu-src/entity.go | 10 ++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 cmd/migration/migrations/20250901080035.sql diff --git a/cmd/migration/migrations/20250901080035.sql b/cmd/migration/migrations/20250901080035.sql new file mode 100644 index 00000000..8b41cd0d --- /dev/null +++ b/cmd/migration/migrations/20250901080035.sql @@ -0,0 +1,2 @@ +-- Modify "McuSrc" table +ALTER TABLE "public"."McuSrc" ADD CONSTRAINT "fk_McuSrc_CheckupCategory" FOREIGN KEY ("CheckupCategory_Code") REFERENCES "public"."McuSrcCategory" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index 6da3d7a3..ede3d757 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,3 +1,4 @@ -h1:LmZ7NtbArHgEvza5276tSjY3D8/0w98RKEJYM3gxMZk= +h1:MnN9ZF4JC2g1P1r3le7M54HgeoPRDPSY/s+NwP7B9e4= 20250829081952.sql h1:YMsYq3uPsx70EjWSGfYnVRR5GV0q1fRGIszYZAWzXNo= -20250901073356.sql h1:Me41GuoGLGDagM6claco/7G6I1aFBxZAQjdR3qhTxuQ= +20250901073356.sql h1:jjd5TLs+Pyi0u3SrOM+aNTbHxSJboXgcOz/L4bkYx+c= +20250901080035.sql h1:YHNFHu7P0NtRL0kKWHxzrg0n7Hf0aZjthFn8KoJDEpw= diff --git a/internal/domain/main-entities/mcu-src/entity.go b/internal/domain/main-entities/mcu-src/entity.go index bec60ac0..cdd8356f 100644 --- a/internal/domain/main-entities/mcu-src/entity.go +++ b/internal/domain/main-entities/mcu-src/entity.go @@ -2,11 +2,13 @@ package mcusrc import ( ecore "simrs-vx/internal/domain/base-entities/core" + emsc "simrs-vx/internal/domain/main-entities/mcu-src-category" ) 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"` + 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"` + CheckupCategory *emsc.McuSrcCategory `json:"checkupCategory,omitempty" gorm:"foreignKey:CheckupCategory_Code;references:Code"` } From 8af9504a7e1dad219b65245cd3dcc3ee477f0c11 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 1 Sep 2025 15:15:08 +0700 Subject: [PATCH 72/75] fix filtering --- internal/domain/main-entities/mcu-src/dto.go | 6 ++++++ .../medical-action-src-item/dto.go | 6 ++++++ .../main-entities/medical-action-src/dto.go | 6 ++++++ .../main-entities/medicine-mix-item/dto.go | 6 ++++++ internal/domain/main-entities/medicine/dto.go | 6 ++++++ internal/domain/main-entities/nurse/dto.go | 7 ++++++- .../domain/main-entities/nutritionist/dto.go | 6 ++++++ internal/domain/main-entities/person/dto.go | 17 +++++++++++++++++ internal/domain/main-entities/pharmacist/dto.go | 6 ++++++ .../main-entities/practice-schedule/dto.go | 6 ++++++ internal/domain/main-entities/unit/dto.go | 6 ++++++ internal/use-case/main-use-case/mcu-src/case.go | 3 +++ internal/use-case/main-use-case/mcu-src/lib.go | 8 +++++++- .../medical-action-src-item/case.go | 3 +++ .../medical-action-src-item/lib.go | 8 +++++++- .../main-use-case/medical-action-src/case.go | 3 +++ .../main-use-case/medical-action-src/lib.go | 8 +++++++- .../main-use-case/medicine-mix-item/case.go | 3 +++ .../main-use-case/medicine-mix-item/lib.go | 8 +++++++- .../use-case/main-use-case/medicine/case.go | 3 +++ internal/use-case/main-use-case/medicine/lib.go | 8 +++++++- internal/use-case/main-use-case/nurse/case.go | 3 +++ internal/use-case/main-use-case/nurse/lib.go | 8 +++++++- .../use-case/main-use-case/nutritionist/case.go | 3 +++ .../use-case/main-use-case/nutritionist/lib.go | 8 +++++++- internal/use-case/main-use-case/person/case.go | 3 +++ internal/use-case/main-use-case/person/lib.go | 8 +++++++- .../use-case/main-use-case/pharmacist/case.go | 3 +++ .../use-case/main-use-case/pharmacist/lib.go | 8 +++++++- .../main-use-case/practice-schedule/case.go | 3 +++ .../main-use-case/practice-schedule/lib.go | 8 +++++++- internal/use-case/main-use-case/unit/case.go | 3 +++ internal/use-case/main-use-case/unit/lib.go | 8 +++++++- 33 files changed, 187 insertions(+), 12 deletions(-) diff --git a/internal/domain/main-entities/mcu-src/dto.go b/internal/domain/main-entities/mcu-src/dto.go index 7f950979..66205ab2 100644 --- a/internal/domain/main-entities/mcu-src/dto.go +++ b/internal/domain/main-entities/mcu-src/dto.go @@ -11,6 +11,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Code string `json:"code"` Name string `json:"name"` CheckupCategory_Code *string `json:"checkupCategory_code"` diff --git a/internal/domain/main-entities/medical-action-src-item/dto.go b/internal/domain/main-entities/medical-action-src-item/dto.go index 050af71b..75836c14 100644 --- a/internal/domain/main-entities/medical-action-src-item/dto.go +++ b/internal/domain/main-entities/medical-action-src-item/dto.go @@ -14,6 +14,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { MedicalActionSrc_Id *uint `json:"medicalActionSrc_id"` ProcedureSrc_Id *uint `json:"procedureSrc_id"` Item_Id *uint `json:"item_id"` diff --git a/internal/domain/main-entities/medical-action-src/dto.go b/internal/domain/main-entities/medical-action-src/dto.go index 32ad3e0d..664848df 100644 --- a/internal/domain/main-entities/medical-action-src/dto.go +++ b/internal/domain/main-entities/medical-action-src/dto.go @@ -12,6 +12,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Code string `json:"code"` Name string `json:"name"` Item_Id *uint `json:"item_id"` diff --git a/internal/domain/main-entities/medicine-mix-item/dto.go b/internal/domain/main-entities/medicine-mix-item/dto.go index 230347b7..dbcbce21 100644 --- a/internal/domain/main-entities/medicine-mix-item/dto.go +++ b/internal/domain/main-entities/medicine-mix-item/dto.go @@ -13,6 +13,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { MedicineMix_Id *uint `json:"medicineMix_id"` Medicine_Id *uint `json:"medicine_id"` Dose *uint8 `json:"dose"` diff --git a/internal/domain/main-entities/medicine/dto.go b/internal/domain/main-entities/medicine/dto.go index bd17f253..bd01f213 100644 --- a/internal/domain/main-entities/medicine/dto.go +++ b/internal/domain/main-entities/medicine/dto.go @@ -22,6 +22,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Code string `json:"code"` Name string `json:"name"` MedicineGroup_Code *string `json:"medicineGroup_code"` diff --git a/internal/domain/main-entities/nurse/dto.go b/internal/domain/main-entities/nurse/dto.go index 3feaa041..f108c1cb 100644 --- a/internal/domain/main-entities/nurse/dto.go +++ b/internal/domain/main-entities/nurse/dto.go @@ -11,6 +11,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Employee_Id *uint `json:"employee_id"` IHS_Number *string `json:"ihs_number"` @@ -18,7 +24,6 @@ type ReadListDto struct { PageSize int `json:"page_size"` NoPagination int `json:"no_pagination"` } - type ReadDetailDto struct { Id uint16 `json:"id"` Employee_Id *uint `json:"employee_id"` diff --git a/internal/domain/main-entities/nutritionist/dto.go b/internal/domain/main-entities/nutritionist/dto.go index c5bc7003..f69e252e 100644 --- a/internal/domain/main-entities/nutritionist/dto.go +++ b/internal/domain/main-entities/nutritionist/dto.go @@ -11,6 +11,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Employee_Id *uint `json:"employee_id"` IHS_Number *string `json:"ihs_number"` diff --git a/internal/domain/main-entities/person/dto.go b/internal/domain/main-entities/person/dto.go index 2f8c54fd..24ac3d6c 100644 --- a/internal/domain/main-entities/person/dto.go +++ b/internal/domain/main-entities/person/dto.go @@ -23,6 +23,23 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto 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 *string `json:"ethnic_code"` + Page int `json:"page"` PageSize int `json:"page_size"` NoPagination int `json:"no_pagination"` diff --git a/internal/domain/main-entities/pharmacist/dto.go b/internal/domain/main-entities/pharmacist/dto.go index 07bcd1f7..7d32082d 100644 --- a/internal/domain/main-entities/pharmacist/dto.go +++ b/internal/domain/main-entities/pharmacist/dto.go @@ -11,6 +11,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Employee_Id *uint `json:"employee_id"` IHS_Number *string `json:"ihs_number"` diff --git a/internal/domain/main-entities/practice-schedule/dto.go b/internal/domain/main-entities/practice-schedule/dto.go index 64ba3aef..3896868f 100644 --- a/internal/domain/main-entities/practice-schedule/dto.go +++ b/internal/domain/main-entities/practice-schedule/dto.go @@ -14,6 +14,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Doctor_Id *uint `json:"doctor_id"` Unit_Code *string `json:"unit_code"` Day_Code *erc.DayCode `json:"day_code"` diff --git a/internal/domain/main-entities/unit/dto.go b/internal/domain/main-entities/unit/dto.go index 11782b74..8d4c0b44 100644 --- a/internal/domain/main-entities/unit/dto.go +++ b/internal/domain/main-entities/unit/dto.go @@ -12,6 +12,12 @@ type CreateDto struct { } type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Preloads []string `json:"-"` +} + +type FilterDto struct { Installation_Id *uint16 `json:"installation_id"` Code string `json:"code"` Name string `json:"name"` diff --git a/internal/use-case/main-use-case/mcu-src/case.go b/internal/use-case/main-use-case/mcu-src/case.go index 3dc69a7c..ae7a1860 100644 --- a/internal/use-case/main-use-case/mcu-src/case.go +++ b/internal/use-case/main-use-case/mcu-src/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/mcu-src/lib.go b/internal/use-case/main-use-case/mcu-src/lib.go index 023d334e..e7e76041 100644 --- a/internal/use-case/main-use-case/mcu-src/lib.go +++ b/internal/use-case/main-use-case/mcu-src/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Mc tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.McuSrc{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") 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 index e811714d..2efdca2c 100644 --- 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 @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } 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 index f294c118..02d81f6c 100644 --- 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 @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.MedicalActionSrcItem{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") 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 index 0b22aa7e..1c0fe565 100644 --- a/internal/use-case/main-use-case/medical-action-src/case.go +++ b/internal/use-case/main-use-case/medical-action-src/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } 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 index b0cdbdc0..5bef2fca 100644 --- a/internal/use-case/main-use-case/medical-action-src/lib.go +++ b/internal/use-case/main-use-case/medical-action-src/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.MedicalActionSrc{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") 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 index 1b6dfc6e..42145947 100644 --- a/internal/use-case/main-use-case/medicine-mix-item/case.go +++ b/internal/use-case/main-use-case/medicine-mix-item/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } 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 index 739c6a7a..3bea8e9c 100644 --- a/internal/use-case/main-use-case/medicine-mix-item/lib.go +++ b/internal/use-case/main-use-case/medicine-mix-item/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.MedicineMixItem{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/medicine/case.go b/internal/use-case/main-use-case/medicine/case.go index 40f49134..aa970478 100644 --- a/internal/use-case/main-use-case/medicine/case.go +++ b/internal/use-case/main-use-case/medicine/case.go @@ -90,6 +90,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/medicine/lib.go b/internal/use-case/main-use-case/medicine/lib.go index a66e7cd0..c7295e10 100644 --- a/internal/use-case/main-use-case/medicine/lib.go +++ b/internal/use-case/main-use-case/medicine/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Medicine{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/nurse/case.go b/internal/use-case/main-use-case/nurse/case.go index 9bb32296..509be4dd 100644 --- a/internal/use-case/main-use-case/nurse/case.go +++ b/internal/use-case/main-use-case/nurse/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/nurse/lib.go b/internal/use-case/main-use-case/nurse/lib.go index 263888e7..c0ffdbb8 100644 --- a/internal/use-case/main-use-case/nurse/lib.go +++ b/internal/use-case/main-use-case/nurse/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Nu tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Nurse{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/nutritionist/case.go b/internal/use-case/main-use-case/nutritionist/case.go index b7cad178..f584f005 100644 --- a/internal/use-case/main-use-case/nutritionist/case.go +++ b/internal/use-case/main-use-case/nutritionist/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/nutritionist/lib.go b/internal/use-case/main-use-case/nutritionist/lib.go index 263c4231..abe77aa4 100644 --- a/internal/use-case/main-use-case/nutritionist/lib.go +++ b/internal/use-case/main-use-case/nutritionist/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Nu tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Nutritionist{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/person/case.go b/internal/use-case/main-use-case/person/case.go index a372c34a..e0395bd9 100644 --- a/internal/use-case/main-use-case/person/case.go +++ b/internal/use-case/main-use-case/person/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/person/lib.go b/internal/use-case/main-use-case/person/lib.go index 430e8b69..e704bfbb 100644 --- a/internal/use-case/main-use-case/person/lib.go +++ b/internal/use-case/main-use-case/person/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pe tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Person{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/pharmacist/case.go b/internal/use-case/main-use-case/pharmacist/case.go index a2e7aecc..cdc8503f 100644 --- a/internal/use-case/main-use-case/pharmacist/case.go +++ b/internal/use-case/main-use-case/pharmacist/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/pharmacist/lib.go b/internal/use-case/main-use-case/pharmacist/lib.go index 18d41f26..cc22a87f 100644 --- a/internal/use-case/main-use-case/pharmacist/lib.go +++ b/internal/use-case/main-use-case/pharmacist/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ph tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Pharmacist{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/practice-schedule/case.go b/internal/use-case/main-use-case/practice-schedule/case.go index 82ef0c8b..223d97ec 100644 --- a/internal/use-case/main-use-case/practice-schedule/case.go +++ b/internal/use-case/main-use-case/practice-schedule/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/practice-schedule/lib.go b/internal/use-case/main-use-case/practice-schedule/lib.go index a926e984..1d5e34ac 100644 --- a/internal/use-case/main-use-case/practice-schedule/lib.go +++ b/internal/use-case/main-use-case/practice-schedule/lib.go @@ -51,9 +51,15 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pr tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.PracticeSchedule{}). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") diff --git a/internal/use-case/main-use-case/unit/case.go b/internal/use-case/main-use-case/unit/case.go index 0ab8cdcb..beb91f7b 100644 --- a/internal/use-case/main-use-case/unit/case.go +++ b/internal/use-case/main-use-case/unit/case.go @@ -87,6 +87,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { return err } + if len(input.Includes) > 0 { + input.Preloads = pu.GetPreloads(input.Includes) + } if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } diff --git a/internal/use-case/main-use-case/unit/lib.go b/internal/use-case/main-use-case/unit/lib.go index d7aebcaf..f43530dc 100644 --- a/internal/use-case/main-use-case/unit/lib.go +++ b/internal/use-case/main-use-case/unit/lib.go @@ -51,10 +51,16 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Un tx = dg.I } + if len(input.Preloads) > 0 { + for _, preload := range input.Preloads { + tx = tx.Preload(preload) + } + } + tx = tx. Model(&e.Unit{}). Preload("Installation"). - Scopes(gh.Filter(input)). + Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") From 8594bc51d4722d9e640cd30a30377f061084b153 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 1 Sep 2025 17:57:25 +0700 Subject: [PATCH 73/75] add front and endtitle on person --- cmd/migration/migrations/20250901105703.sql | 2 ++ cmd/migration/migrations/atlas.sum | 5 +++-- internal/domain/main-entities/person/entity.go | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 cmd/migration/migrations/20250901105703.sql diff --git a/cmd/migration/migrations/20250901105703.sql b/cmd/migration/migrations/20250901105703.sql new file mode 100644 index 00000000..e9c47a1a --- /dev/null +++ b/cmd/migration/migrations/20250901105703.sql @@ -0,0 +1,2 @@ +-- Modify "Person" table +ALTER TABLE "public"."Person" ADD COLUMN "FrontTitle" character varying(50) NULL, ADD COLUMN "EndTitle" character varying(50) NULL; diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index ede3d757..b4d8d0f9 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,4 +1,5 @@ -h1:MnN9ZF4JC2g1P1r3le7M54HgeoPRDPSY/s+NwP7B9e4= +h1:vQwjJ2jG5TRFv8oZyhxcynOFS+H0vyKY/XWsXJyhpuo= 20250829081952.sql h1:YMsYq3uPsx70EjWSGfYnVRR5GV0q1fRGIszYZAWzXNo= 20250901073356.sql h1:jjd5TLs+Pyi0u3SrOM+aNTbHxSJboXgcOz/L4bkYx+c= -20250901080035.sql h1:YHNFHu7P0NtRL0kKWHxzrg0n7Hf0aZjthFn8KoJDEpw= +20250901080035.sql h1:LWa3X0NWjalVcxNbk5HaHj1Oqu60/AQabi0jBmCeQBI= +20250901105703.sql h1:45mFfTFkLv+1oQXfqNxtCBGXTyzWuqq759I3u1SVxRo= diff --git a/internal/domain/main-entities/person/entity.go b/internal/domain/main-entities/person/entity.go index 0acdbc91..09f04c7e 100644 --- a/internal/domain/main-entities/person/entity.go +++ b/internal/domain/main-entities/person/entity.go @@ -13,6 +13,8 @@ import ( type Person struct { ecore.Main // adjust this according to the needs Name string `json:"name" gorm:"not null;size:150"` + FrontTitle *string `json:"frontTitle" gorm:"size:50"` + EndTitle *string `json:"endTitle" gorm:"size:50"` 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"` From b289831e6c65c91780d1761d8c3b0d932901d9f6 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 1 Sep 2025 17:58:40 +0700 Subject: [PATCH 74/75] feat (person): add front and endtitle --- internal/domain/main-entities/person/dto.go | 8 ++++++++ internal/use-case/main-use-case/person/helper.go | 2 ++ 2 files changed, 10 insertions(+) diff --git a/internal/domain/main-entities/person/dto.go b/internal/domain/main-entities/person/dto.go index 24ac3d6c..02de4b7e 100644 --- a/internal/domain/main-entities/person/dto.go +++ b/internal/domain/main-entities/person/dto.go @@ -11,6 +11,8 @@ import ( type CreateDto struct { Name string `json:"name"` + FrontTitle *string `json:"frontTitle"` + EndTitle *string `json:"endTitle"` BirthDate *time.Time `json:"birthDate,omitempty"` BirthRegency_Code *string `json:"birthRegency_code"` Gender_Code *erp.GenderCode `json:"gender_code"` @@ -30,6 +32,8 @@ type ReadListDto struct { type FilterDto struct { Name string `json:"name"` + FrontTitle *string `json:"frontTitle"` + EndTitle *string `json:"endTitle"` BirthDate *time.Time `json:"birthDate,omitempty"` BirthRegency_Code *string `json:"birthRegency_code"` Gender_Code *erp.GenderCode `json:"gender_code"` @@ -69,6 +73,8 @@ type MetaDto struct { type ResponseDto struct { ecore.Main Name string `json:"name"` + FrontTitle *string `json:"frontTitle"` + EndTitle *string `json:"endTitle"` BirthDate *time.Time `json:"birthDate,omitempty"` BirthRegency_Code *string `json:"birthRegency_code"` Gender_Code *erp.GenderCode `json:"gender_code"` @@ -86,6 +92,8 @@ type ResponseDto struct { func (d *Person) ToResponse() ResponseDto { resp := ResponseDto{ Name: d.Name, + FrontTitle: d.FrontTitle, + EndTitle: d.EndTitle, BirthDate: d.BirthDate, BirthRegency_Code: d.BirthRegency_Code, Gender_Code: d.Gender_Code, diff --git a/internal/use-case/main-use-case/person/helper.go b/internal/use-case/main-use-case/person/helper.go index 32b4ff42..f4408ab2 100644 --- a/internal/use-case/main-use-case/person/helper.go +++ b/internal/use-case/main-use-case/person/helper.go @@ -18,6 +18,8 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Person) { } data.Name = inputSrc.Name + data.FrontTitle = inputSrc.FrontTitle + data.EndTitle = inputSrc.EndTitle data.BirthDate = inputSrc.BirthDate data.BirthRegency_Code = inputSrc.BirthRegency_Code data.Gender_Code = inputSrc.Gender_Code From 4f3dee37fa15a007ba025b9b9d2a66e645f18f42 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 1 Sep 2025 18:44:57 +0700 Subject: [PATCH 75/75] feat (employee): add create feat doctor, nurse, nutritionist, pharmacy --- internal/domain/main-entities/employee/dto.go | 9 ++- .../use-case/main-use-case/employee/case.go | 58 +++++++++++++++++-- .../use-case/main-use-case/employee/helper.go | 43 +++++++++----- 3 files changed, 87 insertions(+), 23 deletions(-) diff --git a/internal/domain/main-entities/employee/dto.go b/internal/domain/main-entities/employee/dto.go index 61b560db..66de6b25 100644 --- a/internal/domain/main-entities/employee/dto.go +++ b/internal/domain/main-entities/employee/dto.go @@ -11,13 +11,16 @@ import ( type CreateDto struct { User_Id *uint `json:"user_id"` - UserRequest *eu.CreateDto `json:"user_request"` + User *eu.CreateDto `json:"user"` Person_Id *uint `json:"person_id"` - PersonRequest *ep.CreateDto `json:"person_request"` + Person *ep.CreateDto `json:"person"` Position_Code ero.EmployeePosisitionCode `json:"position_code"` Division_Code *string `json:"division_code"` Number *string `json:"number"` Status_Code erc.ActiveStatusCode `json:"status_code"` + IHS_Number *string `json:"ihs_number"` + SIP_Number *string `json:"sip_number"` + Unit_Id *uint `json:"unit_id"` } type ReadListDto struct { @@ -99,6 +102,6 @@ func ToResponseList(data []Employee) []ResponseDto { func (c CreateDto) Sanitize() CreateDto { sanitized := c - sanitized.UserRequest.Password = "[REDACTED]" + sanitized.User.Password = "[REDACTED]" return sanitized } diff --git a/internal/use-case/main-use-case/employee/case.go b/internal/use-case/main-use-case/employee/case.go index 5d77ded2..0acc1e60 100644 --- a/internal/use-case/main-use-case/employee/case.go +++ b/internal/use-case/main-use-case/employee/case.go @@ -1,15 +1,25 @@ package employee import ( + ed "simrs-vx/internal/domain/main-entities/doctor" e "simrs-vx/internal/domain/main-entities/employee" + en "simrs-vx/internal/domain/main-entities/nurse" + et "simrs-vx/internal/domain/main-entities/nutritionist" + ep "simrs-vx/internal/domain/main-entities/pharmacist" "strconv" - dg "github.com/karincake/apem/db-gorm-pg" - d "github.com/karincake/dodol" + ud "simrs-vx/internal/use-case/main-use-case/doctor" + un "simrs-vx/internal/use-case/main-use-case/nurse" + ut "simrs-vx/internal/use-case/main-use-case/nutritionist" + up "simrs-vx/internal/use-case/main-use-case/pharmacist" + + ero "simrs-vx/internal/domain/references/organization" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" "gorm.io/gorm" ) @@ -34,11 +44,10 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } - if input.Person_Id == nil { - if err := createPerson(&input, &event, tx); err != nil { - return err - } + if err := createOrUpdatePerson(&input, &event, tx); err != nil { + return err } + if err := createUser(&input, &event, tx); err != nil { return err } @@ -49,6 +58,43 @@ func Create(input e.CreateDto) (*d.Data, error) { data = *resData } + switch input.Position_Code { + case ero.EPCDoc: + createDoc := ed.CreateDto{ + Employee_Id: &data.Id, + IHS_Number: input.IHS_Number, + SIP_Number: input.SIP_Number, + Unit_Id: input.Unit_Id, + } + if _, err := ud.CreateData(createDoc, &event, tx); err != nil { + return err + } + case ero.EPCNur: + createNurse := en.CreateDto{ + Employee_Id: &data.Id, + IHS_Number: input.IHS_Number, + } + if _, err := un.CreateData(createNurse, &event, tx); err != nil { + return err + } + case ero.EPCNut: + createNutritionist := et.CreateDto{ + Employee_Id: &data.Id, + IHS_Number: input.IHS_Number, + } + if _, err := ut.CreateData(createNutritionist, &event, tx); err != nil { + return err + } + case ero.EPCPha: + createPharmacist := ep.CreateDto{ + Employee_Id: &data.Id, + IHS_Number: input.IHS_Number, + } + if _, err := up.CreateData(createPharmacist, &event, tx); err != nil { + return err + } + } + mwRunner.setMwType(pu.MWTPost) // Run post-middleware if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { diff --git a/internal/use-case/main-use-case/employee/helper.go b/internal/use-case/main-use-case/employee/helper.go index 8eca2b26..48d658be 100644 --- a/internal/use-case/main-use-case/employee/helper.go +++ b/internal/use-case/main-use-case/employee/helper.go @@ -7,11 +7,14 @@ package employee import ( "errors" e "simrs-vx/internal/domain/main-entities/employee" - pl "simrs-vx/pkg/logger" + ep "simrs-vx/internal/domain/main-entities/person" + "strconv" up "simrs-vx/internal/use-case/main-use-case/person" uu "simrs-vx/internal/use-case/main-use-case/user" + pl "simrs-vx/pkg/logger" + "gorm.io/gorm" ) @@ -33,7 +36,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Employee) { } func createUser(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { - if input.UserRequest == nil { + if input.User == nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-create-fail", @@ -42,7 +45,7 @@ func createUser(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { } return pl.SetLogError(event, input) } - user, err := uu.CreateData(*input.UserRequest, event, tx) + user, err := uu.CreateData(*input.User, event, tx) if err != nil { return err } @@ -50,21 +53,33 @@ func createUser(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { return nil } -func createPerson(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { - if input.PersonRequest == nil { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "data-create-fail", - Detail: "person request is required", - Raw: errors.New("person request is required"), +func createOrUpdatePerson(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + if input.Person_Id == nil { + person, err := up.CreateData(*input.Person, event, tx) + if err != nil { + return err } - return pl.SetLogError(event, input) + input.Person_Id = &person.Id + return nil } - person, err := up.CreateData(*input.PersonRequest, event, tx) + + person, err := up.ReadDetailData(ep.ReadDetailDto{Id: *input.Person_Id}, event, tx) if err != nil { return err } - input.Person_Id = &person.Id - return nil + if person == nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: "person with ID " + strconv.Itoa(int(*input.Person_Id)) + " not found", + Raw: errors.New("person with ID " + strconv.Itoa(int(*input.Person_Id)) + " not found"), + } + return pl.SetLogError(event, input) + } + + if err := up.UpdateData(ep.UpdateDto{CreateDto: *input.Person}, person, event, tx); err != nil { + return err + } + return nil }