From 280d37357644f1ccf904af4cd3fca1190bbfaaf9 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Mon, 25 Aug 2025 14:07:14 +0700 Subject: [PATCH] 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)