diff --git a/assets/docs/control-letter.html b/assets/docs/control-letter.html new file mode 100644 index 00000000..780a052f --- /dev/null +++ b/assets/docs/control-letter.html @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + +
+ logo + +
+ SURAT RENCANA KONTROL +
+
+ RSUD dr. Saiful Anwar +
+
+ No. : {{ .Number }} +
+
+ Kepada Yth +
+
+
+ {{ .Doctor_Name }} +
+
+ Sp./Sub. {{ .DstUnit_Name }} +
+
+ +
+ Mohon Pemeriksaan dan Penanganan Lebih Lanjut: +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ No.Kartu + : + {{ .CardNumber }} +
+ Nama Peserta + : + {{ .Name }} +
+ Tgl.Lahir + : + {{ .BirthDate }} +
+ Diagnosa + : + {{ .Diagnose }} +
+ Rencana Kontrol + : + {{ .PlanDate }} +
+ +
+ Demikian atas bantuannya, diucapkan banyak terima kasih. +
+ + + + + + + + + + + + + + + + + + + +
Mengetahui:
Tgl. Cetak: {{ .PrintDate }}{{ .ResponsibleDoctor_Name }}
+ +
+ + + \ No newline at end of file diff --git a/assets/docs/general-consent.html b/assets/docs/general-consent.html new file mode 100644 index 00000000..de84a742 --- /dev/null +++ b/assets/docs/general-consent.html @@ -0,0 +1,325 @@ + + + + General Consent + + + + + + + + +
+ logo + +
+ PEMERINTAH PROVINSI JAWA TIMUR +
+
+ RUMAH SAKIT UMUM DAERAH Dr. SAIFUL ANWAR +
+
+ TERAKREDITASI KARS VERSI 2012 TINGKAT PARIPURNA +
+
+ Jl. Jaksa Agung Suprapto No. 2 MALANG 65111 +
+
Telp. (0341) 362101, Fax. (0341) 362110
+
Email: rsu-drsaifulanwar@jatimprov.go.id
+
Website: www.rsudsaifulanwar.jatimprov.go.id
+
+ logo +
+ +
+ +
+ FORMULIR PEMBERIAN INFORMASI DAN PERSETUJUAN UMUM +
+
+ (GENERAL CONSENT) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1. + Hak dan Kewajiban sebagai pasien : + Dengan menandatangani dokumen ini saya mengakui bahwa pada proses + pendaftaran untuk mendapatkan perawatan di RSUD Dr. Saiful Anwar telah + mendapatkan informasi tentang hak dan kewajiban saya sebagai pasien + (melalui leaflet/banner dan atau petugas). Saya berhak mendapatkan + pelayanan kesehatan sesuai standar, mendapatkan informasi yang cukup + tentang keadaan kesehatan, rencana tindakan, manfaat, risiko, + alternatif tindakan, serta biaya yang akan timbul. Saya berkewajiban + memberikan informasi kesehatan yang jujur dan lengkap kepada tenaga + kesehatan, mematuhi aturan rumah sakit, serta memenuhi kewajiban + pembayaran sesuai ketentuan yang berlaku. +
2. + Persetujuan Pelayanan : + Saya menyetujui dan memberikan persetujuan untuk dirawat di RSUD Dr. + Saiful Anwar dan dengan ini saya meminta dan memberikan kuasa kepada + RSUD Dr. Saiful Anwar, dokter dan perawat serta tenaga kesehatan + lainnya untuk memberikan asuhan keperawatan, pemeriksaan fisik yang + dilakukan oleh dokter dan perawat dan melakukan prosedur diagnostik + radiologi dan/atau terapi dan tata laksana sesuai pertimbangan dokter + yang diperlukan atau disarankan pada perawatan saya. Hal ini mencakup + seluruh pemeriksaan dan prosedur diagnostik rutin termasuk X-ray, + pemberian dan/atau tindakan medis serta penyuntikan (intramuskular, + intravena dan prosedur invasif lainnya), produk farmasi dan + obat-obatan, pemasangan alat kesehatan (kecuali yang membutuhkan + persetujuan khusus/tertulis) dan pengambilan darah untuk pemeriksaan + laboratorium atau pemeriksaan patologi. +
3. + Akses Informasi Kesehatan : + Saya memberi kuasa kepada setiap dan seluruh orang yang merawat saya + untuk memeriksa dan/atau memberitahukan informasi kesehatan saya + kepada pemberi kesehatan lain yang turut merawat saya selama di rumah + sakit ini, sesuai kebutuhan pelayanan. +
4. + Rahasia Kedokteran : + Saya setuju RSUD Dr. Saiful Anwar Malang wajib menjamin kerahasiaan + informasi medis saya baik untuk kepentingan perawatan dan pengobatan, + pendidikan maupun penelitian, sesuai ketentuan yang berlaku. +
5. + Membuka Rahasia Kedokteran : + Saya setuju untuk membuka rahasia kedokteran terkait dengan kondisi + kesehatan, asuhan dan pengobatan yang saya terima kepada: +
a) Dokter dan tenaga kesehatan lain yang turut merawat/memberikan + asuhan kepada saya; +
b) Perusahaan asuransi kesehatan atau perusahaan lainnya atau pihak + lain yang menjamin pembiayaan saya; +
c) Anggota keluarga saya : + {{ if eq (len .Relatives) 0 }} + .......................................... +{{ else }} +
    + {{ range $i, $name := .Relatives }} + {{ if lt $i 2 }} +
  • {{ $name }}
  • + {{ end }} + {{ end }} +
+{{ end }}
+
Saya memahami bahwa pembukaan rahasia ini hanya sejauh yang + diperlukan untuk tujuan perawatan, pembiayaan atau administrasi yang + terkait. +
6. + Privasi : + Saya memberi kuasa kepada RSUD Dr. Saiful Anwar Malang untuk menjaga + privasi dan kerahasiaan penyakit saya selama dalam perawatan, serta + membatasi akses terhadap informasi yang tidak berkepentingan. +
7. + Barang Pribadi : + Saya setuju untuk tidak membawa barang-barang berharga yang tidak + diperlukan (seperti perhiasan, elektronik, dll) selama dalam perawatan + di RSUD Dr. Saiful Anwar. Jika saya tetap membawa dan terjadi + kehilangan, kerusakan atau pencurian, maka RSUD Dr. Saiful Anwar tidak + bertanggung jawab atas hal tersebut, kecuali bila ada perjanjian + tertulis yang menyatakan lain. +
8. + Pengajuan Keluhan : + Saya menyatakan bahwa saya telah menerima informasi tentang adanya + tata cara mengajukan dan mengatasi keluhan terkait pelayanan medik + yang diberikan terhadap diri saya. Saya setuju untuk mengikuti tata + cara pengajuan keluhan sesuai prosedur yang ada di rumah sakit. +
9. + Kewajiban Pembayaran : + Saya menyatakan setuju, baik sebagai wali ataupun sebagai pasien, + bahwa sesuai pertimbangan pelayanan yang diberikan kepada pasien, maka + saya wajib untuk membayar total biaya pelayanan sesuai acuan biaya dan + ketentuan RSUD Dr. Saiful Anwar Malang dengan jaminan atau pribadi. + Apabila asuransi kesehatan swasta atau program pemerintah menanggung + pembiayaan saya, saya memberi wewenang kepada rumah sakit untuk + memberi tagihan dari semua pelayanan dan tindakan medis yang + diberikan. Tanggungan Asuransi saya mungkin menyatakan bahwa sebagian + pembayaran tetap menjadi tanggung jawab pribadi saya atau tidak + ditanggung oleh asuransi, maka rumah sakit berwenang memberi tagihan + untuk biaya yang tidak ditanggung oleh asuransi dan saya bertanggung + jawab untuk membayarnya. Apabila saya tidak memberikan persetujuan, + atau dikemudian hari mencabut persetujuan saya untuk melepaskan + rahasia kedokteran saya kepada perusahaan asuransi yang saya tentukan, + maka saya pribadi bertanggung jawab untuk membayar semua pelayanan dan + tindakan medis dari RSUD Dr. Saiful Anwar Malang. +
10. + Rumah Sakit Pendidikan : + Saya mengetahui bahwa RSUD Dr. Saiful Anwar merupakan rumah sakit + pendidikan yang menjadi tempat praktik klinik bagi mahasiswa + kedokteran dan profesi-profesi kesehatan lainnya, karena itu mereka + mungkin berpartisipasi dan atau terlibat dalam perawatan saya dan saya + menyetujui bahwa mereka berpartisipasi dalam perawatan saya sepanjang + di bawah supervisi dokter penanggung jawab pasien (DPJP). +
11. + Selama Dalam Perawatan : + Selama dalam perawatan saya dan keluarga saya akan mematuhi ketentuan + untuk tidak mengambil, menyimpan, mengedarkan gambar/video dokumen dan + aktivitas pelayanan selama di RS tanpa seizin rumah sakit. +
12. + Penegasan Kepercayaan : + Melalui dokumen ini, saya menegaskan kembali bahwa saya mempercayakan + kepada semua tenaga kesehatan rumah sakit untuk memberikan perawatan, + diagnostik dan terapi kepada saya sebagai pasien rawat inap atau rawat + jalan atau Instalasi Gawat Darurat (IGD), termasuk semua pemeriksaan + penunjang yang dibutuhkan untuk pengobatan dan tindakan yang + diperlukan. +
+ +

+ +
+ Saya menyetujui setiap pernyataan dalam formulir ini dan menandatangani + tanpa paksaan. +
+ + + + + +
+ Malang, {{ .Date }} +
+ + + + + + + + + + + + + + +
+
+ Pasien/keluarga/
penanggung jawab +
+ +
+ ....................................... +
+ +
+ {{ .Responsible }} +
+
+
+ Pemberi Informasi +
+ +
+ ....................................... +
+ +
+ {{ .Informant }} +
+
+
+ Saksi I +
+ +
+ ....................................... +
+ +
+ {{ .Witness1 }} +
+
+
+ Saksi II +
+ +
+ ....................................... +
+ +
+ {{ .Witness2 }} +
+
+ + diff --git a/assets/docs/resume.html b/assets/docs/resume.html new file mode 100644 index 00000000..4ad209ff --- /dev/null +++ b/assets/docs/resume.html @@ -0,0 +1,707 @@ + + + + + General Consent + + + + + + + + + + +
+ logo + +
+ PEMERINTAH PROVINSI JAWA TIMUR +
+
+ RUMAH SAKIT UMUM DAERAH Dr. SAIFUL ANWAR +
+
+ TERAKREDITASI KARS VERSI 2012 TINGKAT PARIPURNA +
+
+ Jl. Jaksa Agung Suprapto No. 2 MALANG 65111 +
+
Telp. (0341) 362101, Fax. (0341) 362110
+
Email: rsu-drsaifulanwar@jatimprov.go.id
+
Website: www.rsudsaifulanwar.jatimprov.go.id
+
+ logo +
+ +
+ +
+ IDENTITAS PASIEN +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ No. RM + : {{ .MedicalRecord }} + Ruang/Klinik + : {{ .Unit }}
+ NIK + : {{ .NIK }} + Kelas + : {{ .Class }}
+ Nama + : {{ .Name }} + DPJP + : {{ .Doctor_Name }}
+ Tempat/Tanggal Lahir + : {{ .BirthPlaceDate }}
+ Jenis Kelamin + : {{ .Gender }}
+ No. Telepon + : {{ .Phone }}
+ +
+

+ RESUME MEDIS +

+

Medical Discharge Summary

+ + +

(Diisi oleh Dokter Penanggung Jawab Pelayanan)

+ + + + + + + + + + + + + + + + + + + + + +
+ Tanggal Masuk + : {{ .StartedAt }}
+ Tanggal Keluar + : {{ .FinishedAt }}
+ Diagnosis Masuk + : {{ .DiagnosisIn }}
+ Diagnosis Keluar + : {{ .DiagnosisOut }}
+ + + + + + + + + + + + {{ $dataLen := len .Diagnosis }} + {{ if gt $dataLen 0 }} + + {{ range $index, $diagnosis := .Diagnosis }} + + + + + + + {{ end }} + + + {{ if eq $dataLen 1 }} + + + + + + + {{ end }} + {{ else }} + + + + + + + + + + + + + + {{ end }} + +
+ No + + Diagnosa + + Dasar Diagnosa + + Kode ICD-10 +
{{ if eq $index 0 }}1{{ else if eq $index 1 }}2{{ else if eq $index 2 }}3{{ else if eq $index 3 }}4{{ else if eq $index 4 }}5{{ else }}{{ $index }}{{ end }}{{ $diagnosis.DiagnosisName }}{{ $diagnosis.Basis }}{{ $diagnosis.ICD10 }}
2
1
2
+ + + + + + + +

Kajian Awal Medis

+

(Diisi oleh Dokter Penanggung Jawab Pelayanan)

+ + + + + + + + + + + + + + + + + +
+ Keluhan Utama + : {{ .MainComplaint }}
+ Riwayat Penyakit + : {{ .MedicalHistory }}
+ Pemeriksaan Fisik & Keadaan Umum + : {{ .PhysicalExamination }}
+ +

Pemeriksaan Penunjang

+ + + + + + +
+ Pemeriksaan + : {{ .SupportingExamination }}
+ +
+ + +

Tindakan Medis

+ + + + + + + + + + + {{ $dataLen := len .MedicalActions }} + {{ if gt $dataLen 0 }} + + {{ range $index, $action := .MedicalActions }} + + + + + + + {{ end }} + + + {{ if eq $dataLen 1 }} + + + + + + + {{ end }} + {{ else }} + + + + + + + + + + + + + + {{ end }} + +
+ No + + Tindakan + + Dasar Tindakan + + Kode ICD 9-CM +
{{ if eq $index 0 }}1{{ else if eq $index 1 }}2{{ else if eq $index 2 }}3{{ else if eq $index 3 }}4{{ else if eq $index 4 }}5{{ else }}{{ $index }}{{ end }}{{ $action.Action }}{{ $action.Basis }}{{ $action.ICD9 }}
2
1
2
+ + + + + + + + +
+ Tindakan Medis + : {{ .MedicalAction }}
+ + + + + + +
+

Konsultasi

+
+ + + + + + + + + + {{ $dataLen := len .Consultations }} + {{ if gt $dataLen 0 }} + + {{ range $index, $consultation := .Consultations }} + + + + + + {{ end }} + + + {{ if eq $dataLen 1 }} + + {{ end }} + {{ else }} + + + + {{ end }} + +
NoKonsultasiJawaban Konsultasi
{{ if eq $index 0 }}1{{ else if eq $index 1 }}2{{ else if eq $index 2 }}3{{ else if eq $index 3 }}4{{ else if eq $index 4 }}5{{ else }}{{ $index }}{{ end }}{{ $consultation.Consultation }}{{ $consultation.ConsultationAnswer }}
2
1
2
+ + + +

Terapi

+ + + + + + +
+ Alergi + : + {{ .Allergy}} +
+ + + + + + +
+

Obat yang diberikan

+ + + + + + + + + {{ $dataLen := len .Medications }} + + {{ if gt $dataLen 0 }} + + {{ range .Medications }} + + + + + {{ end }} + + + {{ if eq $dataLen 1 }} + + + + + {{ end }} + {{ else }} + + + + + + + + + + {{ end }} + +
+ Terapi (Farmakologi & Non Farmakologi) Selama Perawatan + + Terapi (Farmakologi & Non Farmakologi) Waktu Pulang +
{{ .DuringTreatment }}{{ .AtDischarge }}
  
  
  
+
+ + + + + + + +

Kondisi saat Pulang

+ + + + + + + + + + + + + + + + + + + + + + + + +
Kesadaran: {{ .ConsciousnessLevel }}
+ Tanda Vital +

Vital sign

+
:
+ + + + + + +
+ + + + + {{ if and .BloodPressure (ne .BloodPressure "0/0") (ne .BloodPressure "") }} + + {{ else }} + + {{ end }} + + + + + + + {{ if ne .BodyTemperature 0.0 }} + + {{ else }} + + {{ end }} + + + + + {{ if ne .HeartRate 0.0 }} + + {{ else }} + + {{ end }} + + +
+ Tekanan Darah +

Blood Pressure

+
: {{ .BloodPressure }} mmHg +
+ Suhu +

Temperatur

+
: {{ .BodyTemperature }} C +
+ Nadi +

Pulse

+
: {{ .HeartRate }} x/Menit
+
+ + + + + + {{ if ne .RespirationRate 0.0 }} + + {{ else }} + + {{ end }} + + + + + + + + +
+ Frekuensi Nafas +

Respiratory rate

+
: {{ .RespirationRate }} x/Menit
+ Skala Nyeri +

Pain Scale

+
: {{ .PainScale }}
+
+ +
Keadaan Keluar: {{ .ConditionOnDischarge }}
Cara Keluar +

Patient discharge of hospital

+
:{{ .DischargeMethod }}
+ + + + + + + + + + + + + + + + + + + + + + + +
+

INSTRUKSI UNTUK TINDAK LANJUT

+

Follow up Consultation to

+
+

Kontrol Ke

+

Follow up Consultation to

+
+ + + + + + + + + + + + + + + + +
Fasyankes: {{ .NIK }}
Tanggal: {{ .NIK }}
Klinik: {{ .NIK }}
+
+

Dalam keadaan darurat dapat menghubungi

+

In case of emergencycontact

+
+

IGD

+

(Accident & Emergency Instalation)

+
+ + + + + + +
Telepon +

Phone

+
: (0341) 362101
+
+

EDUKASI & RENCANA TINDAK LANJUT

+

Follow up plan (if necessary)

+
+

+

(bila diperlukan)

+
+ + + + + + + + + + + + + + + +
+ Malang, {{ .Date }}
+ Dokter Penanggung Jawab Pelayanan +
+ ({{ .Doctor_Name }}) +
+ +
+
+

*) Data dapat berubah setelah pasien pulang sesuai prosedur

+ + + + \ No newline at end of file diff --git a/assets/docs/screening-form-a.html b/assets/docs/screening-form-a.html new file mode 100644 index 00000000..4f34b876 --- /dev/null +++ b/assets/docs/screening-form-a.html @@ -0,0 +1,167 @@ + + + + + + + + + +
+ Tanggal Terbit : {{ .IssuedDate }} +
+ + + + + + + + + + + + + + + + + + +
No. RM:{{ .MedicalRecord }}
Nama:{{ .Name }}
Tanggal Lahir:{{ .BirthDate }}
+ +
+

+ FORM A +

+ +
+

Kajian Awal Medis:

+ + + {{ if gt (len .EarlyMedic) 0 }} + {{ range .EarlyMedic }} + + + + {{ end }} + {{ else }} + + + + {{ end }} + +
+ ☑ {{ . }} +
+
+ +
+

ASSESMEN:

+ + + + +
+ {{ .Assessment }} +
+
+ +
+

IDENTIFIKASI MASALAH:

+ + {{ if gt (len .ProblemIdentification) 0 }} + {{ range .ProblemIdentification }} + + + + {{ end }} + {{ else }} + + + + {{ end }} + +
+ ☑ {{ . }} +
+
+ +
+

PERENCANAAN:

+ + + + +
+ {{ .Planning }} +
+
+ + + + + + + + + + + +
+ {{ .Date }}
+
+ ({{ .Employee_Name }}) +
+ +
+ + + \ No newline at end of file diff --git a/assets/docs/screening-form-b.html b/assets/docs/screening-form-b.html new file mode 100644 index 00000000..9abc94ce --- /dev/null +++ b/assets/docs/screening-form-b.html @@ -0,0 +1,109 @@ + + + + + + + + + +
+ Tanggal Terbit : {{ .IssuedDate }} +
+ + + + + + + + + + + + + + + + + + +
No. RM:{{ .MedicalRecord }}
Nama:{{ .Name }}
Tanggal Lahir:{{ .BirthDate }}
+ + + + + + + + + + + {{ range .FormB }} + + + + + + + + + {{ end }} + +
NOTanggal/jam + Implementasi, Monitoring, Fasilitasi, koordinasi, komunikasi dan kolaborasi, + advokasi, hasil pelayanan, Terminasi + MPP
{{ .Number }}{{ .Date }} + {{ .Value }} + + {{ .Employee_Name }} +
+ +
+ + + \ No newline at end of file diff --git a/assets/docs/therapy-protocol-1.html b/assets/docs/therapy-protocol-1.html new file mode 100644 index 00000000..1e3949d8 --- /dev/null +++ b/assets/docs/therapy-protocol-1.html @@ -0,0 +1,312 @@ + + + + + General Consent + + + + + + + + + + +
+ logo + +
+ PEMERINTAH PROVINSI JAWA TIMUR +
+
+ RUMAH SAKIT UMUM DAERAH Dr. SAIFUL ANWAR +
+
+ TERAKREDITASI KARS VERSI 2012 TINGKAT PARIPURNA +
+
+ Jl. Jaksa Agung Suprapto No. 2 MALANG 65111 +
+
Telp. (0341) 362101, Fax. (0341) 362110
+
Email: rsu-drsaifulanwar@jatimprov.go.id
+
Website: www.rsudsaifulanwar.jatimprov.go.id
+
+ logo +
+ +
+ +
+

+ Protokol Terapi +

+

Layanan Kedokteran Fisik dan Rehabilitasi +

+
+Terapi Ke

+{{ .Repalcable }} +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ No RM + {{ .Repalcable }}
+ Nama Pasien + {{ .Repalcable }}
+ Tanggal Lahir + {{ .Repalcable }}
+ Diagnosa + {{ .Repalcable }}
+ Permintaan Terapi + {{ .Repalcable }}
+ Frekuensi Terapi + + 2 x Per Minggu       + Evaluasi: 1 Bulan +
+ Target Terapi + {{ .Repalcable }}
+ Waktu Mencapai Target + {{ .Repalcable }}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ NO + + Tanggal + + Dokter + + Fisioterapi + + Terapi Wicara + + Okupansi Terapi + + Ortotik Prostetik + + PSM + + TTD Pasien +
+ 1 + {{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}
+ 2 + {{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}
+ 3 + {{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}
+ 4 + {{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}
+ 5 + {{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}
+ 6 + {{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}
+ 7 + {{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}
+ 8 + {{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}{{ .Repalcable }}
+ + + + + + + + + + + +
+ Evaluasi + {{ .Repalcable }}
+ Rencana Selanjutnya + {{ .Repalcable }}
+ + + + + + + + + + + +
+ Malang,
+ Cap dan TTD Dr. SpKFR +
+ (........................................................) +
+ +
+ + + \ No newline at end of file diff --git a/assets/docs/therapy-protocol-2.html b/assets/docs/therapy-protocol-2.html new file mode 100644 index 00000000..b468bd43 --- /dev/null +++ b/assets/docs/therapy-protocol-2.html @@ -0,0 +1,217 @@ + + + + + General Consent + + + + + + + + + +
+ logo + +
+ PEMERINTAH PROVINSI JAWA TIMUR +
+
+ RUMAH SAKIT UMUM DAERAH Dr. SAIFUL ANWAR +
+
+ TERAKREDITASI KARS VERSI 2012 TINGKAT PARIPURNA +
+
+ Jl. Jaksa Agung Suprapto No. 2 MALANG 65111 +
+
Telp. (0341) 362101, Fax. (0341) 362110
+
Email: rsu-drsaifulanwar@jatimprov.go.id
+
Website: www.rsudsaifulanwar.jatimprov.go.id
+
+ +
+ + + + + + + + + + + + + + + + + + + +
+ No RM: + {{ .Repalcable }}
+ Nama Pasien + {{ .Repalcable }}
+ Diagnosa + {{ .Repalcable }}
+ Permintaan Terapi + {{ .Repalcable }}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ PELAKSANAAN PROGRAM + + Tanggal + + TTD +
+ PASIEN + + DOKTER + + TERAPIS +
1. {{ .Repalcable }}{{ .Repalcable }}
2. {{ .Repalcable }}{{ .Repalcable }}
3. {{ .Repalcable }}{{ .Repalcable }}
4. {{ .Repalcable }}{{ .Repalcable }}
5. {{ .Repalcable }}{{ .Repalcable }}
6. {{ .Repalcable }}{{ .Repalcable }}
7. {{ .Repalcable }}{{ .Repalcable }}
8. {{ .Repalcable }}{{ .Repalcable }}
9. {{ .Repalcable }}{{ .Repalcable }}
10. {{ .Repalcable }}{{ .Repalcable }}
11. {{ .Repalcable }}{{ .Repalcable }}
12. {{ .Repalcable }}{{ .Repalcable }}
13. {{ .Repalcable }}{{ .Repalcable }}
14. {{ .Repalcable }}{{ .Repalcable }}
15. {{ .Repalcable }}{{ .Repalcable }}
16. {{ .Repalcable }}{{ .Repalcable }}
17. {{ .Repalcable }}{{ .Repalcable }}
18. {{ .Repalcable }}{{ .Repalcable }}
19. {{ .Repalcable }}{{ .Repalcable }}
20. {{ .Repalcable }}{{ .Repalcable }}
+ + + + + + + + + + + + + +
+ Tempat & Tanggal
+ Cap dan TTD Dr. SpKFR +
+ (.................................................) +
+ +
+ + + \ No newline at end of file diff --git a/assets/docs/therapy-protocol-3.html b/assets/docs/therapy-protocol-3.html new file mode 100644 index 00000000..6623fb9e --- /dev/null +++ b/assets/docs/therapy-protocol-3.html @@ -0,0 +1,241 @@ + + + + + General Consent + + + + + + + + + +
+ logo + +
+ PEMERINTAH PROVINSI JAWA TIMUR +
+
+ RUMAH SAKIT UMUM DAERAH Dr. SAIFUL ANWAR +
+
+ TERAKREDITASI KARS VERSI 2012 TINGKAT PARIPURNA +
+
+ Jl. Jaksa Agung Suprapto No. 2 MALANG 65111 +
+
Telp. (0341) 362101, Fax. (0341) 362110
+
Email: rsu-drsaifulanwar@jatimprov.go.id
+
Website: www.rsudsaifulanwar.jatimprov.go.id
+
+ +
+ +
+

+ Lembar Formulir Rawat Jalan
Layanan Kedokteran Fisik dan Rehabilitasi +

+
+ +
+ + + + + + + +
I. Identitas PasienNo. RM: {{ .Repalcable }}
+ + + + + + + + + + + + + + + + + + + + + + + +
+ Nama Pasien + : {{ .Repalcable }}
+ Tanggal Lahir + : {{ .Repalcable }}
+ Aalamat + : {{ .Repalcable }}
+ Telp / HP + : {{ .Repalcable }}
+ Hubungan dengan Tertanggung + : + ☑ Suami / Istri +    + ▢ Anak +
+
+ + +
+ + + + +
II. Diisi oleh Dokter SpKFR
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Tanggal Pelayanan + : {{ .Repalcable }}
+ Anamnesa + : {{ .Repalcable }}
+ Pemeriksaan Fisik dan Uji Fungsi + : {{ .Repalcable }}
+ Diagnosis Medis (ICD-10) + : {{ .Repalcable }}
+ Diagnosis Fungsi (ICD-10) + : {{ .Repalcable }}
+ Pemeriksaan Penunjang + : {{ .Repalcable }}
+ Tata Laksana KFR (ICD 9 CM) + : {{ .Repalcable }}
+ Anjuran + : {{ .Repalcable }}
+ Evaluasi + : {{ .Repalcable }}
+ Suspek Penyakit Akibat Kerja + : + ☑ Ya   ( {{ .Repalcable }} ) + +
+ ▢ Tidak +
+
+ + + + + + + + + + + +
+ TTD Pasien + + Tempat & Tanggal
+ Cap dan TTD Dr. SpKFR +
+ (........................................................) + + (........................................................) +
+ +
+ + + \ No newline at end of file diff --git a/cmd/bpjs-api/config.yml-example b/cmd/bpjs-api/config.yml-example index 60b1644c..dcea2f07 100644 --- a/cmd/bpjs-api/config.yml-example +++ b/cmd/bpjs-api/config.yml-example @@ -57,9 +57,6 @@ corsCfg: satuSehatCfg: host: localhost:8200 -bpjsCfg: - host: localhost:8200 - corsCfg: allowedOrigins: - http://example.com diff --git a/cmd/main-api/config.yml-example b/cmd/main-api/config.yml-example index 60b1644c..f5f03f10 100644 --- a/cmd/main-api/config.yml-example +++ b/cmd/main-api/config.yml-example @@ -57,13 +57,20 @@ corsCfg: satuSehatCfg: host: localhost:8200 -bpjsCfg: - host: localhost:8200 - corsCfg: allowedOrigins: - http://example.com allowedMethod: bpjsCfg: - baseUrl: \ No newline at end of file + baseUrl: + +syncUrlCfg: + enable: false + targetHost: + prefix: new-to-old + source: old-app + secretKey: new-world-order!! + +docsCfg: + path: ../../assets/docs/ \ No newline at end of file diff --git a/cmd/main-migration/Makefile b/cmd/main-migration/Makefile index f445a815..a93bb244 100644 --- a/cmd/main-migration/Makefile +++ b/cmd/main-migration/Makefile @@ -16,3 +16,7 @@ apply: ## Calculate the schema hash hash: atlas migrate hash + +## Apply non-linear +apply-non-linear: + atlas migrate apply --env $(ENV) --exec-order non-linear \ No newline at end of file diff --git a/cmd/main-migration/migrations/20251113101344.sql b/cmd/main-migration/migrations/20251113101344.sql new file mode 100644 index 00000000..cda3abed --- /dev/null +++ b/cmd/main-migration/migrations/20251113101344.sql @@ -0,0 +1,11 @@ +-- Create "MedicineForm" table +CREATE TABLE "public"."MedicineForm" ( + "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_MedicineForm_Code" UNIQUE ("Code") +); diff --git a/cmd/main-migration/migrations/20251113120533.sql b/cmd/main-migration/migrations/20251113120533.sql new file mode 100644 index 00000000..b8d56fe8 --- /dev/null +++ b/cmd/main-migration/migrations/20251113120533.sql @@ -0,0 +1,2 @@ +-- Modify "Medicine" table +ALTER TABLE "public"."Medicine" ADD COLUMN "MedicineForm_Code" character varying(20) NULL, ADD CONSTRAINT "fk_Medicine_MedicineForm" FOREIGN KEY ("MedicineForm_Code") REFERENCES "public"."MedicineForm" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251114062746.sql b/cmd/main-migration/migrations/20251114062746.sql new file mode 100644 index 00000000..cdcfb350 --- /dev/null +++ b/cmd/main-migration/migrations/20251114062746.sql @@ -0,0 +1,2 @@ +-- Modify "TherapyProtocol" table +ALTER TABLE "public"."TherapyProtocol" ADD COLUMN "Status_Code" character varying(10) NULL; diff --git a/cmd/main-migration/migrations/20251117005942.sql b/cmd/main-migration/migrations/20251117005942.sql new file mode 100644 index 00000000..84a34010 --- /dev/null +++ b/cmd/main-migration/migrations/20251117005942.sql @@ -0,0 +1,2 @@ +-- Rename a column from "Count" to "Quantity" +ALTER TABLE "public"."DeviceOrderItem" RENAME COLUMN "Count" TO "Quantity"; diff --git a/cmd/main-migration/migrations/20251117075427.sql b/cmd/main-migration/migrations/20251117075427.sql new file mode 100644 index 00000000..a6e0599b --- /dev/null +++ b/cmd/main-migration/migrations/20251117075427.sql @@ -0,0 +1,2 @@ +-- Modify "GeneralConsent" table +ALTER TABLE "public"."GeneralConsent" ADD COLUMN "FileUrl" character varying(1024) NULL; diff --git a/cmd/main-migration/migrations/20251118074929.sql b/cmd/main-migration/migrations/20251118074929.sql new file mode 100644 index 00000000..758110f2 --- /dev/null +++ b/cmd/main-migration/migrations/20251118074929.sql @@ -0,0 +1,2 @@ +-- Modify "GeneralConsent" table +ALTER TABLE "public"."GeneralConsent" DROP CONSTRAINT "fk_GeneralConsent_Encounter", ADD CONSTRAINT "fk_Encounter_GeneralConsents" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251119063438.sql b/cmd/main-migration/migrations/20251119063438.sql new file mode 100644 index 00000000..1d67246e --- /dev/null +++ b/cmd/main-migration/migrations/20251119063438.sql @@ -0,0 +1,4 @@ +-- Modify "Person" table +ALTER TABLE "public"."Person" DROP CONSTRAINT "uni_Person_ResidentIdentityNumber", ALTER COLUMN "ResidentIdentityNumber" TYPE text; +-- Create index "idx_resident_identity" to table: "Person" +CREATE UNIQUE INDEX "idx_resident_identity" ON "public"."Person" ("ResidentIdentityNumber") WHERE ("DeletedAt" IS NULL); diff --git a/cmd/main-migration/migrations/20251119065730.sql b/cmd/main-migration/migrations/20251119065730.sql new file mode 100644 index 00000000..23015cdb --- /dev/null +++ b/cmd/main-migration/migrations/20251119065730.sql @@ -0,0 +1,6 @@ +-- Modify "Person" table +ALTER TABLE "public"."Person" DROP CONSTRAINT "uni_Person_DrivingLicenseNumber", DROP CONSTRAINT "uni_Person_PassportNumber", ALTER COLUMN "ResidentIdentityNumber" TYPE character varying(16), ALTER COLUMN "Nationality" TYPE character varying(50); +-- Create index "idx_driver_license" to table: "Person" +CREATE UNIQUE INDEX "idx_driver_license" ON "public"."Person" ("DrivingLicenseNumber") WHERE ("DeletedAt" IS NULL); +-- Create index "idx_passport" to table: "Person" +CREATE UNIQUE INDEX "idx_passport" ON "public"."Person" ("PassportNumber") WHERE ("DeletedAt" IS NULL); diff --git a/cmd/main-migration/migrations/20251119072302.sql b/cmd/main-migration/migrations/20251119072302.sql new file mode 100644 index 00000000..28208ae7 --- /dev/null +++ b/cmd/main-migration/migrations/20251119072302.sql @@ -0,0 +1,2 @@ +-- Modify "VclaimSepPrint" table +ALTER TABLE "public"."VclaimSepPrint" DROP CONSTRAINT "fk_VclaimSepPrint_VclaimSep", ADD CONSTRAINT "fk_VclaimSep_Prints" FOREIGN KEY ("VclaimSep_Number") REFERENCES "public"."VclaimSep" ("Number") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251119072450.sql b/cmd/main-migration/migrations/20251119072450.sql new file mode 100644 index 00000000..1332c843 --- /dev/null +++ b/cmd/main-migration/migrations/20251119072450.sql @@ -0,0 +1,15 @@ +-- Create "VclaimSepControlLetter" table +CREATE TABLE "public"."VclaimSepControlLetter" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "VclaimSep_Number" character varying(19) NULL, + "Number" character varying(20) NULL, + "Value" text NULL, + "FileUrl" character varying(1024) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_VclaimSepControlLetter_FileUrl" UNIQUE ("FileUrl"), + CONSTRAINT "uni_VclaimSepControlLetter_Number" UNIQUE ("Number"), + CONSTRAINT "fk_VclaimSep_ControlLetters" FOREIGN KEY ("VclaimSep_Number") REFERENCES "public"."VclaimSep" ("Number") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/20251120005512.sql b/cmd/main-migration/migrations/20251120005512.sql new file mode 100644 index 00000000..8fd4b6af --- /dev/null +++ b/cmd/main-migration/migrations/20251120005512.sql @@ -0,0 +1,2 @@ +-- Modify "McuOrderItem" table +ALTER TABLE "public"."McuOrderItem" ADD COLUMN "Note" character varying(1024) NULL; diff --git a/cmd/main-migration/migrations/20251120074415.sql b/cmd/main-migration/migrations/20251120074415.sql new file mode 100644 index 00000000..ae6cd675 --- /dev/null +++ b/cmd/main-migration/migrations/20251120074415.sql @@ -0,0 +1,11 @@ +-- Create "Resume" table +CREATE TABLE "public"."Resume" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NOT NULL, + "Value" text NULL, + "FileUrl" character varying(1024) NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/main-migration/migrations/20251121033803.sql b/cmd/main-migration/migrations/20251121033803.sql new file mode 100644 index 00000000..48cb7f47 --- /dev/null +++ b/cmd/main-migration/migrations/20251121033803.sql @@ -0,0 +1,14 @@ +-- Create "VclaimReference" table +CREATE TABLE "public"."VclaimReference" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Date" timestamptz NULL, + "SrcCode" text NULL, + "SrcName" text NULL, + "Number" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Encounter_VclaimReference" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/20251124071457.sql b/cmd/main-migration/migrations/20251124071457.sql new file mode 100644 index 00000000..0cb4c4e7 --- /dev/null +++ b/cmd/main-migration/migrations/20251124071457.sql @@ -0,0 +1,2 @@ +-- Modify "Resume" table +ALTER TABLE "public"."Resume" ADD COLUMN "Doctor_Code" character varying(10) NULL, ADD COLUMN "Status_Code" character varying(10) NOT NULL, ADD CONSTRAINT "fk_Resume_Doctor" FOREIGN KEY ("Doctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251125125303.sql b/cmd/main-migration/migrations/20251125125303.sql new file mode 100644 index 00000000..56d16371 --- /dev/null +++ b/cmd/main-migration/migrations/20251125125303.sql @@ -0,0 +1,2 @@ +-- Modify "Encounter" table +ALTER TABLE "public"."Encounter" ADD COLUMN "Responsible_Nurse_Code" character varying(20) NULL, ADD CONSTRAINT "fk_Encounter_Responsible_Nurse" FOREIGN KEY ("Responsible_Nurse_Code") REFERENCES "public"."Nurse" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251126064057.sql b/cmd/main-migration/migrations/20251126064057.sql new file mode 100644 index 00000000..fd823ff9 --- /dev/null +++ b/cmd/main-migration/migrations/20251126064057.sql @@ -0,0 +1,2 @@ +-- Modify "InternalReference" table +ALTER TABLE "public"."InternalReference" ADD COLUMN "SrcDoctor_Code" character varying(20) NULL, ADD COLUMN "SrcNurse_Code" character varying(20) NULL, ADD COLUMN "Nurse_Code" character varying(20) NULL, ADD CONSTRAINT "fk_InternalReference_Nurse" FOREIGN KEY ("Nurse_Code") REFERENCES "public"."Nurse" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_InternalReference_SrcDoctor" FOREIGN KEY ("SrcDoctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_InternalReference_SrcNurse" FOREIGN KEY ("SrcNurse_Code") REFERENCES "public"."Nurse" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251201081333.sql b/cmd/main-migration/migrations/20251201081333.sql new file mode 100644 index 00000000..876b32b7 --- /dev/null +++ b/cmd/main-migration/migrations/20251201081333.sql @@ -0,0 +1,13 @@ +-- Create "Screening" table +CREATE TABLE "public"."Screening" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Employee_Id" bigint NULL, + "Type" text NULL, + "Value" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Screening_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/20251201104439.sql b/cmd/main-migration/migrations/20251201104439.sql new file mode 100644 index 00000000..50f60b6b --- /dev/null +++ b/cmd/main-migration/migrations/20251201104439.sql @@ -0,0 +1,19 @@ +-- Create "ActionReport" table +CREATE TABLE "public"."ActionReport" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Date" character varying(20) NOT NULL, + "Doctor_Code" character varying(10) NULL, + "Operator_Employe_Id" bigint NULL, + "Assistant_Employe_Id" bigint NULL, + "Instrumentor_Employe_Id" bigint NULL, + "Diagnose" character varying(1024) NULL, + "Procedures" character varying(10240) NULL, + "Nurse_Code" character varying(10) NULL, + "Value" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_ActionReport_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/20251201113804.sql b/cmd/main-migration/migrations/20251201113804.sql new file mode 100644 index 00000000..0f5c5123 --- /dev/null +++ b/cmd/main-migration/migrations/20251201113804.sql @@ -0,0 +1,2 @@ +-- Modify "ActionReport" table +ALTER TABLE "public"."ActionReport" DROP COLUMN "Date", DROP COLUMN "Procedures"; diff --git a/cmd/main-migration/migrations/20251201113858.sql b/cmd/main-migration/migrations/20251201113858.sql new file mode 100644 index 00000000..fd6fddc9 --- /dev/null +++ b/cmd/main-migration/migrations/20251201113858.sql @@ -0,0 +1,2 @@ +-- Modify "ActionReport" table +ALTER TABLE "public"."ActionReport" ADD COLUMN "Date" timestamptz NOT NULL; diff --git a/cmd/main-migration/migrations/20251201114751.sql b/cmd/main-migration/migrations/20251201114751.sql new file mode 100644 index 00000000..6611b811 --- /dev/null +++ b/cmd/main-migration/migrations/20251201114751.sql @@ -0,0 +1,2 @@ +-- Modify "ActionReport" table +ALTER TABLE "public"."ActionReport" ADD CONSTRAINT "fk_ActionReport_Instrumentor_Employe" FOREIGN KEY ("Instrumentor_Employe_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_ActionReport_Nurse" FOREIGN KEY ("Nurse_Code") REFERENCES "public"."Nurse" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_ActionReport_Operator_Employe" FOREIGN KEY ("Operator_Employe_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251201114913.sql b/cmd/main-migration/migrations/20251201114913.sql new file mode 100644 index 00000000..5155ed37 --- /dev/null +++ b/cmd/main-migration/migrations/20251201114913.sql @@ -0,0 +1,2 @@ +-- Modify "ActionReport" table +ALTER TABLE "public"."ActionReport" ADD CONSTRAINT "fk_ActionReport_Doctor" FOREIGN KEY ("Doctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251202030445.sql b/cmd/main-migration/migrations/20251202030445.sql new file mode 100644 index 00000000..6026dd58 --- /dev/null +++ b/cmd/main-migration/migrations/20251202030445.sql @@ -0,0 +1,2 @@ +-- Modify "Screening" table +ALTER TABLE "public"."Screening" ADD COLUMN "Status" text NULL, ADD COLUMN "FileUrl" character varying(1024) NULL; diff --git a/cmd/main-migration/migrations/20251202044430.sql b/cmd/main-migration/migrations/20251202044430.sql new file mode 100644 index 00000000..308b72a7 --- /dev/null +++ b/cmd/main-migration/migrations/20251202044430.sql @@ -0,0 +1,2 @@ +-- Modify "Item" table +ALTER TABLE "public"."Item" ADD COLUMN "BuyingPrice" numeric NULL, ADD COLUMN "SellingPrice" numeric NULL; diff --git a/cmd/main-migration/migrations/20251202064000.sql b/cmd/main-migration/migrations/20251202064000.sql new file mode 100644 index 00000000..7fed5f08 --- /dev/null +++ b/cmd/main-migration/migrations/20251202064000.sql @@ -0,0 +1,2 @@ +-- Modify "Soapi" table +ALTER TABLE "public"."Soapi" ALTER COLUMN "TypeCode" TYPE character varying(15); diff --git a/cmd/main-migration/migrations/20251202130629.sql b/cmd/main-migration/migrations/20251202130629.sql new file mode 100644 index 00000000..88b685fe --- /dev/null +++ b/cmd/main-migration/migrations/20251202130629.sql @@ -0,0 +1,101 @@ +-- Modify "Consultation" table +ALTER TABLE "public"."Consultation" ALTER COLUMN "DstUnit_Code" TYPE character varying(20); +-- Modify "ControlLetter" table +ALTER TABLE "public"."ControlLetter" ALTER COLUMN "Unit_Code" TYPE character varying(20), ALTER COLUMN "Specialist_Code" TYPE character varying(20), ALTER COLUMN "Subspecialist_Code" TYPE character varying(20); +-- Modify "Encounter" table +ALTER TABLE "public"."Encounter" ALTER COLUMN "Specialist_Code" TYPE character varying(20), ALTER COLUMN "Subspecialist_Code" TYPE character varying(20), ALTER COLUMN "Unit_Code" TYPE character varying(20); +-- Modify "Chemo" table +ALTER TABLE "public"."Chemo" ALTER COLUMN "SrcUnit_Code" TYPE character varying(20); +-- Modify "Installation" table +ALTER TABLE "public"."Installation" ALTER COLUMN "Code" TYPE character varying(20); +-- Modify "InternalReference" table +ALTER TABLE "public"."InternalReference" ALTER COLUMN "Unit_Code" TYPE character varying(20); +-- Modify "PracticeSchedule" table +ALTER TABLE "public"."PracticeSchedule" ALTER COLUMN "Unit_Code" TYPE character varying(20); +-- Create "DevicePackage" table +CREATE TABLE "public"."DevicePackage" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NOT NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_DevicePackage_Code" UNIQUE ("Code") +); +-- Create "DevicePackageItem" table +CREATE TABLE "public"."DevicePackageItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "DevicePackage_Code" character varying(20) NOT NULL, + "Device_Code" character varying(20) NOT NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_DevicePackageItem_Device" FOREIGN KEY ("Device_Code") REFERENCES "public"."Device" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_DevicePackageItem_DevicePackage" FOREIGN KEY ("DevicePackage_Code") REFERENCES "public"."DevicePackage" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "MaterialPackage" table +CREATE TABLE "public"."MaterialPackage" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NOT NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_MaterialPackage_Code" UNIQUE ("Code") +); +-- Create "MaterialPackageItem" table +CREATE TABLE "public"."MaterialPackageItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "MaterialPackage_Code" character varying(20) NOT NULL, + "Material_Code" character varying(20) NOT NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_MaterialPackageItem_Material" FOREIGN KEY ("Material_Code") REFERENCES "public"."Material" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_MaterialPackageItem_MaterialPackage" FOREIGN KEY ("MaterialPackage_Code") REFERENCES "public"."MaterialPackage" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Modify "Infra" table +ALTER TABLE "public"."Infra" ALTER COLUMN "Code" TYPE character varying(20), ALTER COLUMN "InfraGroup_Code" TYPE character varying(20), ALTER COLUMN "Parent_Code" TYPE character varying(20); +-- Modify "Specialist" table +ALTER TABLE "public"."Specialist" ALTER COLUMN "Code" TYPE character varying(20), ALTER COLUMN "Unit_Code" TYPE character varying(20); +-- Modify "Subspecialist" table +ALTER TABLE "public"."Subspecialist" ALTER COLUMN "Code" TYPE character varying(20), ALTER COLUMN "Specialist_Code" TYPE character varying(20); +-- Modify "Unit" table +ALTER TABLE "public"."Unit" ALTER COLUMN "Code" TYPE character varying(20), ALTER COLUMN "Installation_Code" TYPE character varying(20); +-- Create "ProcedureRoom" table +CREATE TABLE "public"."ProcedureRoom" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(20) NULL, + "Infra_Code" character varying(20) NULL, + "Type_Code" character varying(10) NULL, + "Unit_Code" character varying(20) NULL, + "Specialist_Code" character varying(20) NULL, + "Subspecialist_Code" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_ProcedureRoom_Code" UNIQUE ("Code"), + CONSTRAINT "uni_ProcedureRoom_Infra_Code" UNIQUE ("Infra_Code"), + CONSTRAINT "fk_ProcedureRoom_Infra" FOREIGN KEY ("Infra_Code") REFERENCES "public"."Infra" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_ProcedureRoom_Specialist" FOREIGN KEY ("Specialist_Code") REFERENCES "public"."Specialist" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_ProcedureRoom_Subspecialist" FOREIGN KEY ("Subspecialist_Code") REFERENCES "public"."Subspecialist" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_ProcedureRoom_Unit" FOREIGN KEY ("Unit_Code") REFERENCES "public"."Unit" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "ProcedureRoomOrder" table +CREATE TABLE "public"."ProcedureRoomOrder" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Infra_Code" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_ProcedureRoomOrder_ProcedureRoom" FOREIGN KEY ("Infra_Code") REFERENCES "public"."ProcedureRoom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Drop "Room" table +DROP TABLE "public"."Room"; diff --git a/cmd/main-migration/migrations/20251202160848.sql b/cmd/main-migration/migrations/20251202160848.sql new file mode 100644 index 00000000..8d77fe04 --- /dev/null +++ b/cmd/main-migration/migrations/20251202160848.sql @@ -0,0 +1,2 @@ +-- Modify "ProcedureRoomOrder" table +ALTER TABLE "public"."ProcedureRoomOrder" ADD COLUMN "MaterialPackage_Code" character varying(20) NULL, ADD CONSTRAINT "fk_ProcedureRoomOrder_MaterialPackage" FOREIGN KEY ("MaterialPackage_Code") REFERENCES "public"."MaterialPackage" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251202180207.sql b/cmd/main-migration/migrations/20251202180207.sql new file mode 100644 index 00000000..32c5b1dc --- /dev/null +++ b/cmd/main-migration/migrations/20251202180207.sql @@ -0,0 +1,2 @@ +-- Modify "ProcedureRoomOrder" table +ALTER TABLE "public"."ProcedureRoomOrder" ADD COLUMN "Status_Code" character varying(20) NULL; diff --git a/cmd/main-migration/migrations/20251202231005.sql b/cmd/main-migration/migrations/20251202231005.sql new file mode 100644 index 00000000..65fe436a --- /dev/null +++ b/cmd/main-migration/migrations/20251202231005.sql @@ -0,0 +1,14 @@ +-- Modify "MaterialPackageItem" table +ALTER TABLE "public"."MaterialPackageItem" ADD COLUMN "Count" integer NULL; +-- Create "ProcedureRoomOrderItem" table +CREATE TABLE "public"."ProcedureRoomOrderItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "ProcedureRoomOrder_Id" bigint NULL, + "ProcedureRoom_Code" character varying(20) NULL, + "Note" character varying(255) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_ProcedureRoomOrderItem_ProcedureRoom" FOREIGN KEY ("ProcedureRoom_Code") REFERENCES "public"."ProcedureRoom" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/20251203205052.sql b/cmd/main-migration/migrations/20251203205052.sql new file mode 100644 index 00000000..831497a2 --- /dev/null +++ b/cmd/main-migration/migrations/20251203205052.sql @@ -0,0 +1,4 @@ +-- Modify "ProcedureRoomOrder" table +ALTER TABLE "public"."ProcedureRoomOrder" DROP COLUMN "Infra_Code"; +-- Modify "ProcedureRoomOrderItem" table +ALTER TABLE "public"."ProcedureRoomOrderItem" ADD CONSTRAINT "fk_ProcedureRoomOrderItem_ProcedureRoomOrder" FOREIGN KEY ("ProcedureRoomOrder_Id") REFERENCES "public"."ProcedureRoomOrder" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251205073858.sql b/cmd/main-migration/migrations/20251205073858.sql new file mode 100644 index 00000000..96f9200a --- /dev/null +++ b/cmd/main-migration/migrations/20251205073858.sql @@ -0,0 +1,23 @@ +-- Modify "Chemo" table +ALTER TABLE "public"."Chemo" ADD COLUMN "Doctor_Code" character varying(20) NULL, ADD COLUMN "NextChemoDate" timestamptz NULL, ADD CONSTRAINT "fk_Chemo_Doctor" FOREIGN KEY ("Doctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION; +-- Rename a column from "Encounter_Id" to "Chemo_Id" +ALTER TABLE "public"."ChemoProtocol" RENAME COLUMN "Encounter_Id" TO "Chemo_Id"; +-- Modify "ChemoProtocol" table +ALTER TABLE "public"."ChemoProtocol" DROP CONSTRAINT "fk_ChemoProtocol_Encounter", ALTER COLUMN "DurationUnit_Code" TYPE text, ADD COLUMN "Interval" bigint NULL, ADD COLUMN "Cycle" bigint NULL, ADD COLUMN "Series" integer NULL, ADD COLUMN "Status_Code" text NULL, ADD CONSTRAINT "fk_ChemoProtocol_Chemo" FOREIGN KEY ("Chemo_Id") REFERENCES "public"."Chemo" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; +-- Create "ChemoPlan" table +CREATE TABLE "public"."ChemoPlan" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Parent_Id" bigint NULL, + "Protocol_Id" bigint NULL, + "SeriesNumber" integer NULL, + "CycleNumber" bigint NULL, + "PlanDate" timestamptz NULL, + "RealizationDate" timestamptz NULL, + "Notes" text NULL, + "Status" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_ChemoPlan_Protocol" FOREIGN KEY ("Protocol_Id") REFERENCES "public"."ChemoProtocol" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/20251205211957.sql b/cmd/main-migration/migrations/20251205211957.sql new file mode 100644 index 00000000..99677edd --- /dev/null +++ b/cmd/main-migration/migrations/20251205211957.sql @@ -0,0 +1,2 @@ +-- Modify "ChemoPlan" table +ALTER TABLE "public"."ChemoPlan" DROP CONSTRAINT "fk_ChemoPlan_Protocol", ADD CONSTRAINT "fk_ChemoProtocol_ChemoPlans" FOREIGN KEY ("Protocol_Id") REFERENCES "public"."ChemoProtocol" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251205214433.sql b/cmd/main-migration/migrations/20251205214433.sql new file mode 100644 index 00000000..34343308 --- /dev/null +++ b/cmd/main-migration/migrations/20251205214433.sql @@ -0,0 +1,2 @@ +-- Modify "ChemoProtocol" table +ALTER TABLE "public"."ChemoProtocol" ADD COLUMN "Patient_Id" bigint NULL; diff --git a/cmd/main-migration/migrations/20251205221124.sql b/cmd/main-migration/migrations/20251205221124.sql new file mode 100644 index 00000000..3eab115a --- /dev/null +++ b/cmd/main-migration/migrations/20251205221124.sql @@ -0,0 +1,2 @@ +-- Modify "ChemoProtocol" table +ALTER TABLE "public"."ChemoProtocol" ADD COLUMN "VerifiedAt" timestamptz NULL, ADD COLUMN "VerifiedBy_User_Id" bigint NULL, ADD CONSTRAINT "fk_ChemoProtocol_VerifiedBy" FOREIGN KEY ("VerifiedBy_User_Id") REFERENCES "public"."User" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251206021053.sql b/cmd/main-migration/migrations/20251206021053.sql new file mode 100644 index 00000000..03ab3bfb --- /dev/null +++ b/cmd/main-migration/migrations/20251206021053.sql @@ -0,0 +1,26 @@ +-- Create "ProcedureReport" table +CREATE TABLE "public"."ProcedureReport" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Date" timestamptz NOT NULL, + "Doctor_Code" character varying(10) NULL, + "Operator_Name" text NULL, + "Assistant_Name" text NULL, + "Instrumentor_Name" text NULL, + "Diagnose" character varying(1024) NULL, + "Nurse_Name" character varying(10) NULL, + "Anesthesia_Doctor_Code" character varying(10) NULL, + "Anesthesia_Nurse_Name" text NULL, + "ProcedureValue" text NULL, + "ExecutionValue" text NULL, + "Type_Code" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_ProcedureReport_Anesthesia_Doctor" FOREIGN KEY ("Anesthesia_Doctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_ProcedureReport_Doctor" FOREIGN KEY ("Doctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_ProcedureReport_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Drop "ActionReport" table +DROP TABLE "public"."ActionReport"; diff --git a/cmd/main-migration/migrations/20251207020537.sql b/cmd/main-migration/migrations/20251207020537.sql new file mode 100644 index 00000000..14142cb0 --- /dev/null +++ b/cmd/main-migration/migrations/20251207020537.sql @@ -0,0 +1,22 @@ +-- Create "ApMcuOrder" table +CREATE TABLE "public"."ApMcuOrder" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "McuOrder_Id" smallint NULL, + "Substances" text NULL, + "Fictations" text NULL, + "Localization" text NULL, + "ClinicalDiagnoses" text NULL, + "Stadium" text NULL, + "ClinicalNotes" text NULL, + "PastHistory" text NULL, + "CurrentHistory" text NULL, + "PrevApMcu" text NULL, + "PrevApMcuNotes" text NULL, + "SupportingExams" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_ApMcuOrder_McuOrder_Id" UNIQUE ("McuOrder_Id"), + CONSTRAINT "fk_ApMcuOrder_McuOrder" FOREIGN KEY ("McuOrder_Id") REFERENCES "public"."McuOrder" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/20251207212015.sql b/cmd/main-migration/migrations/20251207212015.sql new file mode 100644 index 00000000..c551aa8c --- /dev/null +++ b/cmd/main-migration/migrations/20251207212015.sql @@ -0,0 +1,99 @@ +-- Modify "ApMcuOrder" table +ALTER TABLE "public"."ApMcuOrder" DROP COLUMN "McuOrder_Id", ADD COLUMN "Encounter_Id" bigint NULL, ADD COLUMN "Number" bigint NULL, ADD COLUMN "Doctor_Code" character varying(20) NULL, ADD CONSTRAINT "uni_ApMcuOrder_Doctor_Code" UNIQUE ("Doctor_Code"), ADD CONSTRAINT "fk_ApMcuOrder_Doctor" FOREIGN KEY ("Doctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, ADD CONSTRAINT "fk_ApMcuOrder_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; +-- Create "CpMcuOrder" table +CREATE TABLE "public"."CpMcuOrder" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Number" bigint NULL, + "Doctor_Code" character varying(20) NULL, + "UrgencyLevel_Code" character varying(15) NOT NULL, + "OtherNotes" text NULL, + "ExamScheduleDate" timestamptz NULL, + "Resume" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_CpMcuOrder_Doctor_Code" UNIQUE ("Doctor_Code"), + CONSTRAINT "fk_CpMcuOrder_Doctor" FOREIGN KEY ("Doctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_CpMcuOrder_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "CpMcuOrderItem" table +CREATE TABLE "public"."CpMcuOrderItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "CpMcuOrder_Id" bigint NULL, + "McuSrc_Code" character varying(20) NULL, + "Note" character varying(1024) NULL, + "Result" text NULL, + "Status_Code" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_CpMcuOrderItem_CpMcuOrder" FOREIGN KEY ("CpMcuOrder_Id") REFERENCES "public"."CpMcuOrder" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_CpMcuOrderItem_McuSrc" FOREIGN KEY ("McuSrc_Code") REFERENCES "public"."McuSrc" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "MicroMcuOrder" table +CREATE TABLE "public"."MicroMcuOrder" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Number" bigint NULL, + "Doctor_Code" character varying(20) NULL, + "Stage_Code" character varying(10) NOT NULL, + "AxillaryTemp" numeric NULL, + "OtherNotes" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_MicroMcuOrder_Doctor_Code" UNIQUE ("Doctor_Code"), + CONSTRAINT "fk_MicroMcuOrder_Doctor" FOREIGN KEY ("Doctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_MicroMcuOrder_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "MicroMcuOrderItem" table +CREATE TABLE "public"."MicroMcuOrderItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "MicroMcuOrder_Id" bigint NULL, + "McuSrc_Code" character varying(20) NULL, + "Note" character varying(1024) NULL, + "Result" text NULL, + "Status_Code" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_MicroMcuOrderItem_McuSrc" FOREIGN KEY ("McuSrc_Code") REFERENCES "public"."McuSrc" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_MicroMcuOrderItem_MicroMcuOrder" FOREIGN KEY ("MicroMcuOrder_Id") REFERENCES "public"."MicroMcuOrder" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "RadiologyMcuOrder" table +CREATE TABLE "public"."RadiologyMcuOrder" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Encounter_Id" bigint NULL, + "Number" bigint NULL, + "Doctor_Code" character varying(20) NULL, + "ClinicalNotes" text NULL, + "OtherNotes" text NULL, + "Resume" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_RadiologyMcuOrder_Doctor_Code" UNIQUE ("Doctor_Code"), + CONSTRAINT "fk_RadiologyMcuOrder_Doctor" FOREIGN KEY ("Doctor_Code") REFERENCES "public"."Doctor" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_RadiologyMcuOrder_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Create "RadiologyMcuOrderItem" table +CREATE TABLE "public"."RadiologyMcuOrderItem" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "RadiologyMcuOrder_Id" bigint NULL, + "McuSrc_Code" character varying(20) NULL, + "Note" character varying(1024) NULL, + "Result" text NULL, + "Status_Code" text NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_RadiologyMcuOrderItem_McuSrc" FOREIGN KEY ("McuSrc_Code") REFERENCES "public"."McuSrc" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_RadiologyMcuOrderItem_RadiologyMcuOrder" FOREIGN KEY ("RadiologyMcuOrder_Id") REFERENCES "public"."RadiologyMcuOrder" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/20251207221222.sql b/cmd/main-migration/migrations/20251207221222.sql new file mode 100644 index 00000000..3c806128 --- /dev/null +++ b/cmd/main-migration/migrations/20251207221222.sql @@ -0,0 +1,8 @@ +-- Modify "ApMcuOrder" table +ALTER TABLE "public"."ApMcuOrder" ADD COLUMN "Status_Code" character varying(10) NOT NULL; +-- Modify "CpMcuOrder" table +ALTER TABLE "public"."CpMcuOrder" ADD COLUMN "Status_Code" character varying(10) NOT NULL; +-- Modify "MicroMcuOrder" table +ALTER TABLE "public"."MicroMcuOrder" ADD COLUMN "Status_Code" character varying(10) NOT NULL; +-- Modify "RadiologyMcuOrder" table +ALTER TABLE "public"."RadiologyMcuOrder" ADD COLUMN "Status_Code" character varying(10) NOT NULL; diff --git a/cmd/main-migration/migrations/20251209022744.sql b/cmd/main-migration/migrations/20251209022744.sql new file mode 100644 index 00000000..a8a18481 --- /dev/null +++ b/cmd/main-migration/migrations/20251209022744.sql @@ -0,0 +1,2 @@ +-- Modify "ChemoPlan" table +ALTER TABLE "public"."ChemoPlan" ADD COLUMN "Encounter_Id" bigint NULL, ADD CONSTRAINT "fk_ChemoPlan_Encounter" FOREIGN KEY ("Encounter_Id") REFERENCES "public"."Encounter" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION; diff --git a/cmd/main-migration/migrations/20251209025908.sql b/cmd/main-migration/migrations/20251209025908.sql new file mode 100644 index 00000000..5a8522d7 --- /dev/null +++ b/cmd/main-migration/migrations/20251209025908.sql @@ -0,0 +1,2 @@ +-- Modify "Chemo" table +ALTER TABLE "public"."Chemo" ADD COLUMN "Class_Code" text NULL; diff --git a/cmd/main-migration/migrations/20251209030538.sql b/cmd/main-migration/migrations/20251209030538.sql new file mode 100644 index 00000000..4f0ad77f --- /dev/null +++ b/cmd/main-migration/migrations/20251209030538.sql @@ -0,0 +1,2 @@ +-- Modify "ProcedureReport" table +ALTER TABLE "public"."ProcedureReport" ALTER COLUMN "Nurse_Name" TYPE text; diff --git a/cmd/main-migration/migrations/20251209064304.sql b/cmd/main-migration/migrations/20251209064304.sql new file mode 100644 index 00000000..fc289e20 --- /dev/null +++ b/cmd/main-migration/migrations/20251209064304.sql @@ -0,0 +1,12 @@ +-- Create "Registration" table +CREATE TABLE "public"."Registration" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "Installation_Code" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Registration_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Registration_Installation" FOREIGN KEY ("Installation_Code") REFERENCES "public"."Installation" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/main-migration/migrations/20251209070128.sql b/cmd/main-migration/migrations/20251209070128.sql new file mode 100644 index 00000000..fb0caac3 --- /dev/null +++ b/cmd/main-migration/migrations/20251209070128.sql @@ -0,0 +1,2 @@ +-- Modify "Person" table +ALTER TABLE "public"."Person" ADD COLUMN "BirthPlace" text NULL; diff --git a/cmd/main-migration/migrations/20251209084929.sql b/cmd/main-migration/migrations/20251209084929.sql new file mode 100644 index 00000000..c67550ae --- /dev/null +++ b/cmd/main-migration/migrations/20251209084929.sql @@ -0,0 +1,14 @@ +-- Create "Registrator" table +CREATE TABLE "public"."Registrator" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Employee_Id" bigint NULL, + "Installation_Code" character varying(20) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Registrator_Employee" FOREIGN KEY ("Employee_Id") REFERENCES "public"."Employee" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT "fk_Registrator_Installation" FOREIGN KEY ("Installation_Code") REFERENCES "public"."Installation" ("Code") ON UPDATE NO ACTION ON DELETE NO ACTION +); +-- Drop "Registration" table +DROP TABLE "public"."Registration"; diff --git a/cmd/main-migration/migrations/atlas.sum b/cmd/main-migration/migrations/atlas.sum index f59b4131..9c137d56 100644 --- a/cmd/main-migration/migrations/atlas.sum +++ b/cmd/main-migration/migrations/atlas.sum @@ -1,5 +1,4 @@ -h1:3V3a/T/te8iQqsolgRAJKr99GePHgSN9miJHUNngJ74= -h1:IAvX8SEd9TnVqJ7EYac7IGQ2CGS+5RhltXZ10G5+w7s= +h1:B/ZKq0d90aqLf0EvQfND4cd8ZRHcmxfzKF2N1lpSeIs= 20250904105930.sql h1:MEM6blCgke9DzWQSTnLzasbPIrcHssNNrJqZpSkEo6k= 20250904141448.sql h1:J8cmYNk4ZrG9fhfbi2Z1IWz7YkfvhFqTzrLFo58BPY0= 20250908062237.sql h1:Pu23yEW/aKkwozHoOuROvHS/GK4ngARJGdO7FB7HZuI= @@ -109,9 +108,54 @@ h1:IAvX8SEd9TnVqJ7EYac7IGQ2CGS+5RhltXZ10G5+w7s= 20251110093522.sql h1:nsz8jCxGjEdr/bz9g+4ozfZzIP803xONjVmucad1GMc= 20251110100258.sql h1:IBqt1VZj5WjQ+l9aAFGHOCCBtzb03KlLLihFLut7itg= 20251110100545.sql h1:6/LV7751iyKxE2xI6vO1zly+aHUwxXD/IBwLcVpKxqM= -20251111072601.sql h1:dEhwrkT0hJ06/YcvQd5alvdskimcHcYT27QKAzVY5+8= -20251111073546.sql h1:JnJZ4SdOObSe6Jf8v/i/KiRxoCz5KMeXCYytQMZgkZM= -20251111074148.sql h1:95Ui1eo1P68itOz5kZDNFi2ha0ZhUF4gMYiYVcip6fo= -20251111074652.sql h1:vUZbN0qgktRQ2GAlCpdYrbld2grPiSbvcMePEQMfxPs= -20251111082257.sql h1:Zr3Xg5n+p4C8F6Evqm5PVC0pqUvPTBcq692PiUEJlT8= -20251111111017.sql h1:8Kr6FFtkSeaenB/n/aKlOaz/K33SqazxMuH26oI0JI4= +20251110155448.sql h1:kFPobJB+cpflsXBAWUwy3lohuWvrb/VRlXnhJWl7i3Y= +20251111072601.sql h1:ch8F+yVhsSM5xY+TwMLY3PxdLa4Wuhtj76oyw79R7Js= +20251111073546.sql h1:cCv0NPscADAOBahRVqtDWFs6G2t7n+4a+RwlF8vk/c4= +20251111074148.sql h1:70TsV83u1gQ5TktI13K7NQiyCCa35Td2aR6CNtKUa4U= +20251111074652.sql h1:ddfQ/sRKMezPM75xBFTGytUQX5AwZ3znrJVpg73gKPA= +20251111082257.sql h1:ZsdLY1ROouos0l3oS0lkeSiuKLEUGbVvBhpcM2AVhkw= +20251111111017.sql h1:qrJ93dNtQwcuAvpsP/lAK/H63C4cinXrsVaPmWsTqkU= +20251113101344.sql h1:xaOZvAUP1fFfnO+syEFOzJUIg5lTfBe5AWHPbBWuCLA= +20251113120533.sql h1:f3/U1Ve2yF2zSMhkt+xtwF8wUYfUKYwgbNeGfE37EW4= +20251114062746.sql h1:FInLaEFQByESEwFJKuKnuUSTKmcDpi3ZXaxkKwz2+D8= +20251117005942.sql h1:wD3BWrUSmo1HlW16V3lkaBkJvbAZ0fNk77te7J9NhOc= +20251117075427.sql h1:TqU9VKZa3I8YNXUGQWY3WVBYN+1FvyyaKy0hB1jgAho= +20251118074929.sql h1:p1KsWqCuR1JXA/jVO5BmOhCcaQ8clT7t0YRszAhPFbg= +20251119063438.sql h1:NVGM0X/LHD37EaPl8SNzkNiZDJ7AB1QR+LLwLh6WRdg= +20251119065730.sql h1:U5lzk1WvMB0bw3kwckou7jkEt4bwdYItwHr2Vxqe7w4= +20251119072302.sql h1:qCuI2WMEMF/XNbjV+RXPjBnuCKLu1Fia+mR9HiLWBIs= +20251119072450.sql h1:Xg+bTwqGyKPNFEQhJylvpz1wifdfmDJvcAq6vmNf0Ng= +20251120005512.sql h1:Ek6qpacAI/qVuTYxKno+uJyzn7s5z9pf3t7VA8gTzm4= +20251120074415.sql h1:NNUeJVA03EeBHJhHqPXEZoDv/PnC6yK1/cRhmukyaJo= +20251121033803.sql h1:/vfvFX/3pzSCIHnSbMUT9EMBDykOpVkvyfeTEle9Vas= +20251124071457.sql h1:qg2dhCL9YwD13xnfJ175lW/p6MGfzFKaBqd908FByRc= +20251125125303.sql h1:4JSFv1Pmhbe9tqpLXgO63OwYnGsalStgUXKVWPyc1YE= +20251126064057.sql h1:vAdhz5Nn/gGJy0UKZAEldeXv8HpHtJU/t8ygDVIbTsU= +20251201081333.sql h1:PoC8ADRdwDuohDTB74yW/DaB42igdYa4B6humbrEJBk= +20251201104439.sql h1:tpqdrOf9d2aGwZshqm62nG6SXnfVaO/g6A7z0efPS14= +20251201113804.sql h1:kIEmVoETJXBkab2Q+b3y/pP84eF8W2BdQ47amHCnc+c= +20251201113858.sql h1:KLXKZO5XTQPoEU0YLHE8Fhg9WPKpSN3wNgYPJ+RGFcg= +20251201114751.sql h1:HM17diiPknfSHAmP+kJGP6GzToaPU9/NT+KQBpf3Jq0= +20251201114913.sql h1:gqucFgHFFLA6n/Rdz486cZH5xkaJuwefESLJMJLDue8= +20251202030445.sql h1:QWBVfTepT7DaXP5E0BYoxNM0JwKIQ2qIMXzI4kbz/qE= +20251202044430.sql h1:4QZH9lz0GrQ9rzP1AJ+hJgGalNpp+8FCRckNK7xaTbU= +20251202064000.sql h1:/EN7sT1ol/91qW1aXWrzX+Mc3XOC/7f/LtfA0JRHpbg= +20251202130629.sql h1:9mvalqfhqGCdkcJepJDzHprU2xb0i5sYys1Htf62ioo= +20251202160848.sql h1:Kd2/TziKSMezrt4XgbjQcYvY/Lo9rX0qw7/Lz0/oyKk= +20251202180207.sql h1:IHmSMIO3ia+YV5GULixbdlV1joaUAWtnjQHPd8+HKiM= +20251202231005.sql h1:lua0KKoeBptSfs/6ehZE6Azo6YUlNkOJwGFyb1HQWkY= +20251203205052.sql h1:nk0VK2Uv4bHE3SBfHo/aevVZxtHzr7zAzvmMU8TCCtk= +20251205073858.sql h1:46qqXnArgJmzGE/WO7v7Ev8Jh7BudDiGbdANexq/5Dk= +20251205211957.sql h1:3fvtZ/mBWsTIXllXMFOuCLJsp4MivVP56dunehlU0yo= +20251205214433.sql h1:rn3++FEfX7ntcJcOmCEuOMnr27TZqH0KMGRppzFwFTc= +20251205221124.sql h1:CRruUvGZqlVDBmbQSVEl4wFm+uq30AurMMDI6sb8jxg= +20251206021053.sql h1:bpuEocu4lOhZ7oLuxd//22dzjfNgU2iaWEqSD1mVwoU= +20251207020537.sql h1:m6uh4NHVF3EKNTVMqOmuBSDFD9oCQk5mAwo05fT46G4= +20251207212015.sql h1:UPelYGTeUR6rm8mU8dfNzgRDEDun0UQ4tkgsaDljn30= +20251207221222.sql h1:bTfUCvCf2UPh+BA2IY2PHQafb9DwY9nhH5FRuMEHy+0= +20251209022744.sql h1:y5/PAiZH/fYCpDJpkQdNRJwWICHH2iNIwM1V+S1P6KA= +20251209025908.sql h1:p3kZA8kyEj+mQZSrdY3k2K1NojQzFJh/MlZJ0Oy6t/k= +20251209030538.sql h1:zltV6/Fu2zJW0/lVBl7MdnWuJcqNTUIRcqYYZ8Fi1wo= +20251209064304.sql h1:Mj6Zh+2b/4AkM1HjnJGjAs788kVN0UaL34jeaKQIjT0= +20251209070128.sql h1:ip4wNCIF/UFQlNo6KpFG87/XA08aG3/Rf5zpxz3xioY= +20251209084929.sql h1:Z5higP1Ecq5UPWhrWZ5UCrxddMNqiJi8PbCNvGBE48A= diff --git a/cmd/main-sync-api/config.yml-example b/cmd/main-sync-api/config.yml-example deleted file mode 100644 index edb5c84b..00000000 --- a/cmd/main-sync-api/config.yml-example +++ /dev/null @@ -1,41 +0,0 @@ -appCfg: - fullName: SIMRS Sync - codeName: simrs-sync - version: 0.1.0 - env: development - lang: en - -dbCfg: - dsn: - maxOpenConns: 5 - maxIdleConns: 5 - maxIdleTime: 100 - -multiDbCfg: - dbs : - - name: simrs_sync - dsn: - maxOpenConns: 5 - maxIdleConns: 5 - maxIdleTime: 100 - -httpCfg: - host: 127.0.0.1 - port: 8003 - -loggerCfg: - hideTime: true - hideLevel: true - -langCfg: - active: en - path: ../../assets/language/en - fileName: data.json - -corsCfg: - allowedOrigin: - allowedMethod: GET, POST, PUT, PATCH, DELETE, OPTIONS - -syncUrlCfg: - target: - host: \ No newline at end of file diff --git a/cmd/main-sync-api/main.go b/cmd/main-sync-api/main.go deleted file mode 100644 index 5bfdd36b..00000000 --- a/cmd/main-sync-api/main.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - a "github.com/karincake/apem" - - h "simrs-vx/internal/interface/main-sync-handler" - - d "github.com/karincake/apem/db-gorm-pg" - - l "github.com/karincake/apem/logger-zerolog" -) - -func main() { - a.Run(h.SetRoutes(), &l.O, &d.O) -} diff --git a/cmd/simgos-sync-api/config.yml-example b/cmd/simgos-sync-api/config.yml-example index 153be50e..96e4a6d2 100644 --- a/cmd/simgos-sync-api/config.yml-example +++ b/cmd/simgos-sync-api/config.yml-example @@ -36,6 +36,10 @@ corsCfg: allowedOrigin: allowedMethod: GET, POST, PUT, PATCH, DELETE, OPTIONS -syncUrlCfg: - target: - host: \ No newline at end of file +syncPartnerCfg: + oldSource + oldSecretKey + oldHost + newSource + newSecretKey + newHost \ No newline at end of file diff --git a/cmd/simgos-sync-migration/Makefile b/cmd/simgos-sync-migration/Makefile new file mode 100644 index 00000000..e83356e5 --- /dev/null +++ b/cmd/simgos-sync-migration/Makefile @@ -0,0 +1,18 @@ +# Makefile for Atlas migrations + +# Default environment +ENV ?= gorm + +.PHONY: diff apply hash + +## Generate a new migration diff +diff: + atlas migrate diff --env $(ENV) + +## Apply migrations to the database +apply: + atlas migrate apply --env $(ENV) + +## Calculate the schema hash +hash: + atlas migrate hash diff --git a/cmd/simgos-sync-migration/README-ATLAS.MD b/cmd/simgos-sync-migration/README-ATLAS.MD new file mode 100644 index 00000000..da249823 --- /dev/null +++ b/cmd/simgos-sync-migration/README-ATLAS.MD @@ -0,0 +1,59 @@ +# Database Migration with Atlas + +This project uses [Atlas](https://atlasgo.io/) for database schema management and migrations. + +## 📋 Prerequisites + +1. **Download and Install Atlas CLI** + Run the following command in PowerShell or Git Bash: + + ```sh + curl -sSf https://atlasgo.sh | sh + ``` + Verify installation: + + ```sh + atlas version + ``` + +2. Install GORM Provider + Run inside your Go project: + + ```sh + go get -u ariga.io/atlas-provider-gorm + ``` + +3. Create atlas.hcl configuration file + Just create an atlas.hcl file in your project root as example given at atlas.hcl.example +4. Create migrations folder + ```sh + mkdir migrations + ``` +5. Usage +You can use the provided Makefile for common commands: + + Generate a migration diff + ```sh + make diff + ``` + + Apply migrations + ```sh + make apply + ``` + + Compute schema hash + ```sh + make hash + ``` + + If you don’t have make installed, you can run the Atlas commands directly: + ```sh + atlas migrate diff --env gorm + ``` + ```sh + atlas migrate apply --env gorm + ``` + ```sh + atlas migrate hash + ``` \ No newline at end of file diff --git a/cmd/simgos-sync-migration/atlas.hcl.example b/cmd/simgos-sync-migration/atlas.hcl.example new file mode 100644 index 00000000..857d1352 --- /dev/null +++ b/cmd/simgos-sync-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/cmd/simgos-sync-migration/migration.go b/cmd/simgos-sync-migration/migration.go new file mode 100644 index 00000000..fdd2c995 --- /dev/null +++ b/cmd/simgos-sync-migration/migration.go @@ -0,0 +1,9 @@ +package main + +import ( + m "simrs-vx/internal/interface/migration" +) + +func main() { + m.Migrate(m.SimgosSync) +} diff --git a/cmd/simgos-sync-migration/migrations/20251113035508.sql b/cmd/simgos-sync-migration/migrations/20251113035508.sql new file mode 100644 index 00000000..5dddf417 --- /dev/null +++ b/cmd/simgos-sync-migration/migrations/20251113035508.sql @@ -0,0 +1,36 @@ +-- Create "InstallationLink" table +CREATE TABLE "public"."InstallationLink" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Simx_Id" bigint NULL, + "Simgos_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_InstallationLink_Simgos_Id" UNIQUE ("Simgos_Id"), + CONSTRAINT "uni_InstallationLink_Simx_Id" UNIQUE ("Simx_Id") +); +-- Create "InstallationSimgosLog" table +CREATE TABLE "public"."InstallationSimgosLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "InstallationSimxLog" table +CREATE TABLE "public"."InstallationSimxLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/simgos-sync-migration/migrations/20251114071129.sql b/cmd/simgos-sync-migration/migrations/20251114071129.sql new file mode 100644 index 00000000..4499a544 --- /dev/null +++ b/cmd/simgos-sync-migration/migrations/20251114071129.sql @@ -0,0 +1,36 @@ +-- Create "UnitLink" table +CREATE TABLE "public"."UnitLink" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Simx_Id" bigint NULL, + "Simgos_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_UnitLink_Simgos_Id" UNIQUE ("Simgos_Id"), + CONSTRAINT "uni_UnitLink_Simx_Id" UNIQUE ("Simx_Id") +); +-- Create "UnitSimgosLog" table +CREATE TABLE "public"."UnitSimgosLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "UnitSimxLog" table +CREATE TABLE "public"."UnitSimxLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/simgos-sync-migration/migrations/20251117041601.sql b/cmd/simgos-sync-migration/migrations/20251117041601.sql new file mode 100644 index 00000000..7c33b155 --- /dev/null +++ b/cmd/simgos-sync-migration/migrations/20251117041601.sql @@ -0,0 +1,108 @@ +-- Create "DivisionLink" table +CREATE TABLE "public"."DivisionLink" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Simx_Id" bigint NULL, + "Simgos_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_DivisionLink_Simgos_Id" UNIQUE ("Simgos_Id"), + CONSTRAINT "uni_DivisionLink_Simx_Id" UNIQUE ("Simx_Id") +); +-- Create "DivisionSimgosLog" table +CREATE TABLE "public"."DivisionSimgosLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "DivisionSimxLog" table +CREATE TABLE "public"."DivisionSimxLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "SpecialistLink" table +CREATE TABLE "public"."SpecialistLink" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Simx_Id" bigint NULL, + "Simgos_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_SpecialistLink_Simgos_Id" UNIQUE ("Simgos_Id"), + CONSTRAINT "uni_SpecialistLink_Simx_Id" UNIQUE ("Simx_Id") +); +-- Create "SpecialistSimgosLog" table +CREATE TABLE "public"."SpecialistSimgosLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "SpecialistSimxLog" table +CREATE TABLE "public"."SpecialistSimxLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "SubspecialistLink" table +CREATE TABLE "public"."SubspecialistLink" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Simx_Id" bigint NULL, + "Simgos_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_SubspecialistLink_Simgos_Id" UNIQUE ("Simgos_Id"), + CONSTRAINT "uni_SubspecialistLink_Simx_Id" UNIQUE ("Simx_Id") +); +-- Create "SubspecialistSimgosLog" table +CREATE TABLE "public"."SubspecialistSimgosLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "SubspecialistSimxLog" table +CREATE TABLE "public"."SubspecialistSimxLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/simgos-sync-migration/migrations/20251118082246.sql b/cmd/simgos-sync-migration/migrations/20251118082246.sql new file mode 100644 index 00000000..f5d9dbf5 --- /dev/null +++ b/cmd/simgos-sync-migration/migrations/20251118082246.sql @@ -0,0 +1,36 @@ +-- Create "PatientLink" table +CREATE TABLE "public"."PatientLink" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Simx_Id" bigint NULL, + "Simgos_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_PatientLink_Simgos_Id" UNIQUE ("Simgos_Id"), + CONSTRAINT "uni_PatientLink_Simx_Id" UNIQUE ("Simx_Id") +); +-- Create "PatientSimgosLog" table +CREATE TABLE "public"."PatientSimgosLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "PatientSimxLog" table +CREATE TABLE "public"."PatientSimxLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/simgos-sync-migration/migrations/20251118082915.sql b/cmd/simgos-sync-migration/migrations/20251118082915.sql new file mode 100644 index 00000000..90b41344 --- /dev/null +++ b/cmd/simgos-sync-migration/migrations/20251118082915.sql @@ -0,0 +1,36 @@ +-- Create "EncounterLink" table +CREATE TABLE "public"."EncounterLink" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Simx_Id" bigint NULL, + "Simgos_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_EncounterLink_Simgos_Id" UNIQUE ("Simgos_Id"), + CONSTRAINT "uni_EncounterLink_Simx_Id" UNIQUE ("Simx_Id") +); +-- Create "EncounterSimgosLog" table +CREATE TABLE "public"."EncounterSimgosLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "EncounterSimxLog" table +CREATE TABLE "public"."EncounterSimxLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/simgos-sync-migration/migrations/20251126115527.sql b/cmd/simgos-sync-migration/migrations/20251126115527.sql new file mode 100644 index 00000000..49ca1e5c --- /dev/null +++ b/cmd/simgos-sync-migration/migrations/20251126115527.sql @@ -0,0 +1,36 @@ +-- Create "InternalReferenceLink" table +CREATE TABLE "public"."InternalReferenceLink" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Simx_Id" bigint NULL, + "Simgos_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_InternalReferenceLink_Simgos_Id" UNIQUE ("Simgos_Id"), + CONSTRAINT "uni_InternalReferenceLink_Simx_Id" UNIQUE ("Simx_Id") +); +-- Create "InternalReferenceSimgosLog" table +CREATE TABLE "public"."InternalReferenceSimgosLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "InternalReferenceSimxLog" table +CREATE TABLE "public"."InternalReferenceSimxLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/simgos-sync-migration/migrations/20251201093443.sql b/cmd/simgos-sync-migration/migrations/20251201093443.sql new file mode 100644 index 00000000..1ecce17e --- /dev/null +++ b/cmd/simgos-sync-migration/migrations/20251201093443.sql @@ -0,0 +1,36 @@ +-- Create "SoapiLink" table +CREATE TABLE "public"."SoapiLink" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Simx_Id" bigint NULL, + "Simgos_Id" bigint NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "uni_SoapiLink_Simgos_Id" UNIQUE ("Simgos_Id"), + CONSTRAINT "uni_SoapiLink_Simx_Id" UNIQUE ("Simx_Id") +); +-- Create "SoapiSimgosLog" table +CREATE TABLE "public"."SoapiSimgosLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); +-- Create "SoapiSimxLog" table +CREATE TABLE "public"."SoapiSimxLog" ( + "Id" bigserial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Value" text NULL, + "Date" timestamptz NULL, + "Status" text NULL, + "ErrMessage" text NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/simgos-sync-migration/migrations/atlas.sum b/cmd/simgos-sync-migration/migrations/atlas.sum new file mode 100644 index 00000000..e82a5610 --- /dev/null +++ b/cmd/simgos-sync-migration/migrations/atlas.sum @@ -0,0 +1,8 @@ +h1:6YZBXq/r79I5tuYyY1+CBzhZsSeukHSs8MyHCC5QuV4= +20251113035508.sql h1:rjDlu6yDdy5xv6nrCOr7NialrLSLT23pzduYNq29Hf0= +20251114071129.sql h1:Z0GQ5bJo3C+tplaWzxT8n3J9HLkEaVsRVp5nn7bmYow= +20251117041601.sql h1:l/RPG5mObqCSBjO4mzG+wTq2ieSycvlfOSz4czpUdWY= +20251118082246.sql h1:xLUwA+EvKWIg3X/TJvu7rqbtBzONiINfag5NJpMV29E= +20251118082915.sql h1:hP6FmUVFuADIN2cDg2Z1l7Wx7PQRb+IYQDvKD7J8VAM= +20251126115527.sql h1:Bvg+Y7k+h5s+/UaezUyJb7J7uzEJS7U5Z/RoCixcUtI= +20251201093443.sql h1:m18tksKG3OzbkxXkhfKUUqbkxnJ0VBPi3Cw34Tbywyc= diff --git a/go.mod b/go.mod index 9d557637..c395bd8f 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,8 @@ toolchain go1.24.6 require ( ariga.io/atlas-provider-gorm v0.5.6 + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 + github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.3 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.5.5 @@ -41,6 +43,7 @@ require ( github.com/karincake/pentol v0.0.3 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.11 // indirect + github.com/kylelemons/godebug v1.1.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 diff --git a/go.sum b/go.sum index 9681a749..da70ac51 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h 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/SebastiaanKlippert/go-wkhtmltopdf v1.9.3 h1:vrA6+R1BMLKMTbos8jAeuBrImHPGtY4gTlcue3OIej8= +github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.3/go.mod h1:SQq4xfIdvf6WYKSDxAJc+xOJdolt+/bc1jnQKMtPMvQ= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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= diff --git a/internal/domain/bpjs-entities/control-plan/dto.go b/internal/domain/bpjs-entities/control-plan/dto.go new file mode 100644 index 00000000..2290707d --- /dev/null +++ b/internal/domain/bpjs-entities/control-plan/dto.go @@ -0,0 +1,7 @@ +package controlplan + +type ReadListDto struct { + PathValue1 string `json:"-"` // jenis kontrol + PathValue2 string `json:"-"` // kode poli + PathValue3 string `json:"-"` // tanggal +} diff --git a/internal/domain/bpjs-entities/control-plan/entity.go b/internal/domain/bpjs-entities/control-plan/entity.go new file mode 100644 index 00000000..1a07379a --- /dev/null +++ b/internal/domain/bpjs-entities/control-plan/entity.go @@ -0,0 +1,22 @@ +package controlplan + +type Response struct { + MetaData MetaData `json:"metaData"` + Response *ResponseItems `json:"response"` // nullable +} + +type MetaData struct { + Code string `json:"code"` + Message string `json:"message"` +} + +type ResponseItems struct { + List []DoctorSchedule `json:"list"` +} + +type DoctorSchedule struct { + JadwalPraktek string `json:"jadwalPraktek"` + Kapasitas string `json:"kapasitas"` + KodeDokter string `json:"kodeDokter"` + NamaDokter string `json:"namaDokter"` +} diff --git a/internal/domain/bpjs-entities/referral/dto.go b/internal/domain/bpjs-entities/referral/dto.go new file mode 100644 index 00000000..16113d24 --- /dev/null +++ b/internal/domain/bpjs-entities/referral/dto.go @@ -0,0 +1,5 @@ +package referral + +type ReadDetailDto struct { + Number *string `json:"number"` // nomor rujukan +} diff --git a/internal/domain/bpjs-entities/referral/entity.go b/internal/domain/bpjs-entities/referral/entity.go new file mode 100644 index 00000000..680400b6 --- /dev/null +++ b/internal/domain/bpjs-entities/referral/entity.go @@ -0,0 +1,96 @@ +package referral + +type Response struct { + MetaData MetaData `json:"metaData"` + Response *ReferralDetail `json:"response"` // nullable +} + +type MetaData struct { + Code string `json:"code"` + Message string `json:"message"` +} + +type ReferralDetail struct { + AsalFaskes string `json:"asalFaskes"` + Rujukan RujukanDetail `json:"rujukan"` +} + +type RujukanDetail struct { + Diagnosa Diagnosa `json:"diagnosa"` + Keluhan *string `json:"keluhan"` // nullable + NoKunjungan string `json:"noKunjungan"` + Pelayanan Pelayanan `json:"pelayanan"` + Peserta Peserta `json:"peserta"` + PoliRujukan Poli `json:"poliRujukan"` + ProvPerujuk Provider `json:"provPerujuk"` + TglKunjungan string `json:"tglKunjungan"` +} + +type Diagnosa struct { + Kode string `json:"kode"` + Nama string `json:"nama"` +} + +type Pelayanan struct { + Kode string `json:"kode"` + Nama string `json:"nama"` +} + +type Peserta struct { + Cob Cob `json:"cob"` + HakKelas KeteranganKode `json:"hakKelas"` + Informasi Informasi `json:"informasi"` + JenisPeserta KeteranganKode `json:"jenisPeserta"` + Mr Mr `json:"mr"` + Nama string `json:"nama"` + Nik string `json:"nik"` + NoKartu string `json:"noKartu"` + Pisa string `json:"pisa"` + ProvUmum Provider `json:"provUmum"` + Sex string `json:"sex"` + StatusPeserta KeteranganKode `json:"statusPeserta"` + TglCetakKartu string `json:"tglCetakKartu"` + TglLahir string `json:"tglLahir"` + TglTAT string `json:"tglTAT"` + TglTMT string `json:"tglTMT"` + Umur Umur `json:"umur"` +} + +type Cob struct { + NmAsuransi *string `json:"nmAsuransi"` // nullable + NoAsuransi *string `json:"noAsuransi"` + TglTAT *string `json:"tglTAT"` + TglTMT *string `json:"tglTMT"` +} + +type KeteranganKode struct { + Keterangan string `json:"keterangan"` + Kode string `json:"kode"` +} + +type Informasi struct { + Dinsos *string `json:"dinsos"` + ESep *string `json:"eSEP"` + NoSKTM *string `json:"noSKTM"` + ProlanisPRB *string `json:"prolanisPRB"` +} + +type Mr struct { + NoMR string `json:"noMR"` + NoTelepon string `json:"noTelepon"` +} + +type Provider struct { + Kode string `son:"kode"` + NmProvider string `json:"nama"` +} + +type Poli struct { + Kode string `json:"kode"` + Nama string `json:"nama"` +} + +type Umur struct { + UmurSaatPelayanan string `json:"umurSaatPelayanan"` + UmurSekarang string `json:"umurSekarang"` +} diff --git a/internal/domain/bpjs-entities/vclaim-reference/dto.go b/internal/domain/bpjs-entities/vclaim-reference/dto.go new file mode 100644 index 00000000..027359a3 --- /dev/null +++ b/internal/domain/bpjs-entities/vclaim-reference/dto.go @@ -0,0 +1,73 @@ +package vclaimreference + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + "time" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Date *time.Time `json:"date"` + SrcCode *string `json:"src_code"` + SrcName *string `json:"src_name"` + Number *string `json:"number"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Sort string `json:"sort"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter-id"` +} + +type ReadDetailDto struct { + Id uint `json:"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 + Encounter_Id *uint `json:"encounter_id"` + Date *time.Time `json:"date"` + SrcCode *string `json:"src_code"` + SrcName *string `json:"src_name"` + Number *string `json:"number"` +} + +func (d VclaimReference) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Date: d.Date, + SrcCode: d.SrcCode, + SrcName: d.SrcName, + Number: d.Number, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []VclaimReference) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/bpjs-entities/vclaim-reference/entity.go b/internal/domain/bpjs-entities/vclaim-reference/entity.go new file mode 100644 index 00000000..a9a974d7 --- /dev/null +++ b/internal/domain/bpjs-entities/vclaim-reference/entity.go @@ -0,0 +1,15 @@ +package vclaimreference + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + "time" +) + +type VclaimReference struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Date *time.Time `json:"date"` + SrcCode *string `json:"src_code"` + SrcName *string `json:"src_name"` + Number *string `json:"number"` +} diff --git a/internal/domain/bpjs-entities/vclaim-sep-control-letter/dto.go b/internal/domain/bpjs-entities/vclaim-sep-control-letter/dto.go new file mode 100644 index 00000000..19530c2c --- /dev/null +++ b/internal/domain/bpjs-entities/vclaim-sep-control-letter/dto.go @@ -0,0 +1,71 @@ +package vclaimsepcontrolletter + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + VclaimSep_Number *string `json:"vclaimSep_number"` + Number *string `json:"number" gorm:"unique;size:20"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl" gorm:"unique;size:1024"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Sort string `json:"sort"` + Pagination ecore.Pagination +} + +type FilterDto struct { + VclaimSep_Number *string `json:"vclaimSep_number"` +} + +type ReadDetailDto struct { + Id *uint `json:"id"` + Number *string `json:"number"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` + Number *string `json:"number"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + VclaimSep_Number *string `json:"vclaimSep_number"` + Number *string `json:"number"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl"` +} + +func (d VclaimSepControlLetter) ToResponse() ResponseDto { + resp := ResponseDto{ + VclaimSep_Number: d.VclaimSep_Number, + Number: d.Number, + Value: d.Value, + FileUrl: d.FileUrl, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []VclaimSepControlLetter) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/bpjs-entities/vclaim-sep-control-letter/entity.go b/internal/domain/bpjs-entities/vclaim-sep-control-letter/entity.go new file mode 100644 index 00000000..57f758fb --- /dev/null +++ b/internal/domain/bpjs-entities/vclaim-sep-control-letter/entity.go @@ -0,0 +1,13 @@ +package vclaimsepcontrolletter + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type VclaimSepControlLetter struct { + ecore.Main + VclaimSep_Number *string `json:"vclaimSep_number"` + Number *string `json:"number" gorm:"unique;size:20"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl" gorm:"unique;size:1024"` +} diff --git a/internal/domain/bpjs-entities/vclaim-sep-print/entity.go b/internal/domain/bpjs-entities/vclaim-sep-print/entity.go index 1bd5e9fc..52809352 100644 --- a/internal/domain/bpjs-entities/vclaim-sep-print/entity.go +++ b/internal/domain/bpjs-entities/vclaim-sep-print/entity.go @@ -2,12 +2,10 @@ package vclaimsepprint import ( ecore "simrs-vx/internal/domain/base-entities/core" - evs "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" ) type VclaimSepPrint struct { ecore.Main - VclaimSep_Number *string `json:"vclaimSep_number"` - VclaimSep *evs.VclaimSep `json:"vclaimSep,omitempty" gorm:"foreignKey:VclaimSep_Number;references:Number"` - Counter *uint `json:"counter"` + VclaimSep_Number *string `json:"vclaimSep_number"` + Counter *uint `json:"counter"` } diff --git a/internal/domain/bpjs-entities/vclaim-sep/dto.go b/internal/domain/bpjs-entities/vclaim-sep/dto.go index 8a174688..2f4475b5 100644 --- a/internal/domain/bpjs-entities/vclaim-sep/dto.go +++ b/internal/domain/bpjs-entities/vclaim-sep/dto.go @@ -1,6 +1,7 @@ package vclaimsep import ( + "encoding/json" ecore "simrs-vx/internal/domain/base-entities/core" evsh "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" ) @@ -8,7 +9,7 @@ import ( type CreateDto struct { Encounter_Id *uint `json:"encounter_id"` Number *string `json:"number" validate:"maxLength=19"` - RequestPayload []byte `json:"requestPayload" validate:"maxLength=1024"` + RequestPayload string `json:"requestPayload" validate:"maxLength=1024"` VclaimSepHist evsh.CreateDto } @@ -25,8 +26,9 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint `json:"id"` - Number *string `json:"number"` + Id uint `json:"id"` + Number *string `json:"number"` + Encounter_Id *uint `json:"encounter_id"` } type UpdateDto struct { @@ -47,14 +49,16 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Number *string `json:"number"` + Encounter_Id *uint `json:"encounter_id"` + Number *string `json:"number"` + Detail *SepDetail `json:"detail,omitempty"` } func (d VclaimSep) ToResponse() ResponseDto { resp := ResponseDto{ Encounter_Id: d.Encounter_Id, Number: d.Number, + Detail: d.Detail, } resp.Main = d.Main return resp @@ -71,3 +75,130 @@ func ToResponseList(data []VclaimSep) []ResponseDto { func (c CreateDto) IsMessageSuccess() bool { return c.VclaimSepHist.Message == "Sukses" } + +func (c CreateDto) RequestPayloadIntoJson() ([]byte, error) { + payload := map[string]interface{}{} + err := json.Unmarshal([]byte(c.RequestPayload), &payload) + if err != nil { + return nil, err + } + return json.Marshal(payload) +} + +func (c CreateDto) RequestPayloadWithEncounterId() ([]byte, error) { + payload := map[string]interface{}{} + + err := json.Unmarshal([]byte(c.RequestPayload), &payload) + if err != nil { + return nil, err + } + + payload["encounter_id"] = c.Encounter_Id + + return json.Marshal(payload) +} + +type SepResponse struct { + MetaData MetaData `json:"metaData"` + Response *SepDetail `json:"response"` +} + +type MetaData struct { + Code string `json:"code"` + Message string `json:"message"` +} + +type SepDetail struct { + AssestmenPel AssestmenPel `json:"assestmenPel"` + Catatan string `json:"catatan"` + Cob string `json:"cob"` + Diagnosa string `json:"diagnosa"` + Dpjp Dpjp `json:"dpjp"` + ESep string `json:"eSEP"` + FlagProcedure FlagProcedure `json:"flagProcedure"` + Informasi any `json:"informasi"` // null = interface{} + JnsPelayanan string `json:"jnsPelayanan"` + Katarak string `json:"katarak"` + KdPenunjang KdPenunjang `json:"kdPenunjang"` + KdStatusKecelakaan string `json:"kdStatusKecelakaan"` + KelasRawat string `json:"kelasRawat"` + KlsRawat KlsRawat `json:"klsRawat"` + Kontrol Kontrol `json:"kontrol"` + LokasiKejadian LokasiKejadian `json:"lokasiKejadian"` + NmStatusKecelakaan string `json:"nmstatusKecelakaan"` + NoRujukan string `json:"noRujukan"` + NoSep string `json:"noSep"` + Penjamin any `json:"penjamin"` // null + Peserta Peserta `json:"peserta"` + Poli string `json:"poli"` + PoliEksekutif string `json:"poliEksekutif"` + TglSep string `json:"tglSep"` + TujuanKunj TujuanKunj `json:"tujuanKunj"` +} + +type AssestmenPel struct { + Kode string `json:"kode"` + Nama string `json:"nama"` +} + +type Dpjp struct { + KdDPJP string `json:"kdDPJP"` + NmDPJP string `json:"nmDPJP"` +} + +type FlagProcedure struct { + Kode string `json:"kode"` + Nama string `json:"nama"` +} + +type KdPenunjang struct { + Kode string `json:"kode"` + Nama string `json:"nama"` +} + +type KlsRawat struct { + KlsRawatHak string `json:"klsRawatHak"` + KlsRawatNaik *string `json:"klsRawatNaik"` // nullable + Pembiayaan *string `json:"pembiayaan"` // nullable + PenanggungJawab *string `json:"penanggungJawab"` // nullable +} + +type Kontrol struct { + KdDokter *string `json:"kdDokter"` // null + NmDokter *string `json:"nmDokter"` // null + NoSurat *string `json:"noSurat"` // null +} + +type LokasiKejadian struct { + KdKab *string `json:"kdKab"` + KdKec *string `json:"kdKec"` + KdProp *string `json:"kdProp"` + KetKejadian *string `json:"ketKejadian"` + Lokasi *string `json:"lokasi"` + TglKejadian *string `json:"tglKejadian"` +} + +type Peserta struct { + Asuransi any `json:"asuransi"` + HakKelas string `json:"hakKelas"` + JnsPeserta string `json:"jnsPeserta"` + Kelamin string `json:"kelamin"` + Nama string `json:"nama"` + NoKartu string `json:"noKartu"` + NoMR string `json:"noMr"` + TglLahir string `json:"tglLahir"` +} + +type TujuanKunj struct { + Kode string `json:"kode"` + Nama string `json:"nama"` +} + +type SepDeleteRequest struct { + Request struct { + TSep struct { + NoSep string `json:"noSep"` + User string `json:"user"` + } `json:"t_sep"` + } `json:"request"` +} diff --git a/internal/domain/bpjs-entities/vclaim-sep/entitiy.go b/internal/domain/bpjs-entities/vclaim-sep/entitiy.go index e23106d8..6948d640 100644 --- a/internal/domain/bpjs-entities/vclaim-sep/entitiy.go +++ b/internal/domain/bpjs-entities/vclaim-sep/entitiy.go @@ -2,10 +2,15 @@ package vclaimsep import ( ecore "simrs-vx/internal/domain/base-entities/core" + evscl "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" + evsp "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-print" ) type VclaimSep struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Number *string `json:"number" gorm:"unique;size:19"` + Encounter_Id *uint `json:"encounter_id"` + Number *string `json:"number" gorm:"unique;size:19"` + Prints []*evsp.VclaimSepPrint `json:"prints,omitempty" gorm:"foreignKey:VclaimSep_Number;references:Number"` + ControlLetters []*evscl.VclaimSepControlLetter `json:"controlLetters,omitempty" gorm:"foreignKey:VclaimSep_Number;references:Number"` + Detail *SepDetail `json:"detail,omitempty" gorm:"-"` } diff --git a/internal/domain/main-entities/antibiotic-in-use/dto.go b/internal/domain/main-entities/antibiotic-in-use/dto.go index 7fbce2dd..1c6ee63f 100644 --- a/internal/domain/main-entities/antibiotic-in-use/dto.go +++ b/internal/domain/main-entities/antibiotic-in-use/dto.go @@ -24,9 +24,11 @@ type FilterDto struct { AntibioticSrc_Id *uint `json:"mcu-src-id"` Result *string `json:"result"` Status_Code erc.DataStatusCode `json:"status-code"` + Includes string `json:"includes"` } type ReadDetailDto struct { - Id uint `json:"id"` + Id uint `json:"id"` + Includes string `json:"includes"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/ap-mcu-order/base/dto.go b/internal/domain/main-entities/ap-mcu-order/base/dto.go new file mode 100644 index 00000000..447bc771 --- /dev/null +++ b/internal/domain/main-entities/ap-mcu-order/base/dto.go @@ -0,0 +1,23 @@ +package apmcuorder + +type CreateDto struct { + Encounter_Id uint `json:"encounter_id"` + Number uint64 `json:"number"` + Doctor_Code string `json:"-"` + Substances string `json:"substances"` + Fictations string `json:"fictations"` + Localization string `json:"localization"` + ClinicalDiagnoses string `json:"clinicalDiagnoses"` + Stadium string `json:"stadium"` + ClinicalNotes string `json:"clinicalNotes"` + CurrentHistory string `json:"currentHistory"` + PastHistory string `json:"pastHistory"` + PrevApMcu string `json:"prevApMcu"` + PrevApMcuNotes string `json:"prevApMcuNotes"` + SupportingExams string `json:"supportingExams"` +} + +type UpdateDto struct { + Id uint64 `json:"id"` + CreateDto +} diff --git a/internal/domain/main-entities/ap-mcu-order/base/entity.go b/internal/domain/main-entities/ap-mcu-order/base/entity.go new file mode 100644 index 00000000..d098fcfd --- /dev/null +++ b/internal/domain/main-entities/ap-mcu-order/base/entity.go @@ -0,0 +1,25 @@ +package apmcuorder + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" +) + +type ApMcuOrder struct { + ecore.BigMain + Encounter_Id uint `json:"encounter_id"` + Number uint64 `json:"number"` + Doctor_Code string `json:"doctor_code" gorm:"unique;size:20"` + Substances string `json:"substances"` + Fictations string `json:"fictations"` + Localization string `json:"localization"` + ClinicalDiagnoses string `json:"clinicalDiagnoses"` + Stadium string `json:"stadium"` + ClinicalNotes *string `json:"clinicalNotes"` + CurrentHistory string `json:"currentHistory"` + PastHistory string `json:"pastHistory"` + PrevApMcu *string `json:"prevApMcu"` + PrevApMcuNotes *string `json:"prevApMcuNotes"` + SupportingExams *string `json:"supportingExams"` + Status_Code erc.DataStatusCode `json:"status_code" gorm:"not null;size:10"` +} diff --git a/internal/domain/main-entities/ap-mcu-order/dto.go b/internal/domain/main-entities/ap-mcu-order/dto.go new file mode 100644 index 00000000..80b0b447 --- /dev/null +++ b/internal/domain/main-entities/ap-mcu-order/dto.go @@ -0,0 +1,96 @@ +package apmcuorder + +import ( + la "simrs-vx/internal/lib/auth" + + ecore "simrs-vx/internal/domain/base-entities/core" + eamob "simrs-vx/internal/domain/main-entities/ap-mcu-order/base" + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" +) + +type CreateDto struct { + eamob.CreateDto + la.AuthInfo +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Sort string `json:"sort"` + Pagination ecore.Pagination +} + +type FilterDto struct { + McuOrder_Id string `json:"mcu-order-id"` +} + +type ReadDetailDto struct { + Id uint64 `json:"id"` +} + +type UpdateDto struct { + Id uint64 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint64 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.BigMain + Encounter_Id uint `json:"encounter_id"` + Encounter *ee.Encounter + Number uint64 `json:"number"` + Doctor_Code string `json:"doctor_code"` + Doctor *ed.Doctor + Substances string `json:"substances"` + Fictations string `json:"fictations"` + Localization string `json:"localization"` + ClinicalDiagnoses string `json:"clinicalDiagnoses"` + Stadium string `json:"stadium"` + ClinicalNotes *string `json:"clinicalNotes"` + PastHistory string `json:"pastHistory"` + CurrentHistory string `json:"currentHistory"` + PrevApMcu *string `json:"prevApMcu"` + PrevApMcuNotes *string `json:"prevApMcuNotes"` + SupportingExams *string `json:"supportingExams"` +} + +func (d ApMcuOrder) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Number: d.Number, + Doctor_Code: d.Doctor_Code, + Doctor: d.Doctor, + Substances: d.Substances, + Fictations: d.Fictations, + Localization: d.Localization, + ClinicalDiagnoses: d.ClinicalDiagnoses, + Stadium: d.Stadium, + ClinicalNotes: d.ClinicalNotes, + PastHistory: d.PastHistory, + CurrentHistory: d.CurrentHistory, + PrevApMcu: d.PrevApMcu, + PrevApMcuNotes: d.PrevApMcuNotes, + SupportingExams: d.SupportingExams, + } + resp.BigMain = d.BigMain + return resp +} + +func ToResponseList(data []ApMcuOrder) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/ap-mcu-order/entity.go b/internal/domain/main-entities/ap-mcu-order/entity.go new file mode 100644 index 00000000..361d0948 --- /dev/null +++ b/internal/domain/main-entities/ap-mcu-order/entity.go @@ -0,0 +1,26 @@ +package apmcuorder + +import ( + eamob "simrs-vx/internal/domain/main-entities/ap-mcu-order/base" + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" + erc "simrs-vx/internal/domain/references/common" +) + +type ApMcuOrder struct { + eamob.ApMcuOrder + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` +} + +func (d ApMcuOrder) IsNotNew() bool { + return d.Status_Code != erc.DSCNew +} + +func (d ApMcuOrder) IsCompleted() bool { + return d.Status_Code == erc.DSCDone +} + +func (d ApMcuOrder) IsSameDoctor(doctor_code *string) bool { + return d.Doctor_Code == *doctor_code +} diff --git a/internal/domain/main-entities/chemo-plan/dto.go b/internal/domain/main-entities/chemo-plan/dto.go new file mode 100644 index 00000000..ffd9803f --- /dev/null +++ b/internal/domain/main-entities/chemo-plan/dto.go @@ -0,0 +1,86 @@ +package chemo_plan + +import ( + // std + "time" + + ere "simrs-vx/internal/domain/references/encounter" + + // internal - domain - main-entities + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Parent_Id *uint `json:"parent_id"` + SeriesNumber *uint16 `json:"seriesNumber"` + CycleNumber *uint `json:"cycleNumber"` + PlanDate *time.Time `json:"planDate"` + RealizationDate *time.Time `json:"realizationDate"` + Notes *string `json:"notes"` + Status ere.StatusProtocolChemo `json:"status"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Parent_Id *uint `json:"parent-id"` + Protocol_Id *uint `json:"protocol-id"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Includes string `json:"includes"` +} + +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 + Parent_Id *uint `json:"parent_id"` // chemo.Id + Protocol_Id *uint `json:"protocol_id"` + SeriesNumber *uint16 `json:"seriesNumber"` // series ke - + CycleNumber *uint `json:"cycleNumber"` // cycle ke - + PlanDate *time.Time `json:"planDate"` + RealizationDate *time.Time `json:"realizationDate"` + Notes *string `json:"notes"` + Status ere.StatusProtocolChemo `json:"status"` +} + +func (d ChemoPlan) ToResponse() ResponseDto { + resp := ResponseDto{ + Parent_Id: d.Parent_Id, + SeriesNumber: d.SeriesNumber, + CycleNumber: d.CycleNumber, + PlanDate: d.PlanDate, + RealizationDate: d.RealizationDate, + Notes: d.Notes, + Status: d.Status, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []ChemoPlan) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/chemo-plan/entity.go b/internal/domain/main-entities/chemo-plan/entity.go new file mode 100644 index 00000000..2dc5a363 --- /dev/null +++ b/internal/domain/main-entities/chemo-plan/entity.go @@ -0,0 +1,24 @@ +package chemo_plan + +import ( + ee "simrs-vx/internal/domain/main-entities/encounter" + "time" + + ecore "simrs-vx/internal/domain/base-entities/core" + + ere "simrs-vx/internal/domain/references/encounter" +) + +type ChemoPlan struct { + ecore.Main + Parent_Id *uint `json:"parent_id"` // chemo.Id + Protocol_Id *uint `json:"protocol_id"` + SeriesNumber *uint16 `json:"seriesNumber"` // series ke - + CycleNumber *uint `json:"cycleNumber"` // cycle ke - + PlanDate *time.Time `json:"planDate"` + RealizationDate *time.Time `json:"realizationDate"` + Notes *string `json:"notes"` + Status ere.StatusProtocolChemo `json:"status"` + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` +} diff --git a/internal/domain/main-entities/chemo-protocol/dto.go b/internal/domain/main-entities/chemo-protocol/dto.go index 04ea0023..03ad0c10 100644 --- a/internal/domain/main-entities/chemo-protocol/dto.go +++ b/internal/domain/main-entities/chemo-protocol/dto.go @@ -9,18 +9,21 @@ import ( // internal - domain - main-entities ecore "simrs-vx/internal/domain/base-entities/core" - ee "simrs-vx/internal/domain/main-entities/encounter" + + ec "simrs-vx/internal/domain/main-entities/chemo" ) type CreateDto struct { - Encounter_Id *uint `json:"encounter_id"` - Patient_Weight *float32 `json:"patient_weight"` - Patient_Height *float32 `json:"patient_height"` - Diagnoses *string `json:"diagnoses"` - Duration *uint `json:"duration"` - DurationUnit_Code *erc.TimeUnitCode `json:"durationUnit_code"` - StartDate *time.Time `json:"startDate"` - EndDate *time.Time `json:"endDate"` + Chemo_Id *uint `json:"chemo_id"` + Patient_Weight *float32 `json:"patient_weight"` + Patient_Height *float32 `json:"patient_height"` + Diagnoses *string `json:"diagnoses"` + Interval *uint `json:"interval"` + Cycle *uint `json:"cycle"` + Series *uint16 `json:"series"` + StartDate *time.Time `json:"startDate"` + EndDate *time.Time `json:"endDate"` + Status_Code erc.DataVerifiedCode `json:"-"` } type ReadListDto struct { @@ -30,7 +33,7 @@ type ReadListDto struct { } type FilterDto struct { - Encounter_Id *uint `json:"encounter-id"` + Chemo_Id *uint `json:"chemo-id"` } type ReadDetailDto struct { @@ -55,28 +58,32 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter,omitempty"` - Patient_Weight *float32 `json:"patient_weight"` - Patient_Height *float32 `json:"patient_height"` - Diagnoses *string `json:"diagnoses"` - Duration *uint `json:"duration"` - DurationUnit_Code *erc.TimeUnitCode `json:"durationUnit_code"` - StartDate *time.Time `json:"startDate"` - EndDate *time.Time `json:"endDate"` + Chemo_Id *uint `json:"chemo_id"` + Chemo *ec.Chemo `json:"chemo,omitempty"` + Patient_Weight *float32 `json:"patient_weight"` + Patient_Height *float32 `json:"patient_height"` + Diagnoses *string `json:"diagnoses"` + Interval *uint `json:"interval"` + Cycle *uint `json:"cycle"` + Series *uint16 `json:"series"` + StartDate *time.Time `json:"startDate"` + EndDate *time.Time `json:"endDate"` + Status_Code erc.DataVerifiedCode `json:"status_code"` } func (d ChemoProtocol) ToResponse() ResponseDto { resp := ResponseDto{ - Encounter_Id: d.Encounter_Id, - Encounter: d.Encounter, - Patient_Weight: d.Patient_Weight, - Patient_Height: d.Patient_Height, - Diagnoses: d.Diagnoses, - Duration: d.Duration, - DurationUnit_Code: d.DurationUnit_Code, - StartDate: d.StartDate, - EndDate: d.EndDate, + Chemo_Id: d.Chemo_Id, + Chemo: d.Chemo, + Patient_Weight: d.Patient_Weight, + Patient_Height: d.Patient_Height, + Diagnoses: d.Diagnoses, + Interval: d.Interval, + Cycle: d.Cycle, + Series: d.Series, + StartDate: d.StartDate, + EndDate: d.EndDate, + Status_Code: d.Status_Code, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/chemo-protocol/entity.go b/internal/domain/main-entities/chemo-protocol/entity.go index e1508e91..6377c136 100644 --- a/internal/domain/main-entities/chemo-protocol/entity.go +++ b/internal/domain/main-entities/chemo-protocol/entity.go @@ -1,21 +1,34 @@ package chemo_protocol import ( - ecore "simrs-vx/internal/domain/base-entities/core" - ee "simrs-vx/internal/domain/main-entities/encounter" - "simrs-vx/internal/domain/references/common" "time" + + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + + ec "simrs-vx/internal/domain/main-entities/chemo" + ecp "simrs-vx/internal/domain/main-entities/chemo-plan" + eus "simrs-vx/internal/domain/main-entities/user" ) type ChemoProtocol struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` - Patient_Weight *float32 `json:"patient_weight"` - Patient_Height *float32 `json:"patient_height"` - Diagnoses *string `json:"diagnoses"` - Duration *uint `json:"duration"` - DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code" gorm:"size:10"` - StartDate *time.Time `json:"startDate"` - EndDate *time.Time `json:"endDate"` + Chemo_Id *uint `json:"chemo_id"` + Chemo *ec.Chemo `json:"chemo,omitempty" gorm:"foreignKey:Chemo_Id;references:Id"` + Patient_Weight *float32 `json:"patient_weight"` + Patient_Height *float32 `json:"patient_height"` + Diagnoses *string `json:"diagnoses"` + Duration *uint `json:"duration"` // not used + DurationUnit_Code *erc.TimeUnitCode `json:"durationUnit_code"` // not used + Interval *uint `json:"interval"` + Cycle *uint `json:"cycle"` // total cycle + Series *uint16 `json:"series"` // total series + StartDate *time.Time `json:"startDate"` + EndDate *time.Time `json:"endDate"` + Status_Code erc.DataVerifiedCode `json:"status_code"` + VerifiedAt *time.Time `json:"verifiedAt"` + VerifiedBy_User_Id *uint `json:"verifiedBy_user_id"` + VerifiedBy *eus.User `json:"verifiedBy,omitempty" gorm:"foreignKey:VerifiedBy_User_Id;references:Id"` + ChemoPlans *[]ecp.ChemoPlan `json:"chemoPlans,omitempty" gorm:"foreignKey:Protocol_Id;references:Id"` + Patient_Id *uint `json:"patient_id"` } diff --git a/internal/domain/main-entities/chemo/dto.go b/internal/domain/main-entities/chemo/dto.go index 5d8b9501..461203d2 100644 --- a/internal/domain/main-entities/chemo/dto.go +++ b/internal/domain/main-entities/chemo/dto.go @@ -1,6 +1,7 @@ package chemo import ( + ed "simrs-vx/internal/domain/main-entities/doctor" // std "time" @@ -50,10 +51,12 @@ type DeleteDto struct { } type VerifyDto struct { - Id uint16 `json:"id"` - Status_Code erc.DataVerifiedCode `json:"status_code"` - Bed *string `json:"bed" validate:"required"` - Needs *string `json:"needs" validate:"required"` + Id uint16 `json:"id"` + Status_Code erc.DataVerifiedCode `json:"status_code"` + Bed *string `json:"bed"` + Needs *string `json:"needs"` + Doctor_Code *string `json:"doctor_code" validate:"required"` + NextChemoDate *time.Time `json:"nextChemoDate"` pa.AuthInfo } @@ -74,6 +77,9 @@ type ResponseDto struct { VerifiedBy *eus.User `json:"verifiedBy,omitempty"` SrcUnit_Code *string `json:"srcUnit_code"` SrcUnit *eun.Unit `json:"srcUnit,omitempty"` + Doctor_Code *string `json:"doctor_code"` + Doctor *ed.Doctor `json:"doctor,omitempty"` + NextChemoDate *time.Time `json:"nextChemoDate"` } func (d Chemo) ToResponse() ResponseDto { @@ -86,6 +92,9 @@ func (d Chemo) ToResponse() ResponseDto { VerifiedBy: d.VerifiedBy, SrcUnit_Code: d.SrcUnit_Code, SrcUnit: d.SrcUnit, + Doctor_Code: d.Doctor_Code, + Doctor: d.Doctor, + NextChemoDate: d.NextChemoDate, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/chemo/entity.go b/internal/domain/main-entities/chemo/entity.go index 6f5180aa..cc828835 100644 --- a/internal/domain/main-entities/chemo/entity.go +++ b/internal/domain/main-entities/chemo/entity.go @@ -1,14 +1,16 @@ package chemo import ( + ere "simrs-vx/internal/domain/references/encounter" "time" ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + + ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" eun "simrs-vx/internal/domain/main-entities/unit" eus "simrs-vx/internal/domain/main-entities/user" - - erc "simrs-vx/internal/domain/references/common" ) type Chemo struct { @@ -19,8 +21,12 @@ type Chemo struct { VerifiedAt *time.Time `json:"verifiedAt"` VerifiedBy_User_Id *uint `json:"verifiedBy_user_id"` VerifiedBy *eus.User `json:"verifiedBy,omitempty" gorm:"foreignKey:VerifiedBy_User_Id;references:Id"` - SrcUnit_Code *string `json:"src_unit_code"` + SrcUnit_Code *string `json:"src_unit_code"` // klinik asal SrcUnit *eun.Unit `json:"src_unit,omitempty" gorm:"foreignKey:SrcUnit_Code;references:Code"` Bed *string `json:"bed" gorm:"size:1024"` Needs *string `json:"needs" gorm:"size:2048"` + Doctor_Code *string `json:"doctor_code"` + Doctor *ed.Doctor `json:"doctor" gorm:"foreignKey:Doctor_Code;references:Code"` + NextChemoDate *time.Time `json:"nextChemoDate"` + Class_Code ere.ChemoClassCode `json:"class_code"` } diff --git a/internal/domain/main-entities/cp-mcu-order-item/base/dto.go b/internal/domain/main-entities/cp-mcu-order-item/base/dto.go new file mode 100644 index 00000000..2510f9a0 --- /dev/null +++ b/internal/domain/main-entities/cp-mcu-order-item/base/dto.go @@ -0,0 +1,6 @@ +package cpmcuorderitem + +type SubCreateDto struct { + McuSrc_Code string `json:"mcuSrc_code" validate:"required"` + Note string `json:"note"` +} diff --git a/internal/domain/main-entities/cp-mcu-order-item/base/entity.go b/internal/domain/main-entities/cp-mcu-order-item/base/entity.go new file mode 100644 index 00000000..5abb8494 --- /dev/null +++ b/internal/domain/main-entities/cp-mcu-order-item/base/entity.go @@ -0,0 +1,17 @@ +package cpmcuorderitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ems "simrs-vx/internal/domain/main-entities/mcu-src" + erc "simrs-vx/internal/domain/references/common" +) + +type CpMcuOrderItem struct { + ecore.BigMain // adjust this according to the needs + CpMcuOrder_Id uint64 `json:"cpMcuOrder_id" gorm:"uniqueIndex:idx_order_src"` + McuSrc_Code string `json:"mcuSrc_code" gorm:"uniqueIndex:idx_order_src"` + McuSrc *ems.McuSrc `json:"mcuSrc,omitempty" gorm:"foreignKey:McuSrc_Code;references:Code"` + Note *string `json:"note" gorm:"size:1024"` + Result *string `json:"result"` + Status_Code erc.DataStatusCode `json:"status_code"` +} diff --git a/internal/domain/main-entities/cp-mcu-order-item/dto.go b/internal/domain/main-entities/cp-mcu-order-item/dto.go new file mode 100644 index 00000000..a0979186 --- /dev/null +++ b/internal/domain/main-entities/cp-mcu-order-item/dto.go @@ -0,0 +1,80 @@ +package cpmcuorderitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + emro "simrs-vx/internal/domain/main-entities/cp-mcu-order" + ems "simrs-vx/internal/domain/main-entities/mcu-src" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type CreateDto struct { + CpMcuOrder_Id uint64 `json:"cpMcuOrder_id"` + McuSrc_Code string `json:"mcuSrc_code"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + CpMcuOrder_Id *uint64 `json:"cp-mcu-order-id"` + McuSrc_Code *string `json:"mcu-src-code"` + Status_Code erc.DataStatusCode `json:"status-code"` +} +type ReadDetailDto struct { + Id uint `json:"id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type SetScheduleDto struct { + Id uint `json:"id"` + ExaminationDate *time.Time `json:"examinationDate"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.BigMain + CpMcuOrder_Id uint64 `json:"cpMcuOrder_id"` + CpMcuOrder *emro.CpMcuOrder `json:"cpMcuOrder,omitempty"` + McuSrc_Code string `json:"mcuSrc_code"` + McuSrc *ems.McuSrc `json:"mcuSrc,omitempty"` + Result *string `json:"result"` + Status_Code erc.DataStatusCode `json:"status_code"` +} + +func (d CpMcuOrderItem) ToResponse() ResponseDto { + resp := ResponseDto{ + CpMcuOrder_Id: d.CpMcuOrder_Id, + CpMcuOrder: d.CpMcuOrder, + McuSrc_Code: d.McuSrc_Code, + McuSrc: d.McuSrc, + Result: d.Result, + Status_Code: d.Status_Code, + } + resp.BigMain = d.BigMain + return resp +} + +func ToResponseList(data []CpMcuOrderItem) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/cp-mcu-order-item/entity.go b/internal/domain/main-entities/cp-mcu-order-item/entity.go new file mode 100644 index 00000000..5858ab58 --- /dev/null +++ b/internal/domain/main-entities/cp-mcu-order-item/entity.go @@ -0,0 +1,17 @@ +package cpmcuorderitem + +import ( + emo "simrs-vx/internal/domain/main-entities/cp-mcu-order" + emoib "simrs-vx/internal/domain/main-entities/cp-mcu-order-item/base" + + erc "simrs-vx/internal/domain/references/common" +) + +type CpMcuOrderItem struct { + emoib.CpMcuOrderItem + CpMcuOrder *emo.CpMcuOrder `json:"cpMcuOrder,omitempty" gorm:"foreignKey:CpMcuOrder_Id;references:Id"` +} + +func (d CpMcuOrderItem) IsCompleted() bool { + return d.Status_Code == erc.DSCDone +} diff --git a/internal/domain/main-entities/cp-mcu-order/base/entity.go b/internal/domain/main-entities/cp-mcu-order/base/entity.go new file mode 100644 index 00000000..e9531e22 --- /dev/null +++ b/internal/domain/main-entities/cp-mcu-order/base/entity.go @@ -0,0 +1,21 @@ +package cpmcuorder + +import ( + "time" + + ecore "simrs-vx/internal/domain/base-entities/core" + ercl "simrs-vx/internal/domain/references/clinical" + erc "simrs-vx/internal/domain/references/common" +) + +type CpMcuOrder struct { + ecore.BigMain + Encounter_Id uint `json:"encounter_id"` + Number uint64 `json:"number"` + Doctor_Code string `json:"doctor_code" gorm:"unique;size:20"` + UrgencyLevel_Code ercl.McuUrgencyLevelCode `json:"urgencyLevel_code" gorm:"not null;size:15"` + OtherNotes *string `json:"otherNotes"` + ExamScheduleDate *time.Time `json:"examinationDate"` + Resume *string `json:"resume"` + Status_Code erc.DataStatusCode `json:"status_code" gorm:"not null;size:10"` +} diff --git a/internal/domain/main-entities/cp-mcu-order/dto.go b/internal/domain/main-entities/cp-mcu-order/dto.go new file mode 100644 index 00000000..afccfb20 --- /dev/null +++ b/internal/domain/main-entities/cp-mcu-order/dto.go @@ -0,0 +1,84 @@ +package cpmcuorder + +import ( + la "simrs-vx/internal/lib/auth" + + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" +) + +type CreateDto struct { + Encounter_Id uint `json:"encounter_id" validate:"required"` + Number uint64 `json:"number"` // SHOULD BE AUTOMATIC WITHOUT SYNC + UrgencyLevel_Code string `json:"urgencyLevel_code" validate:"required"` + OtherNotes string `json:"otherNotes"` + la.AuthInfo +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Sort string `json:"sort"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id uint `json:"encounter-id"` + Doctor_Code string `json:"doctor-code"` +} + +type ReadDetailDto struct { + Id uint64 `json:"id"` + Includes string `json:"includes"` +} + +type UpdateDto struct { + Id uint64 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint64 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.BigMain + Encounter_Id uint + Encounter *ee.Encounter + Number uint64 `json:"number"` + Doctor_Code string `json:"doctor_code"` + Doctor *ed.Doctor + UrgencyLevel_Code string `json:"urgencyLevel_code" gorm:"not null;size:15"` + OtherNotes *string `json:"otherNotes"` + Resume *string `json:"resume"` +} + +func (d CpMcuOrder) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Number: d.Number, + Doctor_Code: d.Doctor_Code, + Doctor: d.Doctor, + UrgencyLevel_Code: string(d.UrgencyLevel_Code), + OtherNotes: d.OtherNotes, + Resume: d.Resume, + } + resp.BigMain = d.BigMain + return resp +} + +func ToResponseList(data []CpMcuOrder) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/cp-mcu-order/entity.go b/internal/domain/main-entities/cp-mcu-order/entity.go new file mode 100644 index 00000000..08a3d927 --- /dev/null +++ b/internal/domain/main-entities/cp-mcu-order/entity.go @@ -0,0 +1,28 @@ +package cpmcuorder + +import ( + ecmoi "simrs-vx/internal/domain/main-entities/cp-mcu-order-item/base" + eamob "simrs-vx/internal/domain/main-entities/cp-mcu-order/base" + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" + erc "simrs-vx/internal/domain/references/common" +) + +type CpMcuOrder struct { + eamob.CpMcuOrder + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` + Items []*ecmoi.CpMcuOrderItem `json:"items" gorm:"foreignKey:CpMcuOrder_Id;references:Id"` +} + +func (d CpMcuOrder) IsNotNew() bool { + return d.Status_Code != erc.DSCNew +} + +func (d CpMcuOrder) IsCompleted() bool { + return d.Status_Code == erc.DSCDone +} + +func (d CpMcuOrder) IsSameDoctor(doctor_code *string) bool { + return d.Doctor_Code == *doctor_code +} diff --git a/internal/domain/main-entities/device-order-item/base/entity.go b/internal/domain/main-entities/device-order-item/base/entity.go new file mode 100644 index 00000000..95eaa895 --- /dev/null +++ b/internal/domain/main-entities/device-order-item/base/entity.go @@ -0,0 +1,14 @@ +package deviceorderitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/device" +) + +type DeviceOrderItem struct { + ecore.Main // adjust this according to the needs + DeviceOrder_Id *uint `json:"deviceOrder_id"` + Device_Code *string `json:"device_code"` + Device *ed.Device `json:"device,omitempty" gorm:"foreignKey:Device_Code;references:Code"` + Quantity uint8 `json:"quantity"` +} diff --git a/internal/domain/main-entities/device-order-item/dto.go b/internal/domain/main-entities/device-order-item/dto.go index afa08ed8..3d31c66d 100644 --- a/internal/domain/main-entities/device-order-item/dto.go +++ b/internal/domain/main-entities/device-order-item/dto.go @@ -9,19 +9,20 @@ import ( type CreateDto struct { DeviceOrder_Id *uint `json:"deviceOrder_id"` Device_Code *string `json:"device_code"` - Count uint8 `json:"count"` + Quantity uint8 `json:"quantity"` } type ReadListDto struct { FilterDto Includes string `json:"includes"` + Sort string `json:"sort"` Pagination ecore.Pagination } type FilterDto struct { - DeviceOrder_Id *uint `json:"deviceOrder-id"` + DeviceOrder_Id *uint `json:"device-order-id"` Device_Code *string `json:"device-code"` - Count uint8 `json:"count"` + Quantity uint8 `json:"quantity"` } type ReadDetailDto struct { Id uint16 `json:"id"` @@ -48,7 +49,7 @@ type ResponseDto struct { DeviceOrder *edo.DeviceOrder `json:"deviceOrder,omitempty"` Device_Code *string `json:"device_code"` Device *ed.Device `json:"device,omitempty"` - Count uint8 `json:"count"` + Quantity uint8 `json:"quantity"` } func (d DeviceOrderItem) ToResponse() ResponseDto { @@ -57,7 +58,7 @@ func (d DeviceOrderItem) ToResponse() ResponseDto { DeviceOrder: d.DeviceOrder, Device_Code: d.Device_Code, Device: d.Device, - Count: d.Count, + Quantity: d.Quantity, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/device-order-item/entity.go b/internal/domain/main-entities/device-order-item/entity.go index 27197125..f214ec6a 100644 --- a/internal/domain/main-entities/device-order-item/entity.go +++ b/internal/domain/main-entities/device-order-item/entity.go @@ -2,15 +2,12 @@ package deviceorderitem import ( ecore "simrs-vx/internal/domain/base-entities/core" - ed "simrs-vx/internal/domain/main-entities/device" edo "simrs-vx/internal/domain/main-entities/device-order" + eb "simrs-vx/internal/domain/main-entities/device-order-item/base" ) type DeviceOrderItem struct { - ecore.Main // adjust this according to the needs - DeviceOrder_Id *uint `json:"deviceOrder_id"` - DeviceOrder *edo.DeviceOrder `json:"deviceOrder,omitempty" gorm:"foreignKey:DeviceOrder_Id;references:Id"` - Device_Code *string `json:"device_code"` - Device *ed.Device `json:"device,omitempty" gorm:"foreignKey:Device_Code;references:Code"` - Count uint8 `json:"count"` + ecore.Main // adjust this according to the needs + eb.DeviceOrderItem + DeviceOrder *edo.DeviceOrder `json:"deviceOrder,omitempty" gorm:"foreignKey:DeviceOrder_Id;references:Id"` } diff --git a/internal/domain/main-entities/device-order/dto.go b/internal/domain/main-entities/device-order/dto.go index 6371800c..cdff2a18 100644 --- a/internal/domain/main-entities/device-order/dto.go +++ b/internal/domain/main-entities/device-order/dto.go @@ -11,6 +11,7 @@ import ( erc "simrs-vx/internal/domain/references/common" // internal - domain - main-entities + edoi "simrs-vx/internal/domain/main-entities/device-order-item/base" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" ) @@ -55,11 +56,12 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter,omitempty"` - Doctor_Code *string `json:"doctor_code"` - Doctor *ed.Doctor `json:"doctor,omitempty"` - Status_Code erc.DataStatusCode `json:"status_code"` + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Doctor_Code *string `json:"doctor_code"` + Doctor *ed.Doctor `json:"doctor,omitempty"` + Status_Code erc.DataStatusCode `json:"status_code"` + Items []edoi.DeviceOrderItem `json:"items"` } func (d DeviceOrder) ToResponse() ResponseDto { @@ -69,6 +71,7 @@ func (d DeviceOrder) ToResponse() ResponseDto { Doctor_Code: d.Doctor_Code, Doctor: d.Doctor, Status_Code: d.Status_Code, + Items: d.Items, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/device-order/entity.go b/internal/domain/main-entities/device-order/entity.go index 7ff4fa34..7ed304e5 100644 --- a/internal/domain/main-entities/device-order/entity.go +++ b/internal/domain/main-entities/device-order/entity.go @@ -1,20 +1,22 @@ package deviceorder import ( + erc "simrs-vx/internal/domain/references/common" + ecore "simrs-vx/internal/domain/base-entities/core" + edoi "simrs-vx/internal/domain/main-entities/device-order-item/base" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" - - erc "simrs-vx/internal/domain/references/common" ) type DeviceOrder struct { - ecore.Main // adjust this according to the needs - Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` - Doctor_Code *string `json:"doctor_code"` - Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` - Status_Code erc.DataStatusCode `json:"status_code"` + ecore.Main // adjust this according to the needs + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Doctor_Code *string `json:"doctor_code"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` + Status_Code erc.DataStatusCode `json:"status_code"` + Items []edoi.DeviceOrderItem `json:"items" gorm:"foreignKey:DeviceOrder_Id;references:Id"` } func (d DeviceOrder) IsCompleted() bool { diff --git a/internal/domain/main-entities/device-package-item/device-package/dto.go b/internal/domain/main-entities/device-package-item/device-package/dto.go new file mode 100644 index 00000000..26aad58a --- /dev/null +++ b/internal/domain/main-entities/device-package-item/device-package/dto.go @@ -0,0 +1,63 @@ +package devicepackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code" validate:"maxLength=20"` + Name string `json:"name" validate:"maxLength=50"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadDetailDto struct { + Id uint16 `json:"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"` +} + +func (d DevicePackage) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []DevicePackage) []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-package-item/device-package/entity.go b/internal/domain/main-entities/device-package-item/device-package/entity.go new file mode 100644 index 00000000..1c03b44d --- /dev/null +++ b/internal/domain/main-entities/device-package-item/device-package/entity.go @@ -0,0 +1,11 @@ +package devicepackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type DevicePackage struct { + ecore.SmallMain + Code string `json:"code" gorm:"unique;size:20;not null"` + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/domain/main-entities/device-package-item/dto.go b/internal/domain/main-entities/device-package-item/dto.go new file mode 100644 index 00000000..a0a224ba --- /dev/null +++ b/internal/domain/main-entities/device-package-item/dto.go @@ -0,0 +1,69 @@ +package devicepackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/device" + edp "simrs-vx/internal/domain/main-entities/device-package" +) + +type CreateDto struct { + DevicePackage_Code string `json:"devicePackage_code" validate:"maxLength=20"` + Device_Code string `json:"code" validate:"maxLength=20"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + DevicePackage_Code string `json:"devicePackage-code"` + Device_Code string `json:"code"` +} + +type ReadDetailDto struct { + Id uint `json:"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 + DevicePackage_Code string `json:"devicePackage_code"` + DevicePackage *edp.DevicePackage `json:"devicePackage,omitempty"` + Device_Code string `json:"code"` + Device *ed.Device `json:"device,omitempty"` +} + +func (d DevicePackageItem) ToResponse() ResponseDto { + resp := ResponseDto{ + DevicePackage_Code: d.DevicePackage_Code, + DevicePackage: d.DevicePackage, + Device_Code: d.Device_Code, + Device: d.Device, + } + resp.Id = d.Id + return resp +} + +func ToResponseList(data []DevicePackageItem) []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-package-item/entity.go b/internal/domain/main-entities/device-package-item/entity.go new file mode 100644 index 00000000..476e24e2 --- /dev/null +++ b/internal/domain/main-entities/device-package-item/entity.go @@ -0,0 +1,15 @@ +package devicepackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/device" + edp "simrs-vx/internal/domain/main-entities/device-package" +) + +type DevicePackageItem struct { + ecore.Main + DevicePackage_Code string `json:"devicePackage_code" gorm:"size:20;not null"` + DevicePackage *edp.DevicePackage `json:"devicePackage" gorm:"foreignKey:DevicePackage_Code;references:Code"` + Device_Code string `json:"code" gorm:"size:20;not null"` + Device *ed.Device `json:"device" gorm:"foreignKey:Device_Code;references:Code"` +} diff --git a/internal/domain/main-entities/device-package/dto.go b/internal/domain/main-entities/device-package/dto.go new file mode 100644 index 00000000..26aad58a --- /dev/null +++ b/internal/domain/main-entities/device-package/dto.go @@ -0,0 +1,63 @@ +package devicepackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code" validate:"maxLength=20"` + Name string `json:"name" validate:"maxLength=50"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadDetailDto struct { + Id uint16 `json:"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"` +} + +func (d DevicePackage) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []DevicePackage) []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-package/entity.go b/internal/domain/main-entities/device-package/entity.go new file mode 100644 index 00000000..1c03b44d --- /dev/null +++ b/internal/domain/main-entities/device-package/entity.go @@ -0,0 +1,11 @@ +package devicepackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type DevicePackage struct { + ecore.SmallMain + Code string `json:"code" gorm:"unique;size:20;not null"` + 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 index 30f0b238..d74b54f7 100644 --- a/internal/domain/main-entities/division/dto.go +++ b/internal/domain/main-entities/division/dto.go @@ -6,6 +6,7 @@ import ( ) type CreateDto struct { + Id *uint `json:"id"` Code string `json:"code" validate:"maxLength=10"` Name string `json:"name" validate:"maxLength=50"` Parent_Code *string `json:"parent_code"` diff --git a/internal/domain/main-entities/doctor/dto.go b/internal/domain/main-entities/doctor/dto.go index e3d1f3ee..c7eb0f6b 100644 --- a/internal/domain/main-entities/doctor/dto.go +++ b/internal/domain/main-entities/doctor/dto.go @@ -43,6 +43,7 @@ type ReadDetailDto struct { Employee_Id *uint `json:"employee_id"` IHS_Number *string `json:"ihs_number"` SIP_Number *string `json:"sip_number"` + Includes string `json:"includes"` } type UpdateDto struct { diff --git a/internal/domain/main-entities/employee/dto.go b/internal/domain/main-entities/employee/dto.go index 85b7008a..5b2c674d 100644 --- a/internal/domain/main-entities/employee/dto.go +++ b/internal/domain/main-entities/employee/dto.go @@ -4,6 +4,7 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ep "simrs-vx/internal/domain/main-entities/person" eu "simrs-vx/internal/domain/main-entities/user" + "time" erc "simrs-vx/internal/domain/references/common" erg "simrs-vx/internal/domain/references/organization" @@ -55,22 +56,26 @@ 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"` - Number *string `json:"number"` - Status_Code erc.ActiveStatusCode `json:"status_code"` + User_Id *uint `json:"user_id"` + User *eu.User `json:"user,omitempty"` + Person_Id *uint `json:"person_id"` + Person *ep.Person `json:"person,omitempty"` + Number *string `json:"number"` + Position_Code *erg.EmployeePositionCode `json:"position_code"` + Contract_ExpiredDate *time.Time `json:"contract_expiredDate"` + Status_Code erc.ActiveStatusCode `json:"status_code"` } func (d Employee) ToResponse() ResponseDto { resp := ResponseDto{ - User_Id: d.User_Id, - User: d.User, - Person_Id: d.Person_Id, - Person: d.Person, - Number: d.Number, - Status_Code: d.Status_Code, + User_Id: d.User_Id, + User: d.User, + Person_Id: d.Person_Id, + Person: d.Person, + Number: d.Number, + Position_Code: d.Position_Code, + Contract_ExpiredDate: d.Contract_ExpiredDate, + Status_Code: d.Status_Code, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/encounter-document/dto.go b/internal/domain/main-entities/encounter-document/dto.go index c1e0894c..6381413b 100644 --- a/internal/domain/main-entities/encounter-document/dto.go +++ b/internal/domain/main-entities/encounter-document/dto.go @@ -1,7 +1,7 @@ package encounter_document import ( - eru "simrs-vx/internal/domain/references/upload" + ere "simrs-vx/internal/domain/references/encounter" // internal - domain - base-entities ecore "simrs-vx/internal/domain/base-entities/core" @@ -9,12 +9,12 @@ import ( ) type CreateDto struct { - Encounter_Id *uint `json:"encounter_id"` - Type_Code eru.UploadCode `json:"type_code"` - Name string `json:"name"` - FilePath string `json:"filePath"` - Filename string `json:"-"` - Upload_Employee_Id *uint `form:"upload_employee_id"` + Encounter_Id *uint `json:"encounter_id"` + Type_Code ere.DocTypeCode `json:"type_code"` + Name string `json:"name"` + FilePath string `json:"filePath"` + Filename string `json:"-"` + Upload_Employee_Id *uint `form:"upload_employee_id"` } type ReadListDto struct { @@ -24,9 +24,9 @@ type ReadListDto struct { } type FilterDto struct { - Encounter_Id *uint `json:"encounter-id"` - Type_Code eru.UploadCode `json:"type-code"` - Upload_Employee_Id *string `json:"encounter-document-employee-id"` + Encounter_Id *uint `json:"encounter-id"` + Type_Code ere.DocTypeCode `json:"type-code"` + Upload_Employee_Id *string `json:"encounter-document-employee-id"` } type ReadDetailDto struct { @@ -51,13 +51,13 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Type_Code eru.UploadCode `json:"type_code"` - Name string `json:"name"` - FilePath *string `json:"filePath"` - FileName *string `json:"fileName"` - Upload_Employee_Id *uint `json:"upload_employee_id"` - Upload_Employee *ee.Employee `json:"upload_employee,omitempty"` + Encounter_Id *uint `json:"encounter_id"` + Type_Code ere.DocTypeCode `json:"type_code"` + Name string `json:"name"` + FilePath *string `json:"filePath"` + FileName *string `json:"fileName"` + Upload_Employee_Id *uint `json:"upload_employee_id"` + Upload_Employee *ee.Employee `json:"upload_employee,omitempty"` } func (d EncounterDocument) ToResponse() ResponseDto { diff --git a/internal/domain/main-entities/encounter-document/entity.go b/internal/domain/main-entities/encounter-document/entity.go index 6c98e1e2..61152eb4 100644 --- a/internal/domain/main-entities/encounter-document/entity.go +++ b/internal/domain/main-entities/encounter-document/entity.go @@ -3,16 +3,16 @@ package encounter_document import ( ecore "simrs-vx/internal/domain/base-entities/core" ee "simrs-vx/internal/domain/main-entities/employee" - eru "simrs-vx/internal/domain/references/upload" + ere "simrs-vx/internal/domain/references/encounter" ) type EncounterDocument struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Type_Code eru.UploadCode `json:"type_code"` - Name string `json:"name"` - FilePath *string `json:"filePath"` - FileName *string `json:"fileName"` - Upload_Employee_Id *uint `json:"upload_employee_id"` - Upload_Employee *ee.Employee `json:"upload_employee,omitempty" gorm:"foreignKey:Upload_Employee_Id;references:Id"` + Encounter_Id *uint `json:"encounter_id"` + Type_Code ere.DocTypeCode `json:"type_code"` + Name string `json:"name"` + FilePath *string `json:"filePath"` + FileName *string `json:"fileName"` + Upload_Employee_Id *uint `json:"upload_employee_id"` + Upload_Employee *ee.Employee `json:"upload_employee,omitempty" gorm:"foreignKey:Upload_Employee_Id;references:Id"` } diff --git a/internal/domain/main-entities/encounter/dto.go b/internal/domain/main-entities/encounter/dto.go index d3f2d04d..324501e4 100644 --- a/internal/domain/main-entities/encounter/dto.go +++ b/internal/domain/main-entities/encounter/dto.go @@ -1,14 +1,6 @@ package encounter import ( - eam "simrs-vx/internal/domain/main-entities/ambulatory" - edc "simrs-vx/internal/domain/main-entities/death-cause" - eem "simrs-vx/internal/domain/main-entities/emergency" - eed "simrs-vx/internal/domain/main-entities/encounter-document" - eip "simrs-vx/internal/domain/main-entities/inpatient" - eir "simrs-vx/internal/domain/main-entities/internal-reference" - er "simrs-vx/internal/domain/main-entities/rehab/base" - // std "time" @@ -24,37 +16,57 @@ import ( // internal - domain - main-entities evs "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + eam "simrs-vx/internal/domain/main-entities/ambulatory" ea "simrs-vx/internal/domain/main-entities/appointment" + edc "simrs-vx/internal/domain/main-entities/death-cause" ed "simrs-vx/internal/domain/main-entities/doctor" + eem "simrs-vx/internal/domain/main-entities/emergency" ee "simrs-vx/internal/domain/main-entities/employee" + eed "simrs-vx/internal/domain/main-entities/encounter-document" + eip "simrs-vx/internal/domain/main-entities/inpatient" + eir "simrs-vx/internal/domain/main-entities/internal-reference" + en "simrs-vx/internal/domain/main-entities/nurse" ep "simrs-vx/internal/domain/main-entities/patient" + er "simrs-vx/internal/domain/main-entities/rehab/base" es "simrs-vx/internal/domain/main-entities/specialist" ess "simrs-vx/internal/domain/main-entities/subspecialist" eu "simrs-vx/internal/domain/main-entities/unit" ) type CreateDto struct { - Patient_Id *uint `json:"patient_id"` - RegisteredAt *time.Time `json:"registeredAt"` - Class_Code ere.EncounterClassCode `json:"class_code" validate:"maxLength=10"` - SubClass_Code *string `json:"subClass_code" validate:"maxLength=10"` // for sub - Infra_Code *string `json:"infra_code"` // for inpatient - Unit_Code *string `json:"unit_code"` - Specialist_Code *string `json:"specialist_code"` - Subspecialist_Code *string `json:"subspecialist_code"` - VisitDate time.Time `json:"visitDate"` - PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code" gorm:"size:10"` - InsuranceCompany_Code *string `json:"insuranceCompany_code"` - Member_Number *string `json:"member_number" validate:"maxLength=20"` - Ref_Number *string `json:"ref_number" validate:"maxLength=20"` - Trx_Number *string `json:"trx_number" validate:"maxLength=20"` - Appointment_Doctor_Code *string `json:"appointment_doctor_code"` - Adm_Employee_Id *uint `json:"-"` - Responsible_Doctor_Code *string `json:"responsible_doctor_code"` - RefSource_Name *string `json:"refSource_name" validate:"maxLength=100"` - Appointment_Id *uint `json:"appointment_id"` - RefTypeCode ere.RefTypeCode `json:"refTypeCode"` - NewStatus bool `json:"newStatus"` + Patient_Id *uint `json:"patient_id"` + RegisteredAt *time.Time `json:"registeredAt"` + Class_Code ere.EncounterClassCode `json:"class_code" validate:"maxLength=10"` + SubClass_Code *string `json:"subClass_code" validate:"maxLength=10"` // for sub + Infra_Code *string `json:"infra_code"` // for inpatient + Unit_Code *string `json:"unit_code"` + Specialist_Code *string `json:"specialist_code"` + Subspecialist_Code *string `json:"subspecialist_code"` + VisitDate time.Time `json:"visitDate"` + StartedAt *time.Time `json:"startedAt"` + FinishedAt *time.Time `json:"finishedAt"` + PaymentMethod_Code ere.AllPaymentMethodCode `json:"paymentMethod_code" gorm:"size:10"` + InsuranceCompany_Code *string `json:"insuranceCompany_code"` + Member_Number *string `json:"member_number" validate:"maxLength=20"` + RefTypeCode ere.RefTypeCode `json:"refTypeCode"` + Ref_Number *string `json:"ref_number" validate:"maxLength=20"` + Trx_Number *string `json:"trx_number" validate:"maxLength=20"` + Appointment_Doctor_Code *string `json:"appointment_doctor_code"` + Adm_Employee_Id *uint `json:"-"` + Responsible_Doctor_Code *string `json:"responsible_doctor_code"` + Responsible_Nurse_Code *string `json:"responsible_nurse_code"` + Discharge_Method_Code *ere.DischargeMethodCode `json:"discharge_method_code" gorm:"size:16"` + RefSource_Name *string `json:"refSource_name" validate:"maxLength=100"` + Appointment_Id *uint `json:"appointment_id"` + EarlyEducation *string `json:"earlyEducation"` + MedicalDischargeEducation *string `json:"medicalDischargeEducation"` + AdmDischargeEducation *string `json:"admDischargeEducation"` + DischargeReason *string `json:"dischargeReason"` + Status_Code erc.DataStatusCode `json:"status_code" gorm:"size:10"` + Discharge_Date *time.Time `json:"discharge_date"` + DeathCause *edc.DeathCause `json:"deathCause"` + NewStatus bool `json:"newStatus"` + VclaimReference *TRujukan `json:"vclaimReference"` Id uint `json:"-"` RecentEncounterAdm *Encounter `json:"-"` // if subClass_Code is rehab @@ -63,10 +75,28 @@ type CreateDto struct { pa.AuthInfo } +type TRujukan struct { + NoSep string `json:"noSep"` // Surat Eligibilitas Peserta + TglRujukan string `json:"tglRujukan"` + PpkDirujuk string `json:"ppkDirujuk"` // PPK (Provider Pelayanan Kesehatan) -> kode RS tujuan + JnsPelayanan string `json:"jnsPelayanan"` // Jenis pelayanan yang dimintakan; 1 = RawatInap; 2 = RawatJalan + Catatan string `json:"catatan"` + DiagRujukan string `json:"diagRujukan"` // Kode Diagnosa + TipeRujukan string `json:"tipeRujukan"` // 0 = Rujukan Penuh; 1 = Rujukan Partial (hanya untuk tindakan tertentu); 2 = Balik (dikembalikan ke faskes asal) + PoliRujukan string `json:"poliRujukan"` // Kode Poli Tujuan + User string `json:"user"` // user yang membuat rujukan +} + type ReadListDto struct { FilterDto - Includes string `json:"includes"` - Pagination ecore.Pagination + Includes string `json:"includes"` + Pagination ecore.Pagination + Patient_Identifier *string `json:"patient-identifier"` + StartDate *string `json:"start-date"` + EndDate *string `json:"end-date"` + PaymentMethod_Code *string `json:"paymentMethod-code"` + Status_Code *string `json:"status-code"` + Unit_Code *string `json:"unit-code"` pa.AuthInfo } @@ -76,7 +106,6 @@ type FilterDto struct { Patient *ep.Patient `json:"patient,omitempty"` RegisteredAt *time.Time `json:"registeredAt"` Class_Code ere.EncounterClassCode `json:"class-code" validate:"maxLength=10"` - Unit_Code *string `json:"unit-code"` Specialist_Code *string `json:"specialist-code"` Subspecialist_Code *string `json:"subspecialist-code"` VisitDate time.Time `json:"visitDate"` @@ -92,22 +121,26 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` Includes string `json:"includes"` } type UpdateDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` CreateDto } type UpdateStatusDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` StatusCode erc.DataStatusCode `json:"status_code"` + + pa.AuthInfo } type DeleteDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` + + pa.AuthInfo } type MetaDto struct { @@ -123,25 +156,36 @@ type DischargeDto struct { AdmDischargeEducation *string `json:"admDischargeEducation"` DischargeReason *string `json:"dischargeReason"` DeathCause *string `json:"deathCause"` + + pa.AuthInfo } type CheckinDto struct { Id uint `json:"id"` Responsible_Doctor_Code *string `json:"responsible_doctor_code"` - Adm_Employee_Id *uint `json:"adm_employee_id"` + Responsible_Nurse_Code *string `json:"responsible_nurse_code"` StartedAt *time.Time `json:"startedAt"` FinishedAt *time.Time `json:"finishedAt"` + + pa.AuthInfo } type SwitchUnitDto struct { Id uint `json:"id"` PolySwitchCode *ere.PolySwitchCode `json:"polySwitchCode"` InternalReferences *[]eir.CreateDto `json:"internalReferences" validate:"required"` + + Src_Doctor_Code *string `json:"-"` + Src_Nurse_Code *string `json:"-"` + pa.AuthInfo } -type ApproveUnitDto struct { - Id uint `json:"id"` - InternalReferences_Id uint16 `json:"internalReferences_id" validate:"required"` +type ApproveCancelUnitDto struct { + Id uint `json:"id"` + InternalReferences_Id uint `json:"internalReferences_id" validate:"required"` + Dst_Doctor_Code *string `json:"dst_doctor_code"` + + pa.AuthInfo } type ResponseDto struct { @@ -157,7 +201,7 @@ type ResponseDto struct { Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` Unit *eu.Unit `json:"unit,omitempty"` VisitDate time.Time `json:"visitDate"` - PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code"` + PaymentMethod_Code ere.AllPaymentMethodCode `json:"paymentMethod_code"` InsuranceCompany_Code *string `json:"insuranceCompany_code"` Member_Number *string `json:"member_number"` Ref_Number *string `json:"ref_number"` @@ -190,6 +234,8 @@ type ResponseDto struct { Rehab *er.Basic `json:"rehab,omitempty"` RehabChildren *[]er.Basic `json:"rehabChildren,omitempty"` EncounterDocuments *[]eed.EncounterDocument `json:"encounterDocuments,omitempty"` + Responsible_Nurse_Code *string `json:"responsible_nurse_code"` + Responsible_Nurse *en.Nurse `json:"responsible_nurse,omitempty"` } func (d Encounter) ToResponse() ResponseDto { @@ -237,6 +283,8 @@ func (d Encounter) ToResponse() ResponseDto { Rehab: d.Rehab, RehabChildren: d.RehabChildren, EncounterDocuments: d.EncounterDocuments, + Responsible_Nurse_Code: d.Responsible_Nurse_Code, + Responsible_Nurse: d.Responsible_Nurse, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/encounter/entity.go b/internal/domain/main-entities/encounter/entity.go index 3939f546..0b1da159 100644 --- a/internal/domain/main-entities/encounter/entity.go +++ b/internal/domain/main-entities/encounter/entity.go @@ -1,7 +1,13 @@ package encounter import ( + "time" + + erc "simrs-vx/internal/domain/references/common" + ere "simrs-vx/internal/domain/references/encounter" + ecore "simrs-vx/internal/domain/base-entities/core" + evr "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" evs "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" eam "simrs-vx/internal/domain/main-entities/ambulatory" ea "simrs-vx/internal/domain/main-entities/appointment" @@ -10,18 +16,16 @@ import ( eem "simrs-vx/internal/domain/main-entities/emergency" ee "simrs-vx/internal/domain/main-entities/employee" eed "simrs-vx/internal/domain/main-entities/encounter-document" + egc "simrs-vx/internal/domain/main-entities/general-consent" eip "simrs-vx/internal/domain/main-entities/inpatient" ei "simrs-vx/internal/domain/main-entities/insurance-company" eir "simrs-vx/internal/domain/main-entities/internal-reference" + en "simrs-vx/internal/domain/main-entities/nurse" ep "simrs-vx/internal/domain/main-entities/patient" er "simrs-vx/internal/domain/main-entities/rehab/base" es "simrs-vx/internal/domain/main-entities/specialist" ess "simrs-vx/internal/domain/main-entities/subspecialist" eu "simrs-vx/internal/domain/main-entities/unit" - - erc "simrs-vx/internal/domain/references/common" - ere "simrs-vx/internal/domain/references/encounter" - "time" ) type Encounter struct { @@ -39,7 +43,7 @@ type Encounter struct { VisitDate time.Time `json:"visitDate"` StartedAt *time.Time `json:"startedAt"` FinishedAt *time.Time `json:"finishedAt"` - PaymentMethod_Code erc.PaymentMethodCode `json:"paymentMethod_code" gorm:"size:10"` + PaymentMethod_Code ere.AllPaymentMethodCode `json:"paymentMethod_code" gorm:"size:10"` InsuranceCompany_Code *string `json:"insuranceCompany_code"` InsuranceCompany *ei.InsuranceCompany `json:"insuranceCompany,omitempty" gorm:"foreignKey:InsuranceCompany_Code;references:Code"` Member_Number *string `json:"memberNumber" gorm:"unique;size:20"` @@ -72,8 +76,19 @@ type Encounter struct { Rehab *er.Basic `json:"rehab,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` RehabChildren *[]er.Basic `json:"rehabChildren,omitempty" gorm:"foreignKey:Parent_Encounter_Id;references:Id"` EncounterDocuments *[]eed.EncounterDocument `json:"encounterDocuments,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + GeneralConsents *[]egc.GeneralConsent `json:"generalConsents,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + VclaimReference *evr.VclaimReference `json:"vclaimReference,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Responsible_Nurse_Code *string `json:"responsible_nurse_code"` + Responsible_Nurse *en.Nurse `json:"responsible_nurse,omitempty" gorm:"foreignKey:Responsible_Nurse_Code;references:Code"` } func (d Encounter) IsDone() bool { return d.Status_Code == erc.DSCDone } + +func (d Encounter) IsSameResponsibleDoctor(input *string) bool { + if input == nil { + return false + } + return *d.Responsible_Doctor_Code == *input +} diff --git a/internal/domain/main-entities/general-consent/dto.go b/internal/domain/main-entities/general-consent/dto.go new file mode 100644 index 00000000..03dd7dc9 --- /dev/null +++ b/internal/domain/main-entities/general-consent/dto.go @@ -0,0 +1,64 @@ +package generalconsent + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Value *string `json:"value"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter-id"` +} + +type ReadDetailDto struct { + Id uint `json:"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 + Encounter_Id *uint `json:"encounter_id"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl"` +} + +func (d GeneralConsent) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Value: d.Value, + FileUrl: d.FileUrl, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []GeneralConsent) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/general-consent/entity.go b/internal/domain/main-entities/general-consent/entity.go index 96758406..7142f97e 100644 --- a/internal/domain/main-entities/general-consent/entity.go +++ b/internal/domain/main-entities/general-consent/entity.go @@ -1,13 +1,12 @@ -package general_consent +package generalconsent import ( "simrs-vx/internal/domain/base-entities/core" - ee "simrs-vx/internal/domain/main-entities/encounter" ) type GeneralConsent struct { core.Main - Encounter_Id *uint `json:"encounter_id" gorm:"not null"` - Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` - Value *string `json:"value"` + Encounter_Id *uint `json:"encounter_id" gorm:"not null"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl" gorm:"size:1024"` } diff --git a/internal/domain/main-entities/infra/dto.go b/internal/domain/main-entities/infra/dto.go index dfe271e5..63c5d4a4 100644 --- a/internal/domain/main-entities/infra/dto.go +++ b/internal/domain/main-entities/infra/dto.go @@ -3,15 +3,16 @@ package infra import ( ecore "simrs-vx/internal/domain/base-entities/core" ei "simrs-vx/internal/domain/main-entities/item" - erb "simrs-vx/internal/domain/main-entities/room/base" + + erb "simrs-vx/internal/domain/main-entities/procedure-room/base" ero "simrs-vx/internal/domain/references/organization" ) type CreateDto struct { - Code string `json:"code" validate:"maxLength=10"` + Code string `json:"code" validate:"maxLength=20"` Name string `json:"name" validate:"maxLength=50"` - InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code" validate:"maxLength=15"` + InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code" validate:"maxLength=20"` Parent_Code *string `json:"parent_code"` Item_Code *string `json:"-"` Unit_Code *string `json:"unit_code"` @@ -31,7 +32,7 @@ type ReadListDto struct { type FilterDto struct { Code string `json:"code"` Name string `json:"name"` - InfraGroup_Code ero.InfraGroupCode `json:"infraGroup-code"` + InfraGroup_Code ero.InfraGroupCode `json:"infra-group-code"` Parent_Code *string `json:"parent-code"` Item_Id *string `json:"item-code"` Search string `json:"search" gormhelper:"searchColumns=Code,Name"` @@ -69,7 +70,7 @@ type ResponseDto struct { Childrens []Infra `json:"childrens,omitempty"` Item_Code *string `json:"item_code"` Item *ei.Item `json:"item,omitempty"` - Rooms []erb.Basic `json:"rooms,omitempty"` + ProcedureRooms *erb.ProcedureRoom `json:"rooms,omitempty"` } func (d Infra) ToResponse() ResponseDto { @@ -79,10 +80,10 @@ func (d Infra) ToResponse() ResponseDto { InfraGroup_Code: d.InfraGroup_Code, Parent_Code: d.Parent_Code, // Parent: d.Parent, - Childrens: d.Childrens, - Item_Code: d.Item_Code, - Item: d.Item, - Rooms: d.Rooms, + Childrens: d.Childrens, + Item_Code: d.Item_Code, + Item: d.Item, + ProcedureRooms: d.ProcedureRooms, } resp.SmallMain = d.SmallMain return resp diff --git a/internal/domain/main-entities/infra/entity.go b/internal/domain/main-entities/infra/entity.go index 51cc8eaa..b9840db4 100644 --- a/internal/domain/main-entities/infra/entity.go +++ b/internal/domain/main-entities/infra/entity.go @@ -4,20 +4,20 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ei "simrs-vx/internal/domain/main-entities/item" - erb "simrs-vx/internal/domain/main-entities/room/base" + erb "simrs-vx/internal/domain/main-entities/procedure-room/base" ero "simrs-vx/internal/domain/references/organization" ) type Infra struct { ecore.SmallMain // adjust this according to the needs - Code string `json:"code" gorm:"uniqueIndex;size:10;not null"` + Code string `json:"code" gorm:"uniqueIndex;size:20;not null"` Name string `json:"name" gorm:"size:50"` - InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code" gorm:"size:15"` - Parent_Code *string `json:"parent_code" gorm:"size:10"` + InfraGroup_Code ero.InfraGroupCode `json:"infraGroup_code" gorm:"size:20"` + Parent_Code *string `json:"parent_code" gorm:"size:20"` Parent *Infra `json:"parent" gorm:"foreignKey:Parent_Code;references:Code"` Childrens []Infra `json:"childrens" gorm:"foreignKey:Parent_Code;references:Code"` Item_Code *string `json:"item_code" gorm:"size:50"` Item *ei.Item `json:"item,omitempty" gorm:"foreignKey:Item_Code;references:Code"` - Rooms []erb.Basic `json:"rooms" gorm:"foreignKey:Infra_Code;references:Code"` + ProcedureRooms *erb.ProcedureRoom `json:"rooms" gorm:"foreignKey:Infra_Code;references:Code"` } diff --git a/internal/domain/main-entities/installation/dto.go b/internal/domain/main-entities/installation/dto.go index 758efb05..bd6fcc0e 100644 --- a/internal/domain/main-entities/installation/dto.go +++ b/internal/domain/main-entities/installation/dto.go @@ -8,9 +8,10 @@ import ( ) type CreateDto struct { - Code *string `json:"code" validate:"maxLength=10"` + Id *uint `json:"id"` + Code *string `json:"code" validate:"maxLength=20"` Name string `json:"name" validate:"maxLength=50"` - EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code" validate:"maxLength=10"` + EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code" validate:"maxLength=20"` } type ReadListDto struct { diff --git a/internal/domain/main-entities/installation/entity.go b/internal/domain/main-entities/installation/entity.go index 5cc82430..6c3c0ecf 100644 --- a/internal/domain/main-entities/installation/entity.go +++ b/internal/domain/main-entities/installation/entity.go @@ -8,7 +8,7 @@ import ( type Installation struct { ecore.SmallMain // adjust this according to the needs - Code string `json:"code" gorm:"unique;size:10"` + Code string `json:"code" gorm:"unique;size:20"` Name string `json:"name" gorm:"size:50"` EncounterClass_Code ere.EncounterClassCode `json:"encounterClass_code" gorm:"size:10"` InstallationPositions []eipb.Basic `json:"installationPositions,omitempty" gorm:"foreignKey:Installation_Code;references:Code"` diff --git a/internal/domain/main-entities/internal-reference/dto.go b/internal/domain/main-entities/internal-reference/dto.go index 6ce50a77..d3771c4d 100644 --- a/internal/domain/main-entities/internal-reference/dto.go +++ b/internal/domain/main-entities/internal-reference/dto.go @@ -9,10 +9,13 @@ import ( ) type CreateDto struct { - Encounter_Id *uint `json:"-"` - Unit_Code *string `json:"unit_code"` - Doctor_Code *string `json:"doctor_code"` - Status_Code erc.DataApprovalCode `json:"status_code"` + Encounter_Id *uint `json:"-"` + Unit_Code *string `json:"unit_code"` + Doctor_Code *string `json:"doctor_code"` + Nurse_Code *string `json:"nurse_code"` + Status_Code erc.DataApprovalCode `json:"status_code"` + SrcDoctor_Code *string `json:"srcDoctor_code"` + SrcNurse_Code *string `json:"srcNurse_code"` } type ReadListDto struct { @@ -29,17 +32,17 @@ type FilterDto struct { } type ReadDetailDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` Includes string `json:"includes"` } type UpdateDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` CreateDto } type DeleteDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` } type MetaDto struct { diff --git a/internal/domain/main-entities/internal-reference/entity.go b/internal/domain/main-entities/internal-reference/entity.go index ae6307bb..90859710 100644 --- a/internal/domain/main-entities/internal-reference/entity.go +++ b/internal/domain/main-entities/internal-reference/entity.go @@ -5,15 +5,22 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/doctor" + en "simrs-vx/internal/domain/main-entities/nurse" eu "simrs-vx/internal/domain/main-entities/unit" ) type InternalReference struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Unit_Code *string `json:"unit_code"` - Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` - Doctor_Code *string `json:"doctor_code"` - Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` - Status_Code *erc.DataApprovalCode `json:"status_code"` + Encounter_Id *uint `json:"encounter_id"` + Unit_Code *string `json:"unit_code"` + Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` + Doctor_Code *string `json:"doctor_code"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` + Status_Code *erc.DataApprovalCode `json:"status_code"` + SrcDoctor_Code *string `json:"srcDoctor_code"` + SrcDoctor *ed.Doctor `json:"srcDoctor,omitempty" gorm:"foreignKey:SrcDoctor_Code;references:Code"` + SrcNurse_Code *string `json:"srcNurse_code"` + SrcNurse *en.Nurse `json:"srcNurse,omitempty" gorm:"foreignKey:SrcNurse_Code;references:Code"` + Nurse_Code *string `json:"nurse_code"` + Nurse *en.Nurse `json:"nurse,omitempty" gorm:"foreignKey:Nurse_Code;references:Code"` } diff --git a/internal/domain/main-entities/item/dto.go b/internal/domain/main-entities/item/dto.go index f20ce217..a25c5a7a 100644 --- a/internal/domain/main-entities/item/dto.go +++ b/internal/domain/main-entities/item/dto.go @@ -13,6 +13,8 @@ type CreateDto struct { Uom_Code *string `json:"uom_code" validate:"maxLength=10"` Infra_Code *string `json:"infra_code"` Stock *int `json:"stock"` + BuyingPrice *float64 `json:"buyingPrice"` + SellingPrice *float64 `json:"sellingPrice"` } type ReadListDto struct { @@ -33,7 +35,7 @@ type FilterDto struct { } type ReadDetailDto struct { - Id *uint16 `json:"id"` + Id *uint `json:"id"` Code *string `json:"code"` } @@ -62,6 +64,8 @@ type ResponseDto struct { Uom *eu.Uom `json:"uom,omitempty"` Infra_Code *string `json:"infra_code"` Stock *int `json:"stock"` + BuyingPrice *float64 `json:"buyingPrice"` + SellingPrice *float64 `json:"sellingPrice"` } func (d Item) ToResponse() ResponseDto { @@ -73,6 +77,8 @@ func (d Item) ToResponse() ResponseDto { Uom: d.Uom, Infra_Code: d.Infra_Code, Stock: d.Stock, + BuyingPrice: d.BuyingPrice, + SellingPrice: d.SellingPrice, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/item/entity.go b/internal/domain/main-entities/item/entity.go index fc721713..55ca2d18 100644 --- a/internal/domain/main-entities/item/entity.go +++ b/internal/domain/main-entities/item/entity.go @@ -16,4 +16,6 @@ type Item struct { Uom *eu.Uom `json:"uom,omitempty" gorm:"foreignKey:Uom_Code;references:Code"` Infra_Code *string `json:"infra_code" gorm:"size:10"` Stock *int `json:"stock"` + BuyingPrice *float64 `json:"buyingPrice"` + SellingPrice *float64 `json:"settlingPrice"` } diff --git a/internal/domain/main-entities/material-package-item/dto.go b/internal/domain/main-entities/material-package-item/dto.go new file mode 100644 index 00000000..60b7e313 --- /dev/null +++ b/internal/domain/main-entities/material-package-item/dto.go @@ -0,0 +1,73 @@ +package materialpackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + em "simrs-vx/internal/domain/main-entities/material" + emp "simrs-vx/internal/domain/main-entities/material-package" +) + +type CreateDto struct { + MaterialPackage_Code string `json:"materialPackage_code" validate:"maxLength=20"` + Material_Code string `json:"material_code" validate:"maxLength=20"` + Count uint16 `json:"count" validate:"required"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination + Sort string `json:"sort"` +} + +type FilterDto struct { + MaterialPackage_Code string `json:"material-package-code"` + Material_Code string `json:"material_code"` +} + +type ReadDetailDto struct { + Id uint `json:"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 + MaterialPackage_Code string `json:"materialPackage_code"` + MaterialPackage *emp.MaterialPackage `json:"materialPackage,omitempty"` + Material_Code string `json:"material_code"` + Material *em.Material `json:"material,omitempty"` + Count *uint16 `json:"count"` +} + +func (d MaterialPackageItem) ToResponse() ResponseDto { + resp := ResponseDto{ + MaterialPackage_Code: d.MaterialPackage_Code, + MaterialPackage: d.MaterialPackage, + Material_Code: d.Material_Code, + Material: d.Material, + Count: d.Count, + } + resp.Id = d.Id + return resp +} + +func ToResponseList(data []MaterialPackageItem) []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-package-item/entity.go b/internal/domain/main-entities/material-package-item/entity.go new file mode 100644 index 00000000..0c45969b --- /dev/null +++ b/internal/domain/main-entities/material-package-item/entity.go @@ -0,0 +1,16 @@ +package materialpackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + em "simrs-vx/internal/domain/main-entities/material" + emp "simrs-vx/internal/domain/main-entities/material-package" +) + +type MaterialPackageItem struct { + ecore.Main + MaterialPackage_Code string `json:"materialPackage_code" gorm:"size:20;not null"` + MaterialPackage *emp.MaterialPackage `json:"materialPackage" gorm:"foreignKey:MaterialPackage_Code;references:Code"` + Material_Code string `json:"code" gorm:"size:20;not null"` + Material *em.Material `json:"material" gorm:"foreignKey:Material_Code;references:Code"` + Count *uint16 `json:"count"` +} diff --git a/internal/domain/main-entities/material-package/dto.go b/internal/domain/main-entities/material-package/dto.go new file mode 100644 index 00000000..51dc1ab1 --- /dev/null +++ b/internal/domain/main-entities/material-package/dto.go @@ -0,0 +1,66 @@ +package materialpackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code string `json:"code" validate:"maxLength=20"` + Name string `json:"name" validate:"maxLength=50"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination + Sort string `json:"sort"` +} + +type FilterDto struct { + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadDetailDto struct { + Id *uint16 `json:"id"` + Code *string `json:"code"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id *uint16 `json:"id"` + 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"` +} + +func (d MaterialPackage) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []MaterialPackage) []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-package/entity.go b/internal/domain/main-entities/material-package/entity.go new file mode 100644 index 00000000..4f3feeab --- /dev/null +++ b/internal/domain/main-entities/material-package/entity.go @@ -0,0 +1,11 @@ +package materialpackage + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type MaterialPackage struct { + ecore.SmallMain + Code string `json:"code" gorm:"unique;size:20;not null"` + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/domain/main-entities/mcu-order-item/base/entity.go b/internal/domain/main-entities/mcu-order-item/base/entity.go new file mode 100644 index 00000000..dcfb0625 --- /dev/null +++ b/internal/domain/main-entities/mcu-order-item/base/entity.go @@ -0,0 +1,20 @@ +package mcuorderitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ems "simrs-vx/internal/domain/main-entities/mcu-src" + "time" + + erc "simrs-vx/internal/domain/references/common" +) + +type McuOrderItem struct { + ecore.Main // adjust this according to the needs + McuOrder_Id *uint `json:"mcuOrder_id" gorm:"uniqueIndex:idx_order_src"` + McuSrc_Code *string `json:"mcuSrc_code" gorm:"uniqueIndex:idx_order_src"` + McuSrc *ems.McuSrc `json:"mcuSrc,omitempty" gorm:"foreignKey:McuSrc_Code;references:Code"` + ExaminationDate *time.Time `json:"examinationDate"` + Note *string `json:"note" gorm:"size:1024"` + Result *string `json:"result"` + Status_Code erc.DataStatusCode `json:"status_code"` +} diff --git a/internal/domain/main-entities/mcu-order-item/entity.go b/internal/domain/main-entities/mcu-order-item/entity.go index 97384243..7d4d757d 100644 --- a/internal/domain/main-entities/mcu-order-item/entity.go +++ b/internal/domain/main-entities/mcu-order-item/entity.go @@ -1,23 +1,17 @@ package mcuorderitem import ( - ecore "simrs-vx/internal/domain/base-entities/core" emo "simrs-vx/internal/domain/main-entities/mcu-order" - ems "simrs-vx/internal/domain/main-entities/mcu-src" - "time" + emoib "simrs-vx/internal/domain/main-entities/mcu-order-item/base" + emosi "simrs-vx/internal/domain/main-entities/mcu-order-sub-item/base" erc "simrs-vx/internal/domain/references/common" ) type McuOrderItem struct { - ecore.Main // adjust this according to the needs - McuOrder_Id *uint `json:"mcuOrder_id" gorm:"uniqueIndex:idx_order_src"` - McuOrder *emo.McuOrder `json:"mcuOrder,omitempty" gorm:"foreignKey:McuOrder_Id;references:Id"` - McuSrc_Code *string `json:"mcuSrc_code" gorm:"uniqueIndex:idx_order_src"` - McuSrc *ems.McuSrc `json:"mcuSrc,omitempty" gorm:"foreignKey:McuSrc_Code;references:Code"` - ExaminationDate *time.Time `json:"examinationDate"` - Result *string `json:"result"` - Status_Code erc.DataStatusCode `json:"status_code"` + emoib.McuOrderItem + McuOrder *emo.McuOrder `json:"mcuOrder,omitempty" gorm:"foreignKey:McuOrder_Id;references:Id"` + Items []*emosi.McuOrderSubItem `json:"items" gorm:"foreignKey:McuOrderItem_Id;references:Id"` } func (d McuOrderItem) IsCompleted() bool { diff --git a/internal/domain/main-entities/mcu-order-sub-item/base/entity.go b/internal/domain/main-entities/mcu-order-sub-item/base/entity.go new file mode 100644 index 00000000..0022744b --- /dev/null +++ b/internal/domain/main-entities/mcu-order-sub-item/base/entity.go @@ -0,0 +1,15 @@ +package mcuordersubitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + + erc "simrs-vx/internal/domain/references/common" +) + +type McuOrderSubItem struct { + ecore.Main // adjust this according to the needs + McuSubSrc_Code *string `json:"mcuSubSrc_code" gorm:"uniqueIndex:idx_order_sub_src"` + McuOrderItem_Id *uint `json:"mcuOrderItem_id" gorm:"uniqueIndex:idx_order_sub_src"` + Result *string `json:"result"` + Status_Code erc.DataStatusCode `json:"status_code"` +} diff --git a/internal/domain/main-entities/mcu-order-sub-item/entity.go b/internal/domain/main-entities/mcu-order-sub-item/entity.go index a9bde496..b594a91b 100644 --- a/internal/domain/main-entities/mcu-order-sub-item/entity.go +++ b/internal/domain/main-entities/mcu-order-sub-item/entity.go @@ -5,17 +5,15 @@ import ( emoi "simrs-vx/internal/domain/main-entities/mcu-order-item" emss "simrs-vx/internal/domain/main-entities/mcu-sub-src" + emosi "simrs-vx/internal/domain/main-entities/mcu-order-sub-item/base" erc "simrs-vx/internal/domain/references/common" ) type McuOrderSubItem struct { - ecore.Main // adjust this according to the needs - McuSubSrc_Code *string `json:"mcuSubSrc_code" gorm:"uniqueIndex:idx_order_sub_src"` - McuSubSrc *emss.McuSubSrc `json:"mcuSubSrc,omitempty" gorm:"foreignKey:McuSubSrc_Code;references:Code"` - McuOrderItem_Id *uint `json:"mcuOrderItem_id" gorm:"uniqueIndex:idx_order_sub_src"` - McuOrderItem *emoi.McuOrderItem `json:"mcuOrderItem,omitempty" gorm:"foreignKey:McuOrderItem_Id;references:Id"` - Result *string `json:"result"` - Status_Code erc.DataStatusCode `json:"status_code"` + ecore.Main // adjust this according to the needs + McuSubSrc *emss.McuSubSrc `json:"mcuSubSrc,omitempty" gorm:"foreignKey:McuSubSrc_Code;references:Code"` + McuOrderItem *emoi.McuOrderItem `json:"mcuOrderItem,omitempty" gorm:"foreignKey:McuOrderItem_Id;references:Id"` + emosi.McuOrderSubItem } func (d McuOrderSubItem) IsCompleted() bool { diff --git a/internal/domain/main-entities/mcu-order/dto.go b/internal/domain/main-entities/mcu-order/dto.go index 594f72d7..2835ce2c 100644 --- a/internal/domain/main-entities/mcu-order/dto.go +++ b/internal/domain/main-entities/mcu-order/dto.go @@ -17,6 +17,7 @@ import ( // internal - domain - main-entities ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" + emoib "simrs-vx/internal/domain/main-entities/mcu-order-item/base" ) type CreateDto struct { @@ -85,7 +86,8 @@ type ResponseDto struct { ExaminationDate *time.Time `json:"examinationDate"` Number uint8 `json:"number"` Temperature float64 `json:"temperature"` - UrgencyLevel_Code ercl.McuUrgencyLevelCode `json:"urgencyLevel_code""` + UrgencyLevel_Code ercl.McuUrgencyLevelCode `json:"urgencyLevel_code"` + Items []*emoib.McuOrderItem `json:"items"` } func (d McuOrder) ToResponse() ResponseDto { @@ -100,6 +102,7 @@ func (d McuOrder) ToResponse() ResponseDto { Number: d.Number, Temperature: d.Temperature, UrgencyLevel_Code: d.UrgencyLevel_Code, + Items: d.Items, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/mcu-order/entity.go b/internal/domain/main-entities/mcu-order/entity.go index b9e5d0d7..81fb7495 100644 --- a/internal/domain/main-entities/mcu-order/entity.go +++ b/internal/domain/main-entities/mcu-order/entity.go @@ -4,6 +4,7 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" + emoib "simrs-vx/internal/domain/main-entities/mcu-order-item/base" "time" ercl "simrs-vx/internal/domain/references/clinical" @@ -23,6 +24,11 @@ type McuOrder struct { Temperature float64 `json:"temperature"` UrgencyLevel_Code ercl.McuUrgencyLevelCode `json:"urgencyLevel_code" gorm:"not null;size:15"` Scope_Code ercl.McuScopeCode `json:"scope_code" gorm:"index;size:10"` + Items []*emoib.McuOrderItem `json:"items" gorm:"foreignKey:McuOrder_Id;references:Id"` +} + +func (d McuOrder) IsNotNew() bool { + return d.Status_Code != erc.DSCNew } func (d McuOrder) IsCompleted() bool { diff --git a/internal/domain/main-entities/mcu-src-category/dto.go b/internal/domain/main-entities/mcu-src-category/dto.go index f9bb7d00..e1ef57d9 100644 --- a/internal/domain/main-entities/mcu-src-category/dto.go +++ b/internal/domain/main-entities/mcu-src-category/dto.go @@ -1,4 +1,4 @@ -package division +package mcusrccategory import ( ecore "simrs-vx/internal/domain/base-entities/core" @@ -20,10 +20,10 @@ type ReadListDto struct { } type FilterDto struct { - Code string `json:"code"` - Name string `json:"name"` - Scope_Code *erc.McuScopeCode `json:"scope-code"` - Search string `json:"search" gormhelper:"searchColumns=Code,Name"` + Code *string `json:"code"` + Name *string `json:"name"` + Scope_Code *string `json:"scope-code"` + Search string `json:"search" gormhelper:"searchColumns=Code,Name"` } type ReadDetailDto struct { diff --git a/internal/domain/main-entities/mcu-src-category/entity.go b/internal/domain/main-entities/mcu-src-category/entity.go index 8fc801b9..2175552c 100644 --- a/internal/domain/main-entities/mcu-src-category/entity.go +++ b/internal/domain/main-entities/mcu-src-category/entity.go @@ -1,4 +1,4 @@ -package division +package mcusrccategory import ( ecore "simrs-vx/internal/domain/base-entities/core" diff --git a/internal/domain/main-entities/medicine-form/dto.go b/internal/domain/main-entities/medicine-form/dto.go new file mode 100644 index 00000000..a7145a2f --- /dev/null +++ b/internal/domain/main-entities/medicine-form/dto.go @@ -0,0 +1,67 @@ +package medicineform + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Code *string `json:"code" validate:"maxLength=20"` + Name string `json:"name" validate:"maxLength=50"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Sort string `json:"sort"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Code string `json:"code"` + Name string `json:"name"` + Search string `json:"search" gormhelper:"searchColumns=Code,Name"` +} + +type ReadDetailDto struct { + Id *uint16 `json:"id"` + Code *string `json:"code"` +} + +type UpdateDto struct { + Id *uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id *uint `json:"id"` + 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"` +} + +func (d MedicineForm) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: d.Code, + Name: d.Name, + } + resp.SmallMain = d.SmallMain + return resp +} + +func ToResponseList(data []MedicineForm) []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-form/entity.go b/internal/domain/main-entities/medicine-form/entity.go new file mode 100644 index 00000000..75b1b104 --- /dev/null +++ b/internal/domain/main-entities/medicine-form/entity.go @@ -0,0 +1,11 @@ +package medicineform + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type MedicineForm 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/medicine/dto.go b/internal/domain/main-entities/medicine/dto.go index 945db1e5..71d41d42 100644 --- a/internal/domain/main-entities/medicine/dto.go +++ b/internal/domain/main-entities/medicine/dto.go @@ -4,6 +4,7 @@ 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" + emf "simrs-vx/internal/domain/main-entities/medicine-form" 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" @@ -71,6 +72,8 @@ type ResponseDto struct { MedicineGroup *emg.MedicineGroup `json:"medicineGroup"` MedicineMethod_Code *string `json:"medicineMethod_code"` MedicineMethod *emm.MedicineMethod `json:"medicineMethod"` + MedicineForm_Code *string `json:"medicineForm_code"` + MedicineForm *emf.MedicineForm `json:"medicineForm"` Uom_Code *string `json:"uom_code"` Uom *eu.Uom `json:"uom"` Dose uint8 `json:"dose"` @@ -89,6 +92,8 @@ func (d Medicine) ToResponse() ResponseDto { MedicineGroup: d.MedicineGroup, MedicineMethod_Code: d.MedicineMethod_Code, MedicineMethod: d.MedicineMethod, + MedicineForm_Code: d.MedicineForm_Code, + MedicineForm: d.MedicineForm, Uom_Code: d.Uom_Code, Uom: d.Uom, Dose: d.Dose, diff --git a/internal/domain/main-entities/medicine/entity.go b/internal/domain/main-entities/medicine/entity.go index dda220bc..0a79e7e5 100644 --- a/internal/domain/main-entities/medicine/entity.go +++ b/internal/domain/main-entities/medicine/entity.go @@ -4,6 +4,7 @@ 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" + emf "simrs-vx/internal/domain/main-entities/medicine-form" 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" @@ -17,6 +18,8 @@ type Medicine struct { 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"` + MedicineForm_Code *string `json:"medicineForm_code" gorm:"size:20"` + MedicineForm *emf.MedicineForm `json:"medicineForm,omitempty" gorm:"foreignKey:MedicineForm_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"` diff --git a/internal/domain/main-entities/micro-mcu-order-item/base/dto.go b/internal/domain/main-entities/micro-mcu-order-item/base/dto.go new file mode 100644 index 00000000..56827131 --- /dev/null +++ b/internal/domain/main-entities/micro-mcu-order-item/base/dto.go @@ -0,0 +1,6 @@ +package micromcuorderitem + +type SubCreateDto struct { + McuSrc_Code string `json:"mcuSrc_code" validate:"required"` + Note string `json:"note"` +} diff --git a/internal/domain/main-entities/micro-mcu-order-item/base/entity.go b/internal/domain/main-entities/micro-mcu-order-item/base/entity.go new file mode 100644 index 00000000..c9d91561 --- /dev/null +++ b/internal/domain/main-entities/micro-mcu-order-item/base/entity.go @@ -0,0 +1,17 @@ +package micromcuorderitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ems "simrs-vx/internal/domain/main-entities/mcu-src" + erc "simrs-vx/internal/domain/references/common" +) + +type MicroMcuOrderItem struct { + ecore.BigMain // adjust this according to the needs + MicroMcuOrder_Id uint64 `json:"microMcuOrder_id" gorm:"uniqueIndex:idx_order_src"` + McuSrc_Code string `json:"mcuSrc_code" gorm:"uniqueIndex:idx_order_src"` + McuSrc *ems.McuSrc `json:"mcuSrc,omitempty" gorm:"foreignKey:McuSrc_Code;references:Code"` + Note *string `json:"note" gorm:"size:1024"` + Result *string `json:"result"` + Status_Code erc.DataStatusCode `json:"status_code"` +} diff --git a/internal/domain/main-entities/micro-mcu-order-item/dto.go b/internal/domain/main-entities/micro-mcu-order-item/dto.go new file mode 100644 index 00000000..1d2ceaeb --- /dev/null +++ b/internal/domain/main-entities/micro-mcu-order-item/dto.go @@ -0,0 +1,80 @@ +package micromcuorderitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ems "simrs-vx/internal/domain/main-entities/mcu-src" + emro "simrs-vx/internal/domain/main-entities/micro-mcu-order" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type CreateDto struct { + MicroMcuOrder_Id uint64 `json:"microMcuOrder_id"` + McuSrc_Code string `json:"mcuSrc_code"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + MicroMcuOrder_Id *uint64 `json:"micro-mcu-order-id"` + McuSrc_Code *string `json:"mcu-src-code"` + Status_Code erc.DataStatusCode `json:"status-code"` +} +type ReadDetailDto struct { + Id uint `json:"id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type SetScheduleDto struct { + Id uint `json:"id"` + ExaminationDate *time.Time `json:"examinationDate"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.BigMain + MicroMcuOrder_Id uint64 `json:"microMcuOrder_id"` + MicroMcuOrder *emro.MicroMcuOrder `json:"microMcuOrder,omitempty"` + McuSrc_Code string `json:"mcuSrc_code"` + McuSrc *ems.McuSrc `json:"mcuSrc,omitempty"` + Result *string `json:"result"` + Status_Code erc.DataStatusCode `json:"status_code"` +} + +func (d MicroMcuOrderItem) ToResponse() ResponseDto { + resp := ResponseDto{ + MicroMcuOrder_Id: d.MicroMcuOrder_Id, + MicroMcuOrder: d.MicroMcuOrder, + McuSrc_Code: d.McuSrc_Code, + McuSrc: d.McuSrc, + Result: d.Result, + Status_Code: d.Status_Code, + } + resp.BigMain = d.BigMain + return resp +} + +func ToResponseList(data []MicroMcuOrderItem) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/micro-mcu-order-item/entity.go b/internal/domain/main-entities/micro-mcu-order-item/entity.go new file mode 100644 index 00000000..64d701f7 --- /dev/null +++ b/internal/domain/main-entities/micro-mcu-order-item/entity.go @@ -0,0 +1,18 @@ +package micromcuorderitem + +import ( + ems "simrs-vx/internal/domain/main-entities/mcu-src" + emo "simrs-vx/internal/domain/main-entities/micro-mcu-order" + emoib "simrs-vx/internal/domain/main-entities/micro-mcu-order-item/base" + erc "simrs-vx/internal/domain/references/common" +) + +type MicroMcuOrderItem struct { + emoib.MicroMcuOrderItem + MicroMcuOrder *emo.MicroMcuOrder `json:"microMcuOrder,omitempty" gorm:"foreignKey:MicroMcuOrder_Id;references:Id"` + McuSrc *ems.McuSrc `json:"mcuSrc,omitempty" gorm:"foreignKey:McuSrc_Code;references:Code"` +} + +func (d MicroMcuOrderItem) IsCompleted() bool { + return d.Status_Code == erc.DSCDone +} diff --git a/internal/domain/main-entities/micro-mcu-order/base/entity.go b/internal/domain/main-entities/micro-mcu-order/base/entity.go new file mode 100644 index 00000000..3e611d81 --- /dev/null +++ b/internal/domain/main-entities/micro-mcu-order/base/entity.go @@ -0,0 +1,18 @@ +package micromcuorder + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ercl "simrs-vx/internal/domain/references/clinical" + erc "simrs-vx/internal/domain/references/common" +) + +type MicroMcuOrder struct { + ecore.BigMain + Encounter_Id uint `json:"encounter_id"` + Number uint64 `json:"number"` + Doctor_Code string `json:"doctor_code" gorm:"unique;size:20"` + Stage_Code ercl.McuOrderStageCode `json:"stage_code" gorm:"not null;size:10"` + AxillaryTemp float64 `json:"axillaryTemp"` + OtherNotes *string `json:"otherNotes"` + Status_Code erc.DataStatusCode `json:"status_code" gorm:"not null;size:10"` +} diff --git a/internal/domain/main-entities/micro-mcu-order/dto.go b/internal/domain/main-entities/micro-mcu-order/dto.go new file mode 100644 index 00000000..008f219f --- /dev/null +++ b/internal/domain/main-entities/micro-mcu-order/dto.go @@ -0,0 +1,86 @@ +package micromcuorder + +import ( + la "simrs-vx/internal/lib/auth" + + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" + ercl "simrs-vx/internal/domain/references/clinical" +) + +type CreateDto struct { + Encounter_Id uint `json:"encounter_id" validate:"required"` + Number uint64 `json:"number"` // SHOULD BE AUTOMATIC WITHOUT SYNC + OrderStage_Code string `json:"orderStage_code" gorm:"not null;size:10"` + AxillaryTemp float64 `json:"axillaryTemp"` + OtherNotes string `json:"otherNotes"` + la.AuthInfo +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Sort string `json:"sort"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id uint `json:"encounter-id"` + Doctor_Code string `json:"doctor-code"` +} + +type ReadDetailDto struct { + Id uint64 `json:"id"` + Includes string `json:"includes"` +} + +type UpdateDto struct { + Id uint64 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint64 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.BigMain + Encounter_Id uint + Encounter *ee.Encounter + Number uint64 `json:"number"` + Doctor_Code string `json:"doctor_code"` + Doctor *ed.Doctor + Stage_Code ercl.McuOrderStageCode `json:"stage_code" gorm:"not null;size:10"` + AxillaryTemp float64 `json:"axillaryTemp"` + OtherNotes *string `json:"otherNotes"` +} + +func (d MicroMcuOrder) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Number: d.Number, + Doctor_Code: d.Doctor_Code, + Doctor: d.Doctor, + Stage_Code: d.Stage_Code, + AxillaryTemp: d.AxillaryTemp, + OtherNotes: d.OtherNotes, + } + resp.BigMain = d.BigMain + return resp +} + +func ToResponseList(data []MicroMcuOrder) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/micro-mcu-order/entity.go b/internal/domain/main-entities/micro-mcu-order/entity.go new file mode 100644 index 00000000..57550c84 --- /dev/null +++ b/internal/domain/main-entities/micro-mcu-order/entity.go @@ -0,0 +1,28 @@ +package micromcuorder + +import ( + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" + emmoi "simrs-vx/internal/domain/main-entities/micro-mcu-order-item/base" + eamob "simrs-vx/internal/domain/main-entities/micro-mcu-order/base" + erc "simrs-vx/internal/domain/references/common" +) + +type MicroMcuOrder struct { + eamob.MicroMcuOrder + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` + Items []*emmoi.MicroMcuOrderItem `json:"items" gorm:"foreignKey:MicroMcuOrder_Id;references:Id"` +} + +func (d MicroMcuOrder) IsNotNew() bool { + return d.Status_Code != erc.DSCNew +} + +func (d MicroMcuOrder) IsCompleted() bool { + return d.Status_Code == erc.DSCDone +} + +func (d MicroMcuOrder) IsSameDoctor(doctor_code *string) bool { + return d.Doctor_Code == *doctor_code +} diff --git a/internal/domain/main-entities/patient/dto.go b/internal/domain/main-entities/patient/dto.go index dd6c1f00..248a7164 100644 --- a/internal/domain/main-entities/patient/dto.go +++ b/internal/domain/main-entities/patient/dto.go @@ -12,7 +12,7 @@ import ( epr "simrs-vx/internal/domain/main-entities/person-relative" erc "simrs-vx/internal/domain/references/common" - eru "simrs-vx/internal/domain/references/upload" + ere "simrs-vx/internal/domain/references/encounter" pa "simrs-vx/internal/lib/auth" ) @@ -28,6 +28,7 @@ type CreateDto struct { RegisteredAt *time.Time `json:"registeredAt"` RegisteredBy_User_Name *string `json:"registeredBy_user_name" validate:"maxLength=100"` Status_Code erc.ActiveStatusCode `json:"status_code" validate:"maxLength=10"` + Number *string `json:"number"` pa.AuthInfo } @@ -59,6 +60,7 @@ type UpdateDto struct { type DeleteDto struct { Id uint `json:"id"` + pa.AuthInfo } type SearchDto struct { @@ -68,7 +70,7 @@ type SearchDto struct { type UploadDto struct { Id uint `json:"-"` - Code eru.UploadCode `json:"-"` + Code ere.DocTypeCode `json:"-"` File multipart.File `json:"-"` FileHeader *multipart.FileHeader `json:"-"` Filename string `json:"-"` diff --git a/internal/domain/main-entities/patient/entity.go b/internal/domain/main-entities/patient/entity.go index 83afa6ce..fc6d8833 100644 --- a/internal/domain/main-entities/patient/entity.go +++ b/internal/domain/main-entities/patient/entity.go @@ -15,7 +15,7 @@ type Patient struct { RegisteredAt *time.Time `json:"registeredAt"` RegisteredBy_User_Name *string `json:"registeredBy_user_name" gorm:"size:100"` Status_Code erc.ActiveStatusCode `json:"status_code" gorm:"not null;size:10"` - Number *string `json:"number" gorm:"unique;size:15"` + Number *string `json:"number" gorm:"size:15;unique"` Parent_Number *string `json:"parent_number"` Parent *Patient `json:"parent,omitempty" gorm:"foreignKey:Parent_Number;references:Number"` } diff --git a/internal/domain/main-entities/person-address/base/entity.go b/internal/domain/main-entities/person-address/base/entity.go new file mode 100644 index 00000000..65d71912 --- /dev/null +++ b/internal/domain/main-entities/person-address/base/entity.go @@ -0,0 +1,22 @@ +package personaddress + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + epr "simrs-vx/internal/domain/main-entities/postal-region" + ev "simrs-vx/internal/domain/main-entities/village" + + erp "simrs-vx/internal/domain/references/person" +) + +type PersonAddress struct { + ecore.Main // adjust this according to the needs + Person_Id uint `json:"person_id"` + Address string `json:"address" gorm:"size:150"` + LocationType_Code erp.AddressLocationTypeCode `json:"locationType_code" gorm:"size:10"` + Rt string `json:"rt" gorm:"size:2"` + Rw string `json:"rw" gorm:"size:2"` + PostalRegion_Code *string `json:"postalRegion_code" gorm:"size:6"` + PostalRegion *epr.PostalRegion `json:"postalRegion,omitempty" gorm:"foreignKey:PostalRegion_Code;references:Code"` + Village_Code *string `json:"village_code" gorm:"size:10"` + Village *ev.Village `json:"village,omitempty" gorm:"foreignKey:Village_Code;references:Code"` +} diff --git a/internal/domain/main-entities/person-address/entity.go b/internal/domain/main-entities/person-address/entity.go index 65d71912..f53e2859 100644 --- a/internal/domain/main-entities/person-address/entity.go +++ b/internal/domain/main-entities/person-address/entity.go @@ -1,22 +1,9 @@ package personaddress import ( - ecore "simrs-vx/internal/domain/base-entities/core" - epr "simrs-vx/internal/domain/main-entities/postal-region" - ev "simrs-vx/internal/domain/main-entities/village" - - erp "simrs-vx/internal/domain/references/person" + eb "simrs-vx/internal/domain/main-entities/person-address/base" ) type PersonAddress struct { - ecore.Main // adjust this according to the needs - Person_Id uint `json:"person_id"` - Address string `json:"address" gorm:"size:150"` - LocationType_Code erp.AddressLocationTypeCode `json:"locationType_code" gorm:"size:10"` - Rt string `json:"rt" gorm:"size:2"` - Rw string `json:"rw" gorm:"size:2"` - PostalRegion_Code *string `json:"postalRegion_code" gorm:"size:6"` - PostalRegion *epr.PostalRegion `json:"postalRegion,omitempty" gorm:"foreignKey:PostalRegion_Code;references:Code"` - Village_Code *string `json:"village_code" gorm:"size:10"` - Village *ev.Village `json:"village,omitempty" gorm:"foreignKey:Village_Code;references:Code"` + eb.PersonAddress } diff --git a/internal/domain/main-entities/person-contact/base/entity.go b/internal/domain/main-entities/person-contact/base/entity.go new file mode 100644 index 00000000..b39aa53e --- /dev/null +++ b/internal/domain/main-entities/person-contact/base/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-contact/entity.go b/internal/domain/main-entities/person-contact/entity.go index b39aa53e..3ba257c4 100644 --- a/internal/domain/main-entities/person-contact/entity.go +++ b/internal/domain/main-entities/person-contact/entity.go @@ -1,13 +1,9 @@ package personcontact import ( - ecore "simrs-vx/internal/domain/base-entities/core" - erp "simrs-vx/internal/domain/references/person" + eb "simrs-vx/internal/domain/main-entities/person-contact/base" ) 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"` + eb.PersonContact } diff --git a/internal/domain/main-entities/person/dto.go b/internal/domain/main-entities/person/dto.go index 588379df..dbab95b0 100644 --- a/internal/domain/main-entities/person/dto.go +++ b/internal/domain/main-entities/person/dto.go @@ -19,6 +19,7 @@ type CreateDto struct { FrontTitle *string `json:"frontTitle" validate:"maxLength=50"` EndTitle *string `json:"endTitle" validate:"maxLength=50"` BirthDate *time.Time `json:"birthDate,omitempty"` + BirthPlace *string `json:"birthPlace" validate:"maxLength=4"` BirthRegency_Code *string `json:"birthRegency_code" validate:"maxLength=4"` Gender_Code *erp.GenderCode `json:"gender_code"` ResidentIdentityNumber *string `json:"residentIdentityNumber" validate:"nik;maxLength=16"` @@ -46,14 +47,13 @@ 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"` + FrontTitle *string `json:"front-title"` + EndTitle *string `json:"end-title"` + BirthDate *time.Time `json:"birth-date,omitempty"` Gender_Code *erp.GenderCode `json:"gender-code"` - ResidentIdentityNumber *string `json:"residentIdentityNumber"` - PassportNumber *string `json:"passportNumber"` - DrivingLicenseNumber *string `json:"drivingLicenseNumber"` + ResidentIdentityNumber *string `json:"resident-identity-number"` + PassportNumber *string `json:"passport-number"` + DrivingLicenseNumber *string `json:"driving-license-number"` Religion_Code *erp.ReligionCode `json:"religion-code"` Education_Code *erp.EducationCode `json:"education-code"` Ocupation_Code *erp.OcupationCode `json:"occupation-code"` @@ -61,7 +61,7 @@ type FilterDto struct { Nationality *string `json:"nationality"` Ethnic_Code *string `json:"ethnic-code"` Language_Code *string `json:"language-code"` - CommunicationIssueStatus bool `json:"communicationIssueStatus"` + CommunicationIssueStatus bool `json:"communication-issue-status"` Disability *string `json:"disability"` } @@ -94,6 +94,7 @@ type ResponseDto struct { FrontTitle *string `json:"frontTitle"` EndTitle *string `json:"endTitle"` BirthDate *time.Time `json:"birthDate,omitempty"` + BirthPlace *string `json:"birthPlace"` BirthRegency_Code *string `json:"birthRegency_code"` BirthRegency *er.Regency `json:"birthRegency,omitempty"` Gender_Code *erp.GenderCode `json:"gender_code"` @@ -128,6 +129,7 @@ func (d *Person) ToResponse() ResponseDto { FrontTitle: d.FrontTitle, EndTitle: d.EndTitle, BirthDate: d.BirthDate, + BirthPlace: d.BirthPlace, BirthRegency_Code: d.BirthRegency_Code, BirthRegency: d.BirthRegency, Gender_Code: d.Gender_Code, diff --git a/internal/domain/main-entities/person/entity.go b/internal/domain/main-entities/person/entity.go index d6e6744a..10626229 100644 --- a/internal/domain/main-entities/person/entity.go +++ b/internal/domain/main-entities/person/entity.go @@ -10,6 +10,7 @@ import ( epi "simrs-vx/internal/domain/main-entities/person-insurance" epr "simrs-vx/internal/domain/main-entities/person-relative" er "simrs-vx/internal/domain/main-entities/regency" + "strings" erp "simrs-vx/internal/domain/references/person" @@ -22,19 +23,20 @@ type Person struct { FrontTitle *string `json:"frontTitle" gorm:"size:50"` EndTitle *string `json:"endTitle" gorm:"size:50"` BirthDate *time.Time `json:"birthDate,omitempty"` + BirthPlace *string `json:"birthPlace,omitempty"` BirthRegency_Code *string `json:"birthRegency_code" gorm:"size:4"` BirthRegency *er.Regency `json:"birthRegency,omitempty" gorm:"foreignKey:BirthRegency_Code;references:Code"` Gender_Code *erp.GenderCode `json:"gender_code" gorm:"size:10"` - ResidentIdentityNumber *string `json:"residentIdentityNumber" gorm:"unique;size:16"` - PassportNumber *string `json:"passportNumber" gorm:"unique;size:20"` - DrivingLicenseNumber *string `json:"drivingLicenseNumber" gorm:"unique;size:20"` + ResidentIdentityNumber *string `json:"residentIdentityNumber" gorm:"uniqueIndex:idx_resident_identity,where:\"DeletedAt\" IS NULL;size:16"` + PassportNumber *string `json:"passportNumber" gorm:"uniqueIndex:idx_passport,where:\"DeletedAt\" IS NULL;size:20"` + DrivingLicenseNumber *string `json:"drivingLicenseNumber" gorm:"uniqueIndex:idx_driver_license,where:\"DeletedAt\" IS NULL;size:20"` Religion_Code *erp.ReligionCode `json:"religion_code" gorm:"size:10"` Confidence *string `json:"confidence" gorm:"size:512"` 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"` MaritalStatus_Code *erp.MaritalStatusCode `json:"maritalStatus_code" gorm:"size:10"` - Nationality *string `json:"nationality": gorm:"size:50"` + Nationality *string `json:"nationality" gorm:"size:50"` Ethnic_Code *string `json:"ethnic_code" gorm:"size:20"` Ethnic *ee.Ethnic `json:"ethnic,omitempty" gorm:"foreignKey:Ethnic_Code;references:Code"` Language_Code *string `json:"language_code" gorm:"size:10"` @@ -58,3 +60,62 @@ func (d Person) IsSameResidentIdentityNumber(input *string) bool { } return d.ResidentIdentityNumber == input } + +func (d Person) GenderString() string { + if d.Gender_Code == nil { + return "" + } + switch *d.Gender_Code { + case erp.GCMale: + return "Laki-laki(L)" + case erp.GCFemale: + return "Perempuan(P)" + default: + return "" + } +} + +func (d Person) GetPhoneNumber() string { + if d.Contacts == nil { + return "" + } + for _, c := range *d.Contacts { + if c.Type_Code == erp.CTPhone || c.Type_Code == erp.CTMPhone { + return c.Value + } + } + return "" +} + +func (d Person) FullName() string { + name := strings.TrimSpace(d.Name) + if name == "" { + return "" + } + + parts := []string{} + + // Front title (dr., drs., etc) + if d.FrontTitle != nil { + ft := strings.TrimSpace(*d.FrontTitle) + if ft != "" { + parts = append(parts, ft) + } + } + + // Name (always included) + parts = append(parts, name) + + // Join front title + name + full := strings.Join(parts, " ") + + // End title → attach with comma + if d.EndTitle != nil { + et := strings.TrimSpace(*d.EndTitle) + if et != "" { + full = full + ", " + et + } + } + + return full +} diff --git a/internal/domain/main-entities/prescription-item/base/entity.go b/internal/domain/main-entities/prescription-item/base/entity.go new file mode 100644 index 00000000..a5cb5c44 --- /dev/null +++ b/internal/domain/main-entities/prescription-item/base/entity.go @@ -0,0 +1,25 @@ +package prescriptionitem + +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" + + erc "simrs-vx/internal/domain/references/common" +) + +type PrescriptionItem struct { + ecore.Main // adjust this according to the needs + Prescription_Id *uint `json:"prescription_id"` + IsMix bool `json:"isMix"` + Medicine_Code *string `json:"medicine_code"` + Medicine *em.Medicine `json:"medicine,omitempty" gorm:"foreignKey:Medicine_Code;references:Code"` + MedicineMix_Id *uint `json:"medicineMix_id"` + MedicineMix *emm.MedicineMix `json:"medicineMix,omitempty" gorm:"foreignKey:MedicineMix_Id;references:Id"` + Frequency *uint16 `json:"frequency"` + Dose float64 `json:"dose"` + Usage string `json:"usage" gorm:"size:255"` + Interval uint8 `json:"interval"` + IntervalUnit_Code erc.TimeUnitCode `json:"intervalUnit_code"` + Quantity float64 `json:"quantity"` +} diff --git a/internal/domain/main-entities/prescription-item/dto.go b/internal/domain/main-entities/prescription-item/dto.go index 33e63ed2..44619ec8 100644 --- a/internal/domain/main-entities/prescription-item/dto.go +++ b/internal/domain/main-entities/prescription-item/dto.go @@ -19,7 +19,7 @@ type CreateDto struct { Usage string `json:"usage"` Interval uint8 `json:"interval"` IntervalUnit_Code erc.TimeUnitCode `json:"intervalUnit_code"` - IntervalMultiplier *uint16 `json:"intervalMultiplier" validate:"required"` + IntervalMultiplier *uint16 `json:"intervalMultiplier"` Quantity float64 `json:"quantity"` } @@ -27,6 +27,7 @@ type ReadListDto struct { FilterDto Includes string `json:"includes"` Pagination ecore.Pagination + Sort string `json:"sort"` } type FilterDto struct { diff --git a/internal/domain/main-entities/prescription-item/entity.go b/internal/domain/main-entities/prescription-item/entity.go index 93174079..465059d7 100644 --- a/internal/domain/main-entities/prescription-item/entity.go +++ b/internal/domain/main-entities/prescription-item/entity.go @@ -2,26 +2,12 @@ package prescriptionitem 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" ep "simrs-vx/internal/domain/main-entities/prescription" - - erc "simrs-vx/internal/domain/references/common" + epib "simrs-vx/internal/domain/main-entities/prescription-item/base" ) type PrescriptionItem struct { - ecore.Main // adjust this according to the needs - Prescription_Id *uint `json:"prescription_id"` - Prescription *ep.Prescription `json:"prescription,omitempty" gorm:"foreignKey:Prescription_Id;references:Id"` - IsMix bool `json:"isMix"` - Medicine_Code *string `json:"medicine_code"` - Medicine *em.Medicine `json:"medicine,omitempty" gorm:"foreignKey:Medicine_Code;references:Code"` - MedicineMix_Id *uint `json:"medicineMix_id"` - MedicineMix *emm.MedicineMix `json:"medicineMix,omitempty" gorm:"foreignKey:MedicineMix_Id;references:Id"` - Frequency *uint16 `json:"frequency"` - Dose float64 `json:"dose"` - Usage string `json:"usage" gorm:"size:255"` - Interval uint8 `json:"interval"` - IntervalUnit_Code erc.TimeUnitCode `json:"intervalUnit_code"` - Quantity float64 `json:"quantity"` + ecore.Main // adjust this according to the needs + epib.PrescriptionItem + Prescription *ep.Prescription `json:"prescription,omitempty" gorm:"foreignKey:Prescription_Id;references:Id"` } diff --git a/internal/domain/main-entities/prescription/dto.go b/internal/domain/main-entities/prescription/dto.go index 9c73c0ee..7c4040fa 100644 --- a/internal/domain/main-entities/prescription/dto.go +++ b/internal/domain/main-entities/prescription/dto.go @@ -6,6 +6,7 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" + epi "simrs-vx/internal/domain/main-entities/prescription-item/base" pa "simrs-vx/internal/lib/auth" @@ -56,12 +57,13 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter,omitempty"` - Doctor_Code *string `json:"doctor_code"` - Doctor *ed.Doctor `json:"doctor,omitempty"` - IssuedAt *time.Time `json:"issuedAt"` - Status_Code erc.DataStatusCode `json:"status_code"` + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Doctor_Code *string `json:"doctor_code"` + Doctor *ed.Doctor `json:"doctor,omitempty"` + IssuedAt *time.Time `json:"issuedAt"` + Status_Code erc.DataStatusCode `json:"status_code"` + Items []epi.PrescriptionItem `json:"items" gorm:"foreignKey:Prescription_Id;references:Id"` } func (d Prescription) ToResponse() ResponseDto { @@ -72,6 +74,7 @@ func (d Prescription) ToResponse() ResponseDto { Doctor: d.Doctor, IssuedAt: d.IssuedAt, Status_Code: d.Status_Code, + Items: d.Items, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/prescription/entity.go b/internal/domain/main-entities/prescription/entity.go index 849e8083..f7cc3597 100644 --- a/internal/domain/main-entities/prescription/entity.go +++ b/internal/domain/main-entities/prescription/entity.go @@ -4,6 +4,7 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" + epi "simrs-vx/internal/domain/main-entities/prescription-item/base" "time" @@ -11,13 +12,18 @@ import ( ) type Prescription struct { - ecore.Main // adjust this according to the needs - Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` - Doctor_Code *string `json:"doctor_code" gorm:"size:20"` - Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` - IssuedAt *time.Time `json:"issuedAt"` - Status_Code erc.DataStatusCode `json:"status_code"` + ecore.Main // adjust this according to the needs + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Doctor_Code *string `json:"doctor_code" gorm:"size:20"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` + IssuedAt *time.Time `json:"issuedAt"` + Status_Code erc.DataStatusCode `json:"status_code"` + Items []epi.PrescriptionItem `json:"items" gorm:"foreignKey:Prescription_Id;references:Id"` +} + +func (d Prescription) IsNotNew() bool { + return d.Status_Code != erc.DSCNew } func (d Prescription) IsApproved() bool { diff --git a/internal/domain/main-entities/procedure-report/dto.go b/internal/domain/main-entities/procedure-report/dto.go new file mode 100644 index 00000000..ec815b43 --- /dev/null +++ b/internal/domain/main-entities/procedure-report/dto.go @@ -0,0 +1,111 @@ +package procedurereport + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/encounter" + "time" + + pa "simrs-vx/internal/lib/auth" +) + +type CreateDto struct { + Encounter_Id uint64 `json:"encounter_id" validate:"required"` + Date *time.Time `json:"date" validate:"required"` + Doctor_Code string `json:"doctor_code" validate:"required"` + Operator_Name string `json:"operator_name" validate:"required"` + Assistant_Name string `json:"assistant_name" validate:"required"` + Instrumentor_Name string `json:"instrumentor_name" validate:"required"` + Anesthesia_Doctor_Code *string `json:"anesthesia_doctor_code"` + Anesthesia_Nurse_Name *string `json:"anesthesia_nurse_name"` + Diagnose *string `json:"diagnose"` + Nurse_Name string `json:"nurse_name" validate:"required"` + ProcedureValue string `json:"procedure_value" validate:"required"` + ExecutionValue string `json:"execution_value" validate:"required"` + Type_Code string `json:"type_code" validate:"required"` + + pa.AuthInfo + + // PROPER + // Operator_Employe_Id uint `json:"operator_employe_id" validate:"required"` + // Assistant_Employe_Id uint `json:"assistant_employe_id" validate:"required"` + // Instrumentor_Employe_Id uint `json:"instrumentor_employe_id" validate:"required"` + // Anesthesia_Doctor_Code string `json:"anesthesia_doctor_code" validate:"required"` + // Anesthesia_Nurse_Employe_Id uint `json:"anesthesia_nurse_employe_id" validate:"required"` + // Nurse_Code string `json:"nurse_code" validate:"required"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter-id"` + Type_Code string `json:"type-code"` +} + +type ReadDetailDto struct { + Id uint16 `json:"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.Main + Encounter_Id uint64 `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Date *time.Time `json:"date"` + Doctor_Code string `json:"doctor_code"` + Operator_Name string `json:"operator_name"` + Assistant_Name string `json:"assistant_name"` + Instrumentor_Name string `json:"instrumentor_name"` + Anesthesia_Doctor_Code *string `json:"anesthesia_doctor_code"` + Anesthesia_Nurse_Name *string `json:"anesthesia_nurse_name"` + Diagnose *string `json:"diagnose"` + Nurse_Name string `json:"nurse_name"` + ProcedureValue *string `json:"procedure_value"` + ExecutionValue *string `json:"execution_value"` + Type_Code string `json:"type_code"` +} + +func (d ProcedureReport) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Date: d.Date, + Doctor_Code: d.Doctor_Code, + Operator_Name: d.Operator_Name, + Assistant_Name: d.Assistant_Name, + Instrumentor_Name: d.Instrumentor_Name, + Anesthesia_Doctor_Code: d.Anesthesia_Doctor_Code, + Anesthesia_Nurse_Name: d.Anesthesia_Nurse_Name, + Nurse_Name: d.Nurse_Name, + ProcedureValue: &d.ProcedureValue, + ExecutionValue: &d.ExecutionValue, + Type_Code: d.Type_Code, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []ProcedureReport) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/procedure-report/entity.go b/internal/domain/main-entities/procedure-report/entity.go new file mode 100644 index 00000000..cf084bd4 --- /dev/null +++ b/internal/domain/main-entities/procedure-report/entity.go @@ -0,0 +1,67 @@ +package procedurereport + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" + "time" +) + +type ProcedureReport struct { + ecore.Main // adjust this according to the needs + Encounter_Id uint64 `json:"encounter_id" gorm:"foreignKey"` + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Date *time.Time `json:"date" gorm:"not null;size:20"` + Doctor_Code string `json:"doctor_code" gorm:"size:10"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` + Operator_Name string `json:"operator_name"` + Assistant_Name string `json:"assistant_name"` + Instrumentor_Name string `json:"instrumentor_name"` + Diagnose *string `json:"diagnose" gorm:"size:1024"` + Nurse_Name string `json:"nurse_name"` + Anesthesia_Doctor_Code *string `json:"anesthesia_doctor_code" gorm:"size:10"` + Anesthesia_Doctor *ed.Doctor `json:"anesthesia,omitempty" gorm:"foreignKey:Anesthesia_Doctor_Code;references:Code"` + Anesthesia_Nurse_Name *string `json:"anesthesia_nurse_name"` + ProcedureValue string `json:"procedure_value"` + ExecutionValue string `json:"execution_value"` + Type_Code string `json:"type_code"` + + // SurgerySize_Code *string `json:"surgerySize_code" gorm:"size:10"` + // Billing_Code *string `json:"billing_code" gorm:"size:10"` + // SurgerySystem_Code *string `json:"surgerySystem_code" gorm:"size:10"` + // StartAt *string `json:"startAt" gorm:"size:20"` + // EndAt *string `json:"endAt" gorm:"size:20"` + // AnesthesiaStartAt *string `json:"anesthesiaStartAt" gorm:"size:20"` + // AnesthesiaEndAt *string `json:"anesthesiaEndAt" gorm:"size:20"` + // SurgeryType_Code *string `json:"surgeryType_code" gorm:"size:10"` + // SurgeryStage_Code *string `json:"surgeryStage_code" gorm:"size:10"` + // BornMortality_Code *string `json:"bornMortality_code" gorm:"size:10"` + // BornLocation_Code *string `json:"bornLocation_code" gorm:"size:10"` + // Weight *string `json:"weight" gorm:"size:10"` + // BornNotes *string `json:"bornNotes" gorm:"size:1024"` + // Description *string `json:"notes" gorm:"size:1024"` + // BleedingAmount *uint16 `json:"bleedingAmount" gorm:"size:10"` + // BloodInType_Code *string `json:"bloodInType_code" gorm:"size:10"` + // BloodInAmount *uint16 `json:"bloodInAmount" gorm:"size:10"` + // Brand *string `json:"brand" gorm:"size:100"` + // ImplantName *string `json:"implantName" gorm:"size:100"` + // ImplantRegisterNumber *string `json:"implantRegisterNumber" gorm:"size:100"` + // ImplantCompanionName *string `json:"implantCompanionName" gorm:"size:100"` + // SpecimentDest_Code *string `json:"specimentDest" gorm:"size:100"` + // TissueInfo *string `json:"tissueInfo" gorm:"size:100"` + + //PROPER + // Doctor_Code string `json:"doctor_code" gorm:"size:10"` + // Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` + // Operator_Employe_Id uint `json:"operator_employe_id"` + // Operator_Employe *eem.Employee `json:"operator_employe,omitempty" gorm:"foreignKey:Operator_Employe_Id;references:Id"` + // Assistant_Employe_Id uint `json:"assistant_employe_id"` + // Instrumentor_Employe_Id uint `json:"instrumentor_employe_id"` + // Instrumentor_Employe *eem.Employee `json:"instrumentor_employe,omitempty" gorm:"foreignKey:Instrumentor_Employe_Id;references:Id"` + // Nurse_Code string `json:"nurse_code" gorm:"size:10"` + // Nurse *en.Nurse `json:"nurse,omitempty" gorm:"foreignKey:Nurse_Code;references:Code"` + // Anesthesia_Doctor_Code string `json:"anesthesia_doctor_code" gorm:"size:10"` + // Anesthesia *eem.Employee `json:"anesthesia,omitempty" gorm:"foreignKey:Anesthesia_Doctor_Code;references:Code"` + // Anesthesia_Nurse_Employe_Id uint `json:"anesthesia_nurse_employe_id"` + // Anesthesia_Nurse *eem.Employee `json:"anesthesia_nurse,omitempty" gorm:"foreignKey:Anesthesia_Nurse_Employe_Id;references:Id"` +} diff --git a/internal/domain/main-entities/procedure-room-order-item/base/entity.go b/internal/domain/main-entities/procedure-room-order-item/base/entity.go new file mode 100644 index 00000000..cd54e456 --- /dev/null +++ b/internal/domain/main-entities/procedure-room-order-item/base/entity.go @@ -0,0 +1,12 @@ +package procedureroomorder + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type ProcedureRoomOrderItem struct { + ecore.BigMain + ProcedureRoomOrder_Id uint64 `json:"procedureRoomOrder_id"` + ProcedureRoom_Code string `json:"procedureRoom_code" gorm:"size:20"` + Note string `json:"note" gorm:"size:255"` +} diff --git a/internal/domain/main-entities/procedure-room-order-item/dto.go b/internal/domain/main-entities/procedure-room-order-item/dto.go new file mode 100644 index 00000000..83c4d094 --- /dev/null +++ b/internal/domain/main-entities/procedure-room-order-item/dto.go @@ -0,0 +1,70 @@ +package procedureroomorder + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + epr "simrs-vx/internal/domain/main-entities/procedure-room" +) + +type CreateDto struct { + ProcedureRoomOrder_Id uint64 `json:"procedureRoomOrder_id"` + ProcedureRoom_Code string `json:"procedureRoom_code"` + Note string `json:"note"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id uint64 `json:"encounter-id"` + ProcedureRoomOrder_Id uint64 `json:"procedure-room-order-id"` +} + +type ReadDetailDto struct { + Id uint64 `json:"id"` + Includes string `json:"includes"` +} + +type UpdateDto struct { + Id uint64 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint64 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.BigMain + ProcedureRoomOrder_Id uint64 `json:"procedureRoomOrder_id"` + ProcedureRoom_Code string `json:"procedureRoom_code"` + ProcedureRoom *epr.ProcedureRoom `json:"procedureRoom,omitempty"` + Note string `json:"note"` +} + +func (d ProcedureRoomOrderItem) ToResponse() ResponseDto { + resp := ResponseDto{ + ProcedureRoomOrder_Id: d.ProcedureRoomOrder_Id, + ProcedureRoom_Code: d.ProcedureRoom_Code, + ProcedureRoom: d.ProcedureRoom, + Note: d.Note, + } + resp.Id = d.Id + return resp +} + +func ToResponseList(data []ProcedureRoomOrderItem) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/procedure-room-order-item/entity.go b/internal/domain/main-entities/procedure-room-order-item/entity.go new file mode 100644 index 00000000..13b4978b --- /dev/null +++ b/internal/domain/main-entities/procedure-room-order-item/entity.go @@ -0,0 +1,13 @@ +package procedureroomorder + +import ( + epr "simrs-vx/internal/domain/main-entities/procedure-room" + epro "simrs-vx/internal/domain/main-entities/procedure-room-order" + eb "simrs-vx/internal/domain/main-entities/procedure-room-order-item/base" +) + +type ProcedureRoomOrderItem struct { + eb.ProcedureRoomOrderItem + ProcedureRoomOrder *epro.ProcedureRoomOrder `json:"procedureRoomOrder,omitempty" gorm:"foreignKey:ProcedureRoomOrder_Id;references:Id"` + ProcedureRoom *epr.ProcedureRoom `json:"procedureRoom,omitempty" gorm:"foreignKey:ProcedureRoom_Code;references:Code"` +} diff --git a/internal/domain/main-entities/procedure-room-order/dto.go b/internal/domain/main-entities/procedure-room-order/dto.go new file mode 100644 index 00000000..4482081c --- /dev/null +++ b/internal/domain/main-entities/procedure-room-order/dto.go @@ -0,0 +1,74 @@ +package procedureroomorder + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ec "simrs-vx/internal/domain/main-entities/encounter" + emp "simrs-vx/internal/domain/main-entities/material-package" + epr "simrs-vx/internal/domain/main-entities/procedure-room" + erc "simrs-vx/internal/domain/references/common" +) + +type CreateDto struct { + Encounter_Id uint64 `json:"encounter_id" validate:"required"` + // Infra_Code string `json:"infra_code" validate:"required"` + MaterialPackage_Code *string `json:"materialPackage_code"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id uint64 `json:"encounter-id"` +} + +type ReadDetailDto struct { + Id uint64 `json:"id"` +} + +type UpdateDto struct { + Id uint64 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint64 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.BigMain + Encounter_Id uint64 `json:"encounter_id"` + Encounter *ec.Encounter `json:"encounter,omitempty"` + Infra_Code string `json:"procedure"` + MaterialPackage_Code *string `json:"materialPackage_code"` + Status_Code erc.DataStatusCode `json:"status_code"` + ProcedureRoom *epr.ProcedureRoom `json:"procedureRoom,omitempty"` + MaterialPackage *emp.MaterialPackage `json:"materialPackage,omitempty"` +} + +func (d ProcedureRoomOrder) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + // Infra_Code: d.Infra_Code, + MaterialPackage_Code: d.MaterialPackage_Code, + Status_Code: d.Status_Code, + } + resp.Id = d.Id + return resp +} + +func ToResponseList(data []ProcedureRoomOrder) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/procedure-room-order/entity.go b/internal/domain/main-entities/procedure-room-order/entity.go new file mode 100644 index 00000000..5a4a8542 --- /dev/null +++ b/internal/domain/main-entities/procedure-room-order/entity.go @@ -0,0 +1,24 @@ +package procedureroomorder + +import ( + erc "simrs-vx/internal/domain/references/common" + + ecore "simrs-vx/internal/domain/base-entities/core" + emp "simrs-vx/internal/domain/main-entities/material-package" + eproi "simrs-vx/internal/domain/main-entities/procedure-room-order-item/base" +) + +type ProcedureRoomOrder struct { + ecore.BigMain + Encounter_Id uint64 `json:"encounter_id"` + // Infra_Code string `json:"infra_code" gorm:"size:20"` + // ProcedureRoom *epr.ProcedureRoom `json:"procedureRoom,omitempty" gorm:"foreignKey:Infra_Code;references:Code"` + MaterialPackage_Code *string `json:"materialPackage_code" gorm:"size:20"` + MaterialPackage *emp.MaterialPackage `json:"materialPackage,omitempty" gorm:"foreignKey:MaterialPackage_Code;references:Code"` + Status_Code erc.DataStatusCode `json:"status_code" gorm:"size:20"` + Items []eproi.ProcedureRoomOrderItem `json:"items,omitempty" gorm:"foreignKey:ProcedureRoomOrder_Id;references:Id"` +} + +func (d ProcedureRoomOrder) IsNotNew() bool { + return d.Status_Code != erc.DSCNew +} diff --git a/internal/domain/main-entities/procedure-room/base/entity.go b/internal/domain/main-entities/procedure-room/base/entity.go new file mode 100644 index 00000000..981dd4f2 --- /dev/null +++ b/internal/domain/main-entities/procedure-room/base/entity.go @@ -0,0 +1,21 @@ +package procedureroombase + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ero "simrs-vx/internal/domain/references/organization" +) + +type ProcedureRoom struct { + ecore.SmallMain + Code string `json:"code" gorm:"unique;size:20"` // copied from infra code + Infra_Code *string `json:"infra_code" gorm:"size:20;unique"` + Type_Code *ero.ProdcedureRoomTypeCode `json:"type_code" gorm:"size:10"` + Unit_Code *string `json:"unit_code" gorm:"size:20"` + Specialist_Code *string `json:"specialist_code" gorm:"size:20"` + Subspecialist_Code *string `json:"subspecialist_code" gorm:"size:20"` +} + +// THIS IS ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ +// func (ProcedureRoom) TableName() string { +// return "Room" +// } diff --git a/internal/domain/main-entities/room/dto.go b/internal/domain/main-entities/procedure-room/dto.go similarity index 82% rename from internal/domain/main-entities/room/dto.go rename to internal/domain/main-entities/procedure-room/dto.go index 2ff41c3a..b3812db2 100644 --- a/internal/domain/main-entities/room/dto.go +++ b/internal/domain/main-entities/procedure-room/dto.go @@ -1,4 +1,4 @@ -package room +package procedureroom import ( ecore "simrs-vx/internal/domain/base-entities/core" @@ -9,7 +9,9 @@ import ( ) type CreateDto struct { + Code *string `json:"code"` Infra_Code *string `json:"infra_code"` + Type_Code string `json:"type_code"` Unit_Code *string `json:"unit_code"` Specialist_Code *string `json:"specialist_code"` Subspecialist_Code *string `json:"subspecialist_code"` @@ -23,6 +25,7 @@ type ReadListDto struct { type FilterDto struct { Infra_Code *string `json:"infra-code"` + Type_Code string `json:"type-code"` Unit_Code *string `json:"unit-code"` Specialist_Code *string `json:"specialist-code"` Subspecialist_Code *string `json:"subspecialist-code"` @@ -49,6 +52,8 @@ type MetaDto struct { type ResponseDto struct { ecore.SmallMain + Code string `json:"code"` + Type_Code *string `json:"type_code"` Infra_Code *string `json:"infra_code"` Infra *ei.Infra `json:"infra,omitempty"` Unit_Code *string `json:"unit_code"` @@ -59,10 +64,12 @@ type ResponseDto struct { Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty"` } -func (d Room) ToResponse() ResponseDto { +func (d ProcedureRoom) ToResponse() ResponseDto { resp := ResponseDto{ + Code: d.Code, Infra_Code: d.Infra_Code, Infra: d.Infra, + Type_Code: (*string)(d.Type_Code), Unit_Code: d.Unit_Code, Unit: d.Unit, Specialist_Code: d.Specialist_Code, @@ -74,7 +81,7 @@ func (d Room) ToResponse() ResponseDto { return resp } -func ToResponseList(data []Room) []ResponseDto { +func ToResponseList(data []ProcedureRoom) []ResponseDto { resp := make([]ResponseDto, len(data)) for i, u := range data { resp[i] = u.ToResponse() diff --git a/internal/domain/main-entities/procedure-room/entity.go b/internal/domain/main-entities/procedure-room/entity.go new file mode 100644 index 00000000..9be3ac69 --- /dev/null +++ b/internal/domain/main-entities/procedure-room/entity.go @@ -0,0 +1,17 @@ +package procedureroom + +import ( + ei "simrs-vx/internal/domain/main-entities/infra" + ebase "simrs-vx/internal/domain/main-entities/procedure-room/base" + es "simrs-vx/internal/domain/main-entities/specialist" + ess "simrs-vx/internal/domain/main-entities/subspecialist" + eu "simrs-vx/internal/domain/main-entities/unit" +) + +type ProcedureRoom struct { + ebase.ProcedureRoom + Infra *ei.Infra `json:"infra,omitempty" gorm:"foreignKey:Infra_Code;references:Code"` + Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` + Specialist *es.Specialist `json:"specialist,omitempty" gorm:"foreignKey:Specialist_Code;references:Code"` + Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty" gorm:"foreignKey:Subspecialist_Code;references:Code"` +} diff --git a/internal/domain/main-entities/radiology-mcu-order-item/base/dto.go b/internal/domain/main-entities/radiology-mcu-order-item/base/dto.go new file mode 100644 index 00000000..8ca6d02f --- /dev/null +++ b/internal/domain/main-entities/radiology-mcu-order-item/base/dto.go @@ -0,0 +1,6 @@ +package radiologymcuorderitem + +type SubCreateDto struct { + McuSrc_Code string `json:"mcuSrc_code" validate:"required"` + Note string `json:"note"` +} diff --git a/internal/domain/main-entities/radiology-mcu-order-item/base/entity.go b/internal/domain/main-entities/radiology-mcu-order-item/base/entity.go new file mode 100644 index 00000000..1f3ff5a5 --- /dev/null +++ b/internal/domain/main-entities/radiology-mcu-order-item/base/entity.go @@ -0,0 +1,17 @@ +package radiologymcuorderitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ems "simrs-vx/internal/domain/main-entities/mcu-src" + erc "simrs-vx/internal/domain/references/common" +) + +type RadiologyMcuOrderItem struct { + ecore.BigMain // adjust this according to the needs + RadiologyMcuOrder_Id uint64 `json:"radiologyMcuOrder_id" gorm:"uniqueIndex:idx_order_src"` + McuSrc_Code string `json:"mcuSrc_code" gorm:"uniqueIndex:idx_order_src"` + McuSrc *ems.McuSrc `json:"mcuSrc,omitempty" gorm:"foreignKey:McuSrc_Code;references:Code"` + Note *string `json:"note" gorm:"size:1024"` + Result *string `json:"result"` + Status_Code erc.DataStatusCode `json:"status_code"` +} diff --git a/internal/domain/main-entities/radiology-mcu-order-item/dto.go b/internal/domain/main-entities/radiology-mcu-order-item/dto.go new file mode 100644 index 00000000..99c65df3 --- /dev/null +++ b/internal/domain/main-entities/radiology-mcu-order-item/dto.go @@ -0,0 +1,80 @@ +package radiologymcuorderitem + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ems "simrs-vx/internal/domain/main-entities/mcu-src" + emro "simrs-vx/internal/domain/main-entities/radiology-mcu-order" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type CreateDto struct { + RadiologyMcuOrder_Id uint64 `json:"radiologyMcuOrder_id"` + McuSrc_Code string `json:"mcuSrc_code"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + RadiologyMcuOrder_Id *uint64 `json:"radiology-mcu-order-id"` + McuSrc_Code *string `json:"mcu-src-code"` + Status_Code erc.DataStatusCode `json:"status-code"` +} +type ReadDetailDto struct { + Id uint `json:"id"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` +} + +type SetScheduleDto struct { + Id uint `json:"id"` + ExaminationDate *time.Time `json:"examinationDate"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.BigMain + RadiologyMcuOrder_Id uint64 `json:"radiologyMcuOrder_id"` + RadiologyMcuOrder *emro.RadiologyMcuOrder `json:"radiologyMcuOrder,omitempty"` + McuSrc_Code string `json:"mcuSrc_code"` + McuSrc *ems.McuSrc `json:"mcuSrc,omitempty"` + Result *string `json:"result"` + Status_Code erc.DataStatusCode `json:"status_code"` +} + +func (d RadiologyMcuOrderItem) ToResponse() ResponseDto { + resp := ResponseDto{ + RadiologyMcuOrder_Id: d.RadiologyMcuOrder_Id, + RadiologyMcuOrder: d.RadiologyMcuOrder, + McuSrc_Code: d.McuSrc_Code, + McuSrc: d.McuSrc, + Result: d.Result, + Status_Code: d.Status_Code, + } + resp.BigMain = d.BigMain + return resp +} + +func ToResponseList(data []RadiologyMcuOrderItem) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/radiology-mcu-order-item/entity.go b/internal/domain/main-entities/radiology-mcu-order-item/entity.go new file mode 100644 index 00000000..da20a56a --- /dev/null +++ b/internal/domain/main-entities/radiology-mcu-order-item/entity.go @@ -0,0 +1,17 @@ +package radiologymcuorderitem + +import ( + emo "simrs-vx/internal/domain/main-entities/radiology-mcu-order" + emoib "simrs-vx/internal/domain/main-entities/radiology-mcu-order-item/base" + + erc "simrs-vx/internal/domain/references/common" +) + +type RadiologyMcuOrderItem struct { + emoib.RadiologyMcuOrderItem + RadiologyMcuOrder *emo.RadiologyMcuOrder `json:"radiologyMcuOrder,omitempty" gorm:"foreignKey:RadiologyMcuOrder_Id;references:Id"` +} + +func (d RadiologyMcuOrderItem) IsCompleted() bool { + return d.Status_Code == erc.DSCDone +} diff --git a/internal/domain/main-entities/radiology-mcu-order/base/entity.go b/internal/domain/main-entities/radiology-mcu-order/base/entity.go new file mode 100644 index 00000000..6871e689 --- /dev/null +++ b/internal/domain/main-entities/radiology-mcu-order/base/entity.go @@ -0,0 +1,17 @@ +package radiologymcuorder + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" +) + +type RadiologyMcuOrder struct { + ecore.BigMain + Encounter_Id uint `json:"encounter_id"` + Number uint64 `json:"number"` + Doctor_Code string `json:"doctor_code" gorm:"unique;size:20"` + ClinicalNotes *string `json:"clinicalNotes"` + OtherNotes *string `json:"otherNotes"` + Resume *string `json:"resume"` + Status_Code erc.DataStatusCode `json:"status_code" gorm:"not null;size:10"` +} diff --git a/internal/domain/main-entities/radiology-mcu-order/dto.go b/internal/domain/main-entities/radiology-mcu-order/dto.go new file mode 100644 index 00000000..4250b4b0 --- /dev/null +++ b/internal/domain/main-entities/radiology-mcu-order/dto.go @@ -0,0 +1,88 @@ +package radiologymcuorder + +import ( + la "simrs-vx/internal/lib/auth" + + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" + ermoi "simrs-vx/internal/domain/main-entities/radiology-mcu-order-item/base" +) + +type CreateDto struct { + Encounter_Id uint `json:"encounter_id"` + Number *uint64 `json:"number"` // SHOULD BE AUTOMATIC WITHOUT SYNC + Doctor_Code string `json:"-" validate:"required"` + ClinicalNotes *string `json:"clinicalNotes"` + OtherNotes *string `json:"otherNotes"` + Items []ermoi.SubCreateDto `json:"items" validate:"required"` + la.AuthInfo +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Sort string `json:"sort"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id uint `json:"encounter-id"` + Doctor_Code string `json:"doctor-code"` +} + +type ReadDetailDto struct { + Id uint64 `json:"id"` + Includes string `json:"includes"` +} + +type UpdateDto struct { + Id uint64 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint64 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.BigMain + Encounter_Id uint `json:"encounter_id"` + Encounter *ee.Encounter + Number uint64 `json:"number"` + Doctor_Code string `json:"doctor_code"` + Doctor *ed.Doctor + ClinicalNotes *string `json:"clinicalNotes"` + OtherNotes *string `json:"otherNotes"` + Resume *string `json:"resume"` + Items []*ermoi.RadiologyMcuOrderItem +} + +func (d RadiologyMcuOrder) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Encounter: d.Encounter, + Number: d.Number, + Doctor_Code: d.Doctor_Code, + Doctor: d.Doctor, + ClinicalNotes: d.ClinicalNotes, + OtherNotes: d.OtherNotes, + Resume: d.Resume, + } + resp.BigMain = d.BigMain + return resp +} + +func ToResponseList(data []RadiologyMcuOrder) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/radiology-mcu-order/entity.go b/internal/domain/main-entities/radiology-mcu-order/entity.go new file mode 100644 index 00000000..1ef8882d --- /dev/null +++ b/internal/domain/main-entities/radiology-mcu-order/entity.go @@ -0,0 +1,28 @@ +package radiologymcuorder + +import ( + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/encounter" + ermoi "simrs-vx/internal/domain/main-entities/radiology-mcu-order-item/base" + eamob "simrs-vx/internal/domain/main-entities/radiology-mcu-order/base" + erc "simrs-vx/internal/domain/references/common" +) + +type RadiologyMcuOrder struct { + eamob.RadiologyMcuOrder + Encounter *ee.Encounter `json:"encounter,omitempty" gorm:"foreignKey:Encounter_Id;references:Id"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` + Items []*ermoi.RadiologyMcuOrderItem `json:"items" gorm:"foreignKey:RadiologyMcuOrder_Id;references:Id"` +} + +func (d RadiologyMcuOrder) IsNotNew() bool { + return d.Status_Code != erc.DSCNew +} + +func (d RadiologyMcuOrder) IsCompleted() bool { + return d.Status_Code == erc.DSCDone +} + +func (d RadiologyMcuOrder) IsSameDoctor(doctor_code *string) bool { + return d.Doctor_Code == *doctor_code +} diff --git a/internal/domain/main-entities/registrator/dto.go b/internal/domain/main-entities/registrator/dto.go new file mode 100644 index 00000000..5f0d4517 --- /dev/null +++ b/internal/domain/main-entities/registrator/dto.go @@ -0,0 +1,71 @@ +package registrator + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" + ei "simrs-vx/internal/domain/main-entities/installation" +) + +type CreateDto struct { + Employee_Id uint `json:"employee_id"` + Installation_Code string `json:"installation_code" validate:"maxLength=20"` +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Employee_Id *uint `json:"employee-id"` + Installation_Code *string `json:"installation-code"` +} + +type ReadDetailDto struct { + Id *uint `json:"id"` + Employee_Id *uint `json:"employee_id"` + Includes string `json:"includes"` +} + +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"` + Installation_Code string `json:"installation_code"` + Installation *ei.Installation `json:"installation,omitempty"` +} + +func (d Registrator) ToResponse() ResponseDto { + resp := ResponseDto{ + Employee_Id: d.Employee_Id, + Employee: d.Employee, + Installation_Code: d.Installation_Code, + Installation: d.Installation, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Registrator) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/registrator/entity.go b/internal/domain/main-entities/registrator/entity.go new file mode 100644 index 00000000..31998c1c --- /dev/null +++ b/internal/domain/main-entities/registrator/entity.go @@ -0,0 +1,15 @@ +package registrator + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ee "simrs-vx/internal/domain/main-entities/employee" + ei "simrs-vx/internal/domain/main-entities/installation" +) + +type Registrator 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"` + Installation_Code string `json:"installation_code" gorm:"size:20"` + Installation *ei.Installation `json:"installation,omitempty" gorm:"foreignKey:Installation_Code;references:Code"` +} diff --git a/internal/domain/main-entities/resume/dto.go b/internal/domain/main-entities/resume/dto.go new file mode 100644 index 00000000..e7ddf09b --- /dev/null +++ b/internal/domain/main-entities/resume/dto.go @@ -0,0 +1,182 @@ +package resume + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + "time" + + erc "simrs-vx/internal/domain/references/common" + + pa "simrs-vx/internal/lib/auth" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Value *string `json:"value"` + Status_Code erc.DataVerifiedCode `json:"status_code"` + + pa.AuthInfo +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter-id"` + Doctor_Code *string `json:"doctor-code"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` + Includes string `json:"includes"` +} + +type UpdateDto struct { + Id uint `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint `json:"id"` + + pa.AuthInfo +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id"` + Doctor_Code *string `json:"doctor_code"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl"` + Status_Code erc.DataVerifiedCode `json:"status_code"` +} + +func (d Resume) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Doctor_Code: d.Doctor_Code, + Value: d.Value, + FileUrl: d.FileUrl, + Status_Code: d.Status_Code, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Resume) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} + +// ValueDto is for resume value +type ValueDto struct { + Assessment Assessment `json:"assessment"` + Diagnosis Diagnosis `json:"diagnosis"` + Action Action `json:"action"` + Consultation Consultation `json:"consultation"` + Supporting SupportingExaminations `json:"supporting"` + Pharmacy PharmacyData `json:"pharmacy"` + Discharge DischargeCondition `json:"discharge"` + National NationalProgram `json:"national"` + Management Management `json:"management"` + Medication Medication `json:"medication"` +} + +type Assessment struct { + StartedAt *time.Time `json:"startedAt` + FinishedAt *time.Time `json:"finishedAt` + Doctor_Code string `json:"doctor_code` + DiagnosisIn string `json:"diagnosisIn` + AmbulatoryIndication string `json:"ambulatoryIndication"` + MainComplaint string `json:"mainComplaint"` + PhysicalExamination string `json:"physicalExamination"` + MedicalHistory string `json:"medicalHistory"` + MedicalDiagnosis string `json:"medicalDiagnosis"` +} + +type Diagnosis struct { + PrimaryDiagnosis DiagnosisEntry `json:"primaryDiagnosis"` + SecondaryDiagnosis []DiagnosisEntry `json:"secondaryDiagnosis"` +} + +type DiagnosisEntry struct { + DiagnosisName string `json:"diagnosis"` + ICD10 string `json:"icd_10"` + Basis string `json:"basis"` // Clinical basis of diagnosis / dasar diagnosa +} + +type Action struct { + PrimaryAction ActionEntry `json:"primaryAction"` + AdditionalActions []ActionEntry `json:"additionalActions"` + MedicalActions string `json:"medicalActions"` // free-text: "Tindakan Medis" +} + +type ActionEntry struct { + Action string `json:"action"` // Tindakan + ICD9 string `json:"icd_9"` // ICD-9 + Basis string `json:"basis"` // Dasar Tindakan +} + +type Consultation struct { + Consultations []ConsultationEntry `json:"consultations"` +} + +type ConsultationEntry struct { + Consultation string `json:"consultation"` // Konsultasi + ConsultationAnswer string `json:"consultationAnswer"` // Jawaban Konsultasi +} + +type SupportingExaminations struct { + Notes string `json:"notes"` // Free-text list of lab/imaging results +} + +type PharmacyData struct { + AllergySpecialConditions string `json:"allergySpecialConditions"` // Kelainan Khusus Alergi + OtherConditions string `json:"otherConditions"` // Kelainan Lain + TherapyDuringCare string `json:"therapyDuringCare"` // Terapi selama dirawat + TherapyAtDischarge string `json:"therapyAtDischarge"` // Terapi waktu pulang + FollowUpInstructions string `json:"followUpInstructions"` // Edukasi / Anjuran / Follow-up +} + +type DischargeCondition struct { + BloodPressureSystolic float64 `json:"bloodPressureSystolic"` // Tekanan Darah Sistol (mmHg) + BloodPressureDiastolic float64 `json:"bloodPressureDiastolic"` // Tekanan Darah Diastol (mmHg) + RespirationRate float64 `json:"respirationRate"` // Pernafasan (kali/menit) + HeartRate float64 `json:"heartRate"` // Denyut Jantung (kali/menit) + BodyTemperature float64 `json:"bodyTemperature"` // Suhu Tubuh (°C) + + ConsciousnessLevel string `json:"consciousnessLevel"` // Tingkat Kesadaran + PainScale int `json:"painScale"` // Skala Nyeri (0–10) +} + +type NationalProgram struct { + ProgramService string `json:"programService"` // e.g. "Antenatal Care" + ProgramServiceStatus string `json:"programServiceStatus"` // e.g. "Suspected" +} + +type Management struct { + NationalProgramService string `json:"nationalProgramService"` // e.g. selected program + FollowUpManagement string `json:"followUpManagement"` // e.g. further management plan + ConditionOnDischarge string `json:"conditionOnDischarge"` // e.g. "Stable" + DischargeMethod string `json:"dischargeMethod"` // e.g. "Discharged with Doctor's Approval" +} + +type MedicationEntry struct { + DuringTreatment string `json:"duringTreatment"` + AtDischarge string `json:"atDischarge"` +} + +type Medication struct { + Medications []MedicationEntry `json:"medications"` +} diff --git a/internal/domain/main-entities/resume/entity.go b/internal/domain/main-entities/resume/entity.go new file mode 100644 index 00000000..93a1d8cd --- /dev/null +++ b/internal/domain/main-entities/resume/entity.go @@ -0,0 +1,30 @@ +package resume + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ed "simrs-vx/internal/domain/main-entities/doctor" + + erc "simrs-vx/internal/domain/references/common" +) + +type Resume struct { + ecore.Main + Encounter_Id *uint `json:"encounter_id" gorm:"not null"` + Doctor_Code *string `json:"doctor_code" gorm:"size:10"` + Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl" gorm:"size:1024"` + Status_Code erc.DataVerifiedCode `json:"status_code" gorm:"not null;size:10"` +} + +func (d Resume) IsNew() bool { + return d.Status_Code == erc.DVCNew +} + +func (d Resume) IsVerified() bool { + return d.Status_Code == erc.DVCVerified +} + +func (d Resume) IsValidated() bool { + return d.Status_Code == erc.DVCValidated +} diff --git a/internal/domain/main-entities/room/base/entity.go b/internal/domain/main-entities/room/base/entity.go deleted file mode 100644 index d5651ac9..00000000 --- a/internal/domain/main-entities/room/base/entity.go +++ /dev/null @@ -1,23 +0,0 @@ -package base - -import ( - ecore "simrs-vx/internal/domain/base-entities/core" - es "simrs-vx/internal/domain/main-entities/specialist" - ess "simrs-vx/internal/domain/main-entities/subspecialist" - eu "simrs-vx/internal/domain/main-entities/unit" -) - -type Basic struct { - ecore.SmallMain // adjust this according to the needs - Infra_Code *string `json:"infra_code" gorm:"size:10"` - Unit_Code *string `json:"unit_code" gorm:"size:10"` - Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` - Specialist_Code *string `json:"specialist_code" gorm:"size:10"` - Specialist *es.Specialist `json:"specialist,omitempty" gorm:"foreignKey:Specialist_Code;references:Code"` - Subspecialist_Code *string `json:"subspecialist_code" gorm:"size:10"` - Subspecialist *ess.Subspecialist `json:"subspecialist,omitempty" gorm:"foreignKey:Subspecialist_Code;references:Code"` -} - -func (Basic) TableName() string { - return "Room" -} diff --git a/internal/domain/main-entities/room/entity.go b/internal/domain/main-entities/room/entity.go deleted file mode 100644 index 49fb8cc6..00000000 --- a/internal/domain/main-entities/room/entity.go +++ /dev/null @@ -1,11 +0,0 @@ -package room - -import ( - ei "simrs-vx/internal/domain/main-entities/infra" - ebase "simrs-vx/internal/domain/main-entities/room/base" -) - -type Room struct { - ebase.Basic - Infra *ei.Infra `json:"infra,omitempty" gorm:"foreignKey:Infra_Code;references:Code"` -} diff --git a/internal/domain/main-entities/screening/dto.go b/internal/domain/main-entities/screening/dto.go new file mode 100644 index 00000000..0c4310ed --- /dev/null +++ b/internal/domain/main-entities/screening/dto.go @@ -0,0 +1,207 @@ +package screening + +import ( + // std + + // internal - lib + pa "simrs-vx/internal/lib/auth" + + // internal - domain - base-entities + ecore "simrs-vx/internal/domain/base-entities/core" + + // internal - domain - main-entities + eem "simrs-vx/internal/domain/main-entities/employee" + + erc "simrs-vx/internal/domain/references/clinical" +) + +type CreateDto struct { + Encounter_Id *uint `json:"encounter_id"` + Employee_Id *uint `json:"-"` + Type erc.ScreeningFormTypeCode `json:"type"` + Value *string `json:"value"` + + pa.AuthInfo +} + +type ReadListDto struct { + FilterDto + Includes string `json:"includes"` + Sort string `json:"sort"` + Pagination ecore.Pagination +} + +type FilterDto struct { + Encounter_Id *uint `json:"encounter-id"` + Employee_Id *uint `json:"employee-id"` + Type erc.ScreeningFormTypeCode `json:"type"` + Value *string `json:"value"` +} + +type ReadDetailDto struct { + Id uint `json:"id"` + Includes string `json:"includes"` +} + +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 + Encounter_Id *uint `json:"encounter_id"` + Employee_Id *uint `json:"employee_id"` + Employee *eem.Employee `json:"employee,omitempty"` + Type erc.ScreeningFormTypeCode `json:"type"` + Value *string `json:"value"` +} + +func (d Screening) ToResponse() ResponseDto { + resp := ResponseDto{ + Encounter_Id: d.Encounter_Id, + Employee_Id: d.Employee_Id, + Employee: d.Employee, + Type: d.Type, + Value: d.Value, + } + resp.Main = d.Main + return resp +} + +func ToResponseList(data []Screening) []ResponseDto { + resp := make([]ResponseDto, len(data)) + for i, u := range data { + resp[i] = u.ToResponse() + } + return resp +} + +type ScreeningEntry struct { + AgeAtRisk bool `json:"ageAtRisk"` // Usia Dengan Risiko + LowCognitiveFunction bool `json:"lowCognitiveFunction"` // Pasien Dengan Fungsi Kognitif Rendah + HighRiskPatient bool `json:"highRiskPatient"` // Pasien Dengan Risiko Tinggi + HighComplaintPotential bool `json:"highComplaintPotential"` // Potensi Komplain Tinggi (Medik dan Non Medik) + ChronicOrCatastrophicOrTerminal bool `json:"chronicOrCatastrophicOrTerminal"` // Kasus Dengan Penyakit Kronis, Katastropik, Terminal + LowFunctionalStatus bool `json:"lowFunctionalStatus"` // Status Fungsional Rendah, Kebutuhan Bantuan ADL Tinggi + HistoryOfMedicalDeviceUse bool `json:"historyOfMedicalDeviceUse"` // Pasien Dengan Riwayat Penggunaan Peralatan Medis Masa Lalu + MentalOrSocialIssues bool `json:"mentalOrSocialIssues"` // Riwayat Gangguan Mental, Bunuh Diri, Krisis Keluarga, Isu Sosial + FrequentERVisitsOrReadmission bool `json:"frequentERVisitsOrReadmission"` // Sering Masuk IGD, Readmisi RS + HighCareCostEstimate bool `json:"highCareCostEstimate"` // Perkiraan Asuhan Dengan Biaya Tinggi + ComplexFinancingSystem bool `json:"complexFinancingSystem"` // Kemungkinan Sistem Pembiayaan Yang Kompleks + AboveAverageLengthOfStay bool `json:"aboveAverageLengthOfStay"` // Kasus Yang Melebihi Rata-Rata Lama Dirawat + ImportantOrHighRiskDischargePlanning bool `json:"importantOrHighRiskDischargePlanning"` // Rencana Pemulangan Penting / Kontinuitas Pelayanan + Stagnation bool `json:"stagnation"` // Stagnasi +} + +type ProblemIdentification struct { + CareNotFollowingGuidelines bool `json:"careNotFollowingGuidelines"` // Tingkat Asuhan Tidak Sesuai Panduan/ Norma + OverUtilization bool `json:"overUtilization"` // Over Utilization Pelayanan + UnderUtilization bool `json:"underUtilization"` // Under Utilization Pelayanan + PatientNonCompliance bool `json:"patientNonCompliance"` // Ketidakpatuhan Pasien + InadequateEducation bool `json:"inadequateEducation"` // Edukasi Kurang Memadai + LackOfFamilySupport bool `json:"lackOfFamilySupport"` // Kurang Dukungan Keluarga + DecreasedDetermination bool `json:"decreasedDetermination"` // Penurunan Determinasi Ketika Komplikasi Meningkat + FinancialDifficultyDuringComplications bool `json:"financialDifficultyDuringComplications"` // Kendala Keuangan Ketika Komplikasi Meningkat + DischargeCriteriaNotMetOrDelayed bool `json:"dischargeCriteriaNotMetOrDelayed"` // Pemulangan/ Rujukan Belum Memenuhi Kriteria/ Ditunda +} + +type FormA struct { + Screening ScreeningEntry `json:"screening"` + AssessmentDetail string `json:"assessmentDetail"` // Masukkan detail assesmen + ProblemIdentification ProblemIdentification `json:"problemIdentification"` + PlanningDetail string `json:"planningDetail"` // Masukkan detail perencanaan +} + +func (s ScreeningEntry) SelectedScreeningLabels() []string { + result := []string{} + + if s.AgeAtRisk { + result = append(result, "Usia Dengan Risiko") + } + if s.LowCognitiveFunction { + result = append(result, "Pasien Dengan Fungsi Kognitif Rendah") + } + if s.HighRiskPatient { + result = append(result, "Pasien Dengan Risiko Tinggi") + } + if s.HighComplaintPotential { + result = append(result, "Potensi Komplain Tinggi (Medik dan Non Medik)") + } + if s.ChronicOrCatastrophicOrTerminal { + result = append(result, "Kasus Dengan Penyakit Kronis, Katastropik, Terminal") + } + if s.LowFunctionalStatus { + result = append(result, "Status Fungsional Rendah, Kebutuhan Bantuan ADL Tinggi") + } + if s.HistoryOfMedicalDeviceUse { + result = append(result, "Pasien Dengan Riwayat Penggunaan Peralatan Medis Masa Lalu") + } + if s.MentalOrSocialIssues { + result = append(result, "Riwayat Gangguan Mental, Bunuh Diri, Krisis Keluarga, Isu Sosial") + } + if s.FrequentERVisitsOrReadmission { + result = append(result, "Sering Masuk IGD, Readmisi RS") + } + if s.HighCareCostEstimate { + result = append(result, "Perkiraan Asuhan Dengan Biaya Tinggi") + } + if s.ComplexFinancingSystem { + result = append(result, "Kemungkinan Sistem Pembiayaan Yang Kompleks") + } + if s.AboveAverageLengthOfStay { + result = append(result, "Kasus Yang Melebihi Rata-Rata Lama Dirawat") + } + if s.ImportantOrHighRiskDischargePlanning { + result = append(result, "Rencana Pemulangan Penting / Kontinuitas Pelayanan") + } + if s.Stagnation { + result = append(result, "Stagnasi") + } + + return result +} + +func (p ProblemIdentification) SelectedProblemLabels() []string { + result := []string{} + + if p.CareNotFollowingGuidelines { + result = append(result, "Tingkat Asuhan Tidak Sesuai Panduan/ Norma") + } + if p.OverUtilization { + result = append(result, "Over Utilization Pelayanan") + } + if p.UnderUtilization { + result = append(result, "Under Utilization Pelayanan") + } + if p.PatientNonCompliance { + result = append(result, "Ketidakpatuhan Pasien") + } + if p.InadequateEducation { + result = append(result, "Edukasi Kurang Memadai") + } + if p.LackOfFamilySupport { + result = append(result, "Kurang Dukungan Keluarga") + } + if p.DecreasedDetermination { + result = append(result, "Penurunan Determinasi Ketika Komplikasi Meningkat") + } + if p.FinancialDifficultyDuringComplications { + result = append(result, "Kendala Keuangan Ketika Komplikasi Meningkat") + } + if p.DischargeCriteriaNotMetOrDelayed { + result = append(result, "Pemulangan/ Rujukan Belum Memenuhi Kriteria/ Ditunda") + } + + return result +} diff --git a/internal/domain/main-entities/screening/entity.go b/internal/domain/main-entities/screening/entity.go new file mode 100644 index 00000000..007573c4 --- /dev/null +++ b/internal/domain/main-entities/screening/entity.go @@ -0,0 +1,24 @@ +package screening + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + eem "simrs-vx/internal/domain/main-entities/employee" + + erc "simrs-vx/internal/domain/references/clinical" + erco "simrs-vx/internal/domain/references/common" +) + +type Screening struct { + ecore.Main // adjust this according to the needs + Encounter_Id *uint `json:"encounter_id"` + Employee_Id *uint `json:"employee_id"` + Employee *eem.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` + Type erc.ScreeningFormTypeCode `json:"type"` + Status erco.DataVerifiedCode `json:"status"` + Value *string `json:"value"` + FileUrl *string `json:"fileUrl" gorm:"size:1024"` +} + +func (d Screening) IsFormA() bool { + return d.Type == erc.SFTCA +} diff --git a/internal/domain/main-entities/soapi/dto.go b/internal/domain/main-entities/soapi/dto.go index b8f1b827..bc847b3b 100644 --- a/internal/domain/main-entities/soapi/dto.go +++ b/internal/domain/main-entities/soapi/dto.go @@ -32,21 +32,24 @@ type FilterDto struct { Encounter_Id *uint `json:"encounter-id"` Employee_Id *uint `json:"employee-id"` Time *time.Time `json:"time"` - TypeCode erc.SoapiTypeCode `json:"typeCode"` + TypeCode erc.SoapiTypeCode `json:"type-code"` Value *string `json:"value"` } type ReadDetailDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` + Includes string `json:"includes"` } type UpdateDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` CreateDto + pa.AuthInfo } type DeleteDto struct { - Id uint16 `json:"id"` + Id uint `json:"id"` + pa.AuthInfo } type MetaDto struct { @@ -62,7 +65,7 @@ type ResponseDto struct { Employee_Id *uint `json:"employee_id"` Employee *eem.Employee `json:"employee,omitempty"` Time *time.Time `json:"time"` - TypeCode erc.SoapiTypeCode `json:"typeCode"` + TypeCode erc.SoapiTypeCode `json:"type-code"` Value *string `json:"value"` } diff --git a/internal/domain/main-entities/soapi/entity.go b/internal/domain/main-entities/soapi/entity.go index 7e457ca9..d67f692a 100644 --- a/internal/domain/main-entities/soapi/entity.go +++ b/internal/domain/main-entities/soapi/entity.go @@ -17,6 +17,6 @@ type Soapi struct { Employee_Id *uint `json:"employee_id"` Employee *eem.Employee `json:"employee,omitempty" gorm:"foreignKey:Employee_Id;references:Id"` Time *time.Time `json:"time"` - TypeCode erc.SoapiTypeCode `json:"type_code" gorm:"size:11"` + TypeCode erc.SoapiTypeCode `json:"type_code" gorm:"size:15"` Value *string `json:"value"` } diff --git a/internal/domain/main-entities/specialist/dto.go b/internal/domain/main-entities/specialist/dto.go index a67a830f..2d656556 100644 --- a/internal/domain/main-entities/specialist/dto.go +++ b/internal/domain/main-entities/specialist/dto.go @@ -8,6 +8,7 @@ import ( ) type CreateDto struct { + Id *uint `json:"id"` Code string `json:"code" validate:"maxLength=10"` Name string `json:"name" validate:"maxLength=50"` Unit_Code *string `json:"unit_code"` diff --git a/internal/domain/main-entities/specialist/entity.go b/internal/domain/main-entities/specialist/entity.go index 4fef90a5..0b5b7a5d 100644 --- a/internal/domain/main-entities/specialist/entity.go +++ b/internal/domain/main-entities/specialist/entity.go @@ -9,9 +9,9 @@ import ( type Specialist struct { ecore.SmallMain // adjust this according to the needs - Code string `json:"code" gorm:"unique;size:10"` + Code string `json:"code" gorm:"unique;size:20"` Name string `json:"name" gorm:"size:50"` - Unit_Code *string `json:"unit_code" gorm:"size:10"` + Unit_Code *string `json:"unit_code" gorm:"size:20"` Unit *eu.Unit `json:"unit,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` SpecialistPositions []eub.Basic `json:"specialistPositions,omitempty" gorm:"foreignKey:Specialist_Code;references:Code"` Subspecialists []essb.Basic `json:"subspecialists,omitempty" gorm:"foreignKey:Specialist_Code;references:Code"` diff --git a/internal/domain/main-entities/subspecialist-position/dto.go b/internal/domain/main-entities/subspecialist-position/dto.go index 1c37a859..4918a8fe 100644 --- a/internal/domain/main-entities/subspecialist-position/dto.go +++ b/internal/domain/main-entities/subspecialist-position/dto.go @@ -8,7 +8,7 @@ import ( type CreateDto struct { Subspecialist_Code *string `json:"subspecialist_code" validate:"required"` - Code string `json:"code" validate:"maxLength=10;required"` + Code string `json:"code" validate:"maxLength=20;required"` Name string `json:"name" validate:"maxLength=30;required"` HeadStatus bool `json:"headStatus"` Employee_Id *uint `json:"employee_id"` diff --git a/internal/domain/main-entities/subspecialist/base/entity.go b/internal/domain/main-entities/subspecialist/base/entity.go index a94fb76d..9fe77039 100644 --- a/internal/domain/main-entities/subspecialist/base/entity.go +++ b/internal/domain/main-entities/subspecialist/base/entity.go @@ -6,9 +6,9 @@ import ( type Basic struct { ecore.SmallMain // adjust this according to the needs - Code string `json:"code" gorm:"unique;size:10"` + Code string `json:"code" gorm:"unique;size:20"` Name string `json:"name" gorm:"size:50"` - Specialist_Code *string `json:"specialist_code" gorm:"size:10"` + Specialist_Code *string `json:"specialist_code" gorm:"size:20"` } func (Basic) TableName() string { diff --git a/internal/domain/main-entities/subspecialist/dto.go b/internal/domain/main-entities/subspecialist/dto.go index 6e10b573..303da04f 100644 --- a/internal/domain/main-entities/subspecialist/dto.go +++ b/internal/domain/main-entities/subspecialist/dto.go @@ -7,7 +7,8 @@ import ( ) type CreateDto struct { - Code string `json:"code" validate:"maxLength=10"` + Id *uint `json:"id"` + Code string `json:"code" validate:"maxLength=20"` Name string `json:"name" validate:"maxLength=50"` Specialist_Code *string `json:"specialist_code"` } diff --git a/internal/domain/main-entities/therapy-protocol/dto.go b/internal/domain/main-entities/therapy-protocol/dto.go index 40633b89..a1d311dc 100644 --- a/internal/domain/main-entities/therapy-protocol/dto.go +++ b/internal/domain/main-entities/therapy-protocol/dto.go @@ -4,24 +4,27 @@ import ( ecore "simrs-vx/internal/domain/base-entities/core" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/encounter" - "simrs-vx/internal/domain/references/common" + erc "simrs-vx/internal/domain/references/common" + + pa "simrs-vx/internal/lib/auth" ) type CreateDto struct { - Encounter_Id *uint `json:"encounter_id"` - Doctor_Code *string `json:"doctor_code"` - Anamnesis *string `json:"anamnesis" validate:"maxLength=2048"` - MedicalDiagnoses *string `json:"medicalDiagnoses"` - FunctionDiagnoses *string `json:"functionDiagnoses"` - Procedures *string `json:"procedures"` - SupportingExams *string `json:"supportingExams" validate:"maxLength=2048"` - Instruction *string `json:"instruction" validate:"maxLength=2048"` - Evaluation *string `json:"evaluation" validate:"maxLength=2048"` - WorkCauseStatus *string `json:"workCauseStatus"` - Frequency *uint `json:"frequency"` - IntervalUnit_Code *common.TimeUnitCode `json:"intervalUnit_code" validate:"maxLength=10"` - Duration *uint `json:"duration"` - DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code" validate:"maxLength=10"` + Encounter_Id *uint `json:"encounter_id"` + Doctor_Code *string `json:"doctor_code"` + Anamnesis *string `json:"anamnesis" validate:"maxLength=2048"` + MedicalDiagnoses *string `json:"medicalDiagnoses"` + FunctionDiagnoses *string `json:"functionDiagnoses"` + Procedures *string `json:"procedures"` + SupportingExams *string `json:"supportingExams" validate:"maxLength=2048"` + Instruction *string `json:"instruction" validate:"maxLength=2048"` + Evaluation *string `json:"evaluation" validate:"maxLength=2048"` + WorkCauseStatus *string `json:"workCauseStatus"` + Frequency *uint `json:"frequency"` + IntervalUnit_Code *erc.TimeUnitCode `json:"intervalUnit_code" validate:"maxLength=10"` + Duration *uint `json:"duration"` + DurationUnit_Code *erc.TimeUnitCode `json:"durationUnit_code" validate:"maxLength=10"` + Status_Code *erc.DataVerifiedCode `json:"status_code"` } type ReadListDto struct { @@ -49,6 +52,13 @@ type DeleteDto struct { Id uint `json:"id"` } +type VerifyDto struct { + Id uint `json:"id"` + Status_Code erc.DataVerifiedCode `json:"status_code"` + + pa.AuthInfo +} + type MetaDto struct { PageNumber int `json:"page_number"` PageSize int `json:"page_size"` @@ -57,22 +67,23 @@ type MetaDto struct { type ResponseDto struct { ecore.Main - Encounter_Id *uint `json:"encounter_id"` - Encounter *ee.Encounter `json:"encounter,omitempty"` - Doctor_Code *string `json:"doctor_code"` - Doctor *ed.Doctor `json:"doctor,omitempty"` - Anamnesis *string `json:"anamnesis"` - MedicalDiagnoses *string `json:"medicalDiagnoses"` - FunctionDiagnoses *string `json:"functionDiagnoses"` - Procedures *string `json:"procedures"` - SupportingExams *string `json:"supportingExams"` - Instruction *string `json:"instruction"` - Evaluation *string `json:"evaluation"` - WorkCauseStatus *string `json:"workCauseStatus"` - Frequency *uint `json:"frequency"` - IntervalUnit_Code *common.TimeUnitCode `json:"intervalUnit_code"` - Duration *uint `json:"duration"` - DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code"` + Encounter_Id *uint `json:"encounter_id"` + Encounter *ee.Encounter `json:"encounter,omitempty"` + Doctor_Code *string `json:"doctor_code"` + Doctor *ed.Doctor `json:"doctor,omitempty"` + Anamnesis *string `json:"anamnesis"` + MedicalDiagnoses *string `json:"medicalDiagnoses"` + FunctionDiagnoses *string `json:"functionDiagnoses"` + Procedures *string `json:"procedures"` + SupportingExams *string `json:"supportingExams"` + Instruction *string `json:"instruction"` + Evaluation *string `json:"evaluation"` + WorkCauseStatus *string `json:"workCauseStatus"` + Frequency *uint `json:"frequency"` + IntervalUnit_Code *erc.TimeUnitCode `json:"intervalUnit_code"` + Duration *uint `json:"duration"` + DurationUnit_Code *erc.TimeUnitCode `json:"durationUnit_code"` + Status_Code *erc.DataVerifiedCode `json:"status_code"` } func (d TherapyProtocol) ToResponse() ResponseDto { @@ -93,6 +104,7 @@ func (d TherapyProtocol) ToResponse() ResponseDto { IntervalUnit_Code: d.IntervalUnit_Code, Duration: d.Duration, DurationUnit_Code: d.DurationUnit_Code, + Status_Code: d.Status_Code, } resp.Main = d.Main return resp diff --git a/internal/domain/main-entities/therapy-protocol/entity.go b/internal/domain/main-entities/therapy-protocol/entity.go index 7caaf0a6..e7607eea 100644 --- a/internal/domain/main-entities/therapy-protocol/entity.go +++ b/internal/domain/main-entities/therapy-protocol/entity.go @@ -16,16 +16,21 @@ type TherapyProtocol struct { Doctor_Code *string `json:"doctor_code"` Doctor *ed.Doctor `json:"doctor,omitempty" gorm:"foreignKey:Doctor_Code;references:Code"` - Anamnesis *string `json:"anamnesis" gorm:"size:2048"` - MedicalDiagnoses *string `json:"medicalDiagnoses"` - FunctionDiagnoses *string `json:"functionDiagnoses"` - Procedures *string `json:"procedures"` - SupportingExams *string `json:"supportingExams" gorm:"size:2048"` - Instruction *string `json:"instruction" gorm:"size:2048"` - Evaluation *string `json:"evaluation" gorm:"size:2048"` - WorkCauseStatus *string `json:"workCauseStatus" gorm:"size:2048"` - Frequency *uint `json:"frequency"` - IntervalUnit_Code *common.TimeUnitCode `json:"intervalUnit_code" gorm:"size:10"` - Duration *uint `json:"duration"` - DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code" gorm:"size:10"` + Anamnesis *string `json:"anamnesis" gorm:"size:2048"` + MedicalDiagnoses *string `json:"medicalDiagnoses"` + FunctionDiagnoses *string `json:"functionDiagnoses"` + Procedures *string `json:"procedures"` + SupportingExams *string `json:"supportingExams" gorm:"size:2048"` + Instruction *string `json:"instruction" gorm:"size:2048"` + Evaluation *string `json:"evaluation" gorm:"size:2048"` + WorkCauseStatus *string `json:"workCauseStatus" gorm:"size:2048"` + Frequency *uint `json:"frequency"` + IntervalUnit_Code *common.TimeUnitCode `json:"intervalUnit_code" gorm:"size:10"` + Duration *uint `json:"duration"` + DurationUnit_Code *common.TimeUnitCode `json:"durationUnit_code" gorm:"size:10"` + Status_Code *common.DataVerifiedCode `json:"status_code" gorm:"size:10"` +} + +func (d TherapyProtocol) IsNew() bool { + return d.Status_Code != nil && *d.Status_Code == common.DVCNew } diff --git a/internal/domain/main-entities/unit/dto.go b/internal/domain/main-entities/unit/dto.go index f272ecec..76151cb7 100644 --- a/internal/domain/main-entities/unit/dto.go +++ b/internal/domain/main-entities/unit/dto.go @@ -7,8 +7,9 @@ import ( ) type CreateDto struct { + Id *uint `json:"id"` Installation_Code *string `json:"installation_code"` - Code string `json:"code" validate:"maxLength=10"` + Code string `json:"code" validate:"maxLength=20"` Name string `json:"name" validate:"maxLength=50"` } diff --git a/internal/domain/main-entities/unit/entity.go b/internal/domain/main-entities/unit/entity.go index 97db9885..e8110db3 100644 --- a/internal/domain/main-entities/unit/entity.go +++ b/internal/domain/main-entities/unit/entity.go @@ -9,9 +9,9 @@ import ( type Unit struct { ecore.SmallMain // adjust this according to the needs - Installation_Code *string `json:"installation_code" gorm:"size:10"` + Installation_Code *string `json:"installation_code" gorm:"size:20"` Installation *ei.Installation `json:"installation" gorm:"foreignKey:Installation_Code;references:Code"` - Code string `json:"code" gorm:"unique;size:10"` + Code string `json:"code" gorm:"unique;size:20"` Name string `json:"name" gorm:"size:50"` Type_Code *ero.UnitTypeCode `json:"type_code"` UnitPositions []eub.Basic `json:"unitPositions,omitempty" gorm:"foreignKey:Unit_Code;references:Code"` diff --git a/internal/domain/main-entities/user/dto.go b/internal/domain/main-entities/user/dto.go index fd4b3f2c..bb030df3 100644 --- a/internal/domain/main-entities/user/dto.go +++ b/internal/domain/main-entities/user/dto.go @@ -13,22 +13,24 @@ import ( ) type CreateDto struct { - Name string `json:"name" validate:"maxLength=25"` - Password string `json:"password" validate:"maxLength=255"` + Name string `json:"name" validate:"required;maxLength=50"` + Password string `json:"password" validate:"required;maxLength=255"` + ContractPosition_Code erg.ContractPositionCode `json:"contractPosition_code" gorm:"not null;size:20" validate:"required"` Status_Code erc.UserStatusCode `json:"status_code" validate:"maxLength=10"` - Person_Id *uint `json:"-"` - Person *ep.UpdateDto `json:"person"` - PersonAddresses []epa.UpdateDto `json:"personAddresses"` - PersonContacts []epc.UpdateDto `json:"personContacts"` - Code *string `json:"code" validate:"maxLength=20"` - Employee *EmployeUpdateDto `json:"employee"` - IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` - SIP_Number *string `json:"sip_number" validate:"maxLength=20"` - Unit_Code *string `json:"unit_code"` - Infra_Code *string `json:"infra_code"` - Specialist_Code *string `json:"specialist_code"` - Subspecialist_Code *string `json:"subspecialist_code"` - ContractPosition_Code erg.ContractPositionCode `json:"contractPosition_code" gorm:"not null;size:20"` + + Employee *EmployeUpdateDto `json:"employee"` + Person *ep.UpdateDto `json:"person"` + PersonAddresses []epa.UpdateDto `json:"personAddresses"` + PersonContacts []epc.UpdateDto `json:"personContacts"` + Person_Id *uint `json:"-"` + Code *string `json:"code" validate:"maxLength=20"` + IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` + SIP_Number *string `json:"sip_number" validate:"maxLength=20"` + Installation_Code *string `json:"installation_code"` + Unit_Code *string `json:"unit_code"` + Specialist_Code *string `json:"specialist_code"` + Subspecialist_Code *string `json:"subspecialist_code"` + Infra_Code *string `json:"infra_code"` } type ReadListDto struct { @@ -87,11 +89,20 @@ func (d *User) ToResponse() ResponseDto { type EmployeUpdateDto struct { Id uint `json:"id"` User_Id *uint `json:"-"` - Person_Id *uint `json:"-"` Division_Code *string `json:"division_code"` Number *string `json:"number" validate:"maxLength=20"` Position_Code erg.EmployeePositionCode `json:"position_code" validate:"maxLength=20"` Status_Code erc.ActiveStatusCode `json:"status_code" validate:"maxLength=10"` + Person_Id *uint `json:"-"` + // TODO: Extras + // Code *string `json:"code" validate:"maxLength=20"` + // IHS_Number *string `json:"ihs_number" validate:"maxLength=20"` + // SIP_Number *string `json:"sip_number" validate:"maxLength=20"` + // Installation_Code *string `json:"installation_code"` + // Unit_Code *string `json:"unit_code"` + // Specialist_Code *string `json:"specialist_code"` + // Subspecialist_Code *string `json:"subspecialist_code"` + // Infra_Code *string `json:"infra_code"` } func ToResponseList(data []User) []ResponseDto { diff --git a/internal/domain/references/clinical/clinical.go b/internal/domain/references/clinical/clinical.go index f5190297..fc538677 100644 --- a/internal/domain/references/clinical/clinical.go +++ b/internal/domain/references/clinical/clinical.go @@ -9,6 +9,7 @@ type ( InstructionCode string HeadToToeCode string McuUrgencyLevelCode string + McuOrderStageCode string McuScopeCode string SoapiTypeCode string MedicalActionTypeCode string @@ -22,6 +23,15 @@ type ( LearnMethodCode string LangClassCode string TranslatorSrcCode string + ScreeningFormTypeCode string + SurgerySizeCode string + SurgerySystemCode string + SurgeryTypeCode string + SurgeryStageCode string + BornMortalityCode string + BornLocationCode string + SpecimentDestCode string + ProcedureReportType string ) const ( @@ -117,12 +127,18 @@ const ( MULCPF McuUrgencyLevelCode = "priority-form" // Form Prioritas MULCRT McuUrgencyLevelCode = "routine" // Pemeriksaan Rutin - //STCEarlyNurse SoapiTypeCode = "early-nurse" // Kajian Awal Medis - STCEEarlyMedic SoapiTypeCode = "early-medic" // Kajian Awal Rehab Medis - STCEarlyRehab SoapiTypeCode = "early-rehab" // Kajian Awal Rehab Medik - STCFunc SoapiTypeCode = "function" // Assessment Fungsi - STCProgress SoapiTypeCode = "progress" // CPPT - STCDevRecord SoapiTypeCode = "dev-record" // Catatan Perkembangan + MOSFirst McuOrderStageCode = "first" // Stage 1 + MOSSecond McuOrderStageCode = "repeat" // Stage 2 + + STCEarlyNurse SoapiTypeCode = "early-nursery" // Kajian Awal Keperawatan + STCEEarlyMedic SoapiTypeCode = "early-medic" // Kajian Awal Rehab Medis + STCEarlyRehab SoapiTypeCode = "early-rehab" // Kajian Awal Rehab Medik + STCFunc SoapiTypeCode = "function" // Assessment Fungsi + STCProgress SoapiTypeCode = "progress" // CPPT + STCDevRecord SoapiTypeCode = "dev-record" // Catatan Perkembangan + STCKfrAdm SoapiTypeCode = "kfr-adm" // soapi untuk kfr + STCKfrSeries SoapiTypeCode = "kfr-series" // soapi untuk kfr + STCAmbResume SoapiTypeCode = "amb-resume" // Rajal resume MATCChemo MedicalActionTypeCode = "chemo" MATCHemo MedicalActionTypeCode = "hemo" @@ -185,6 +201,48 @@ const ( TSCTeam TranslatorSrcCode = "team" // Tim Penerjemah TSCFamily TranslatorSrcCode = "family" // Keluarga + + SFTCA ScreeningFormTypeCode = "form-a" // Formu A + SFTCB ScreeningFormTypeCode = "form-b" // Formu B + MSCRadiology McuScopeCode = "radiology" + MSCCpLab McuScopeCode = "cp-lab" + MSCMicroLab McuScopeCode = "micro-lab" + MSCApLab McuScopeCode = "ap-lab" + + SSCSmall SurgerySizeCode = "small" + SSCMedium SurgerySizeCode = "medium" + SSCLarge SurgerySizeCode = "large" + SSCSpecial SurgerySizeCode = "special" + + SSyCCito SurgerySystemCode = "cito" + SSyCUrgent SurgerySystemCode = "urgent" + SSyCEfective SurgerySystemCode = "efective" + SSyCSpecial SurgerySystemCode = "special" + + STCClean SurgeryTypeCode = "clean" + STCCleanCtm SurgeryTypeCode = "clean-ctm" + STCUncleanCtm SurgeryTypeCode = "unclean-ctm" + STCUnclean SurgeryTypeCode = "unclean" + + SStCFirst SurgeryStageCode = "first" + SStCRepeat SurgeryStageCode = "repeat" + + BMCAlive BornMortalityCode = "alive" + BMCDead BornMortalityCode = "dead" + + BLCExtMiw BornLocationCode = "ext-miw" + BLCExtDoc BornLocationCode = "ext-doc" + BLCTradMiw BornLocationCode = "trad-miw" + BLCLocalMed BornLocationCode = "local-med" + BLCExtParamedic BornLocationCode = "ext-paramedic" + + SDCAp SpecimentDestCode = "ap" + SDCMicro SpecimentDestCode = "micro" + SDCLab SpecimentDestCode = "lab" + SDCNone SpecimentDestCode = "none" + + PRTProcedure ProcedureReportType = "procedure" + PRTSurgery ProcedureReportType = "surgery" ) type Soapi struct { @@ -309,3 +367,64 @@ type HeadToToe struct { Neuron string `json:"neuron,omitempty"` BodyOthers string `json:"body-others,omitempty"` } + +type ProcedureRecord struct { + Procedures []CodeWithName `json:"procedures"` +} + +type ProcedureExecution struct { + SurgerySize_Code *string `json:"surgerySize_code"` + Billing_Code *string `json:"billing_code"` + SurgerySystem_Code *string `json:"surgerySystem_code"` + StartAt *string `json:"startAt"` + EndAt *string `json:"endAt"` + AnesthesiaStartAt *string `json:"anesthesiaStartAt"` + AnesthesiaEndAt *string `json:"anesthesiaEndAt"` + SurgeryType_Code *string `json:"surgeryType_code"` + SurgeryStage_Code *string `json:"surgeryStage_code"` + BornMortality_Code *string `json:"bornMortality_code"` + BornLocation_Code *string `json:"bornLocation_code"` + Weight *string `json:"weight"` + BornNotes *string `json:"bornNotes" gorm:"size:1024"` + Description *string `json:"notes" gorm:"size:1024"` + BleedingAmount *uint16 `json:"bleedingAmount"` + BloodInType_Code *string `json:"bloodInType_code"` + BloodInAmount *uint16 `json:"bloodInAmount"` + Brand *string `json:"brand" gorm:"size:100"` + ImplantName *string `json:"implantName" gorm:"size:100"` + ImplantRegisterNumber *string `json:"implantRegisterNumber" gorm:"size:100"` + ImplantCompanionName *string `json:"implantCompanionName" gorm:"size:100"` + SpecimentDest_Code *string `json:"specimentDest" gorm:"size:100"` + TissueInfo []string `json:"tissueInfo" gorm:"size:100"` +} + +type SoapiSrc struct { + Id string `json:"id,omitempty"` + Code string `json:"code,omitempty"` + Name string `json:"name,omitempty"` + IndName string `json:"indName,omitempty"` +} + +type EarlyMedicValue struct { + Vaccinated bool `json:"vaccinated,omitempty"` + CaseStatus int `json:"case-status,omitempty"` + EncounterStatus int `json:"encounter-status,omitempty"` + PrimaryComplain string `json:"pri-complain,omitempty"` + CurrentDiseaseHistory string `json:"cur-disea-hist,omitempty"` + SpO2 int `json:"spo2,omitempty"` + SystolicBloodPressure int `json:"syst-bp,omitempty"` + DiastolicBloodPressure int `json:"diast-bp,omitempty"` + RespiratoryRate int `json:"resp-rate,omitempty"` + Pulse int `json:"pulse,omitempty"` + Weight int `json:"weight,omitempty"` + BloodType string `json:"blood-type,omitempty"` + Temperature int `json:"temp,omitempty"` + Height int `json:"height,omitempty"` + PhysicalExamination string `json:"physical-exam,omitempty"` + DiagnoseSrc []SoapiSrc `json:"diagnoseSrc,omitempty"` + ProcedureSrc []SoapiSrc `json:"procedureSrc,omitempty"` + EarlyMedicDiagnose string `json:"early-med-diag,omitempty"` + EarlyMedicPlan string `json:"early-med-plan,omitempty"` + Therapy string `json:"therapy,omitempty"` + ExpectedOutcome []SoapiSrc `json:"expected-outcome,omitempty"` +} diff --git a/internal/domain/references/common/common.go b/internal/domain/references/common/common.go index 2941049c..3a449057 100644 --- a/internal/domain/references/common/common.go +++ b/internal/domain/references/common/common.go @@ -16,6 +16,8 @@ type ( DataVerifiedCode string CrudCode string DataApprovalCode string + ProcessStatusCode string + DocFormatTypeCode string ) const ( @@ -58,6 +60,7 @@ const ( SCInactive ActiveStatusCode = "inactive" // Tidak aktif DSCNew DataStatusCode = "new" // Baru + DSCSubmited DataStatusCode = "submited" // Submited DSCReview DataStatusCode = "review" // Review DSCProcess DataStatusCode = "process" // Proses DSCDone DataStatusCode = "done" // Selesai @@ -69,9 +72,11 @@ const ( DACAvailable DataAvailabilityCode = "available" // Tersedia DACUnavailable DataAvailabilityCode = "unavailable" // Tidak Tersedia - DVCNew DataVerifiedCode = "new" // Baru - DVCVerified DataVerifiedCode = "verified" // Terverifikasi - DVCRejected DataVerifiedCode = "rejected" // Ditolak + DVCNew DataVerifiedCode = "new" // Baru + DVCVerified DataVerifiedCode = "verified" // Terverifikasi + DVCValidated DataVerifiedCode = "validated" // Tervalidasi + DVCCancelled DataVerifiedCode = "cancelled" // Dibatalkan + DVCRejected DataVerifiedCode = "rejected" // Ditolak USCNew UserStatusCode = "new" // Baru USCActive UserStatusCode = "active" // Aktif @@ -101,6 +106,15 @@ const ( DACNew DataApprovalCode = "new" DACApproved DataApprovalCode = "approved" DACRejected DataApprovalCode = "rejected" + DACCanceled DataApprovalCode = "canceled" + + PSCSuccess ProcessStatusCode = "success" + PSCFailed ProcessStatusCode = "failed" + + DFTCPDF DocFormatTypeCode = "pdf" + DFTCTXLSX DocFormatTypeCode = "xlsx" + DFTCTCSV DocFormatTypeCode = "csv" + DFTCTXLS DocFormatTypeCode = "xls" ) func GetDayCodes() map[DayCode]string { diff --git a/internal/domain/references/encounter/encounter.go b/internal/domain/references/encounter/encounter.go index dc3dd09e..83ef759b 100644 --- a/internal/domain/references/encounter/encounter.go +++ b/internal/domain/references/encounter/encounter.go @@ -1,5 +1,7 @@ package encounter +import "fmt" + type ( EncounterClassCode string QueueStatusCode string @@ -18,6 +20,9 @@ type ( SEPRefTypeCode string VisitModeCode string PolySwitchCode string + DocTypeCode string + EntityTypeCode string + StatusProtocolChemo string ) const ( @@ -91,10 +96,11 @@ const ( RTCPrivate RefTypeCode = "private" // Swasta RTCBpjs RefTypeCode = "bpjs" // BPJS - APMCJkn AllPaymentMethodCode = "jkn" // JKN - APMCJkmm AllPaymentMethodCode = "jkmm" // JKMM - APMCSpm AllPaymentMethodCode = "spm" // SPM - APMCPks AllPaymentMethodCode = "pks" // PKS + APMCJkn AllPaymentMethodCode = "jkn" // JKN -> Jaminan Kesehatan Nasional -> BPJS Kesehatan + APMCJkmm AllPaymentMethodCode = "jkmm" // JKMM -> Jaminan Kesehatan Masyarakat Miskin -> Dibiayai oleh APBD daerah + APMCSpm AllPaymentMethodCode = "spm" // SPM -> Surat Pernyataan Miskin + APMCPks AllPaymentMethodCode = "pks" // PKS -> Perjanjian Kerjasama -> Pembayaran melalui instansi atau perusahaan yang memiliki kontrak dengan rumah sakit + APMCUmum AllPaymentMethodCode = "umum" SRTCInternal SEPRefTypeCode = "internal" // Rujukan Internal SRTCExternal SEPRefTypeCode = "external" // Faskes Lain @@ -104,6 +110,29 @@ const ( PSCConsulPoly PolySwitchCode = "consul-poly" // Konsultasi Poliklinik Lain PSCConsulExecutive PolySwitchCode = "consul-executive" // Konsultasi Antar Dokter Eksekutif + + DTCPRN DocTypeCode = "person-resident-number" // Person Resident Number + DTCPDL DocTypeCode = "person-driver-license" // Person Driver License + DTCPP DocTypeCode = "person-passport" // Person Passport + DTCPFC DocTypeCode = "person-family-card" // Person Family Card + DTCMIR DocTypeCode = "mcu-item-result" // Mcu Item Result + DTCEnPatient DocTypeCode = "encounter-patient" + DTCEnSupport DocTypeCode = "encounter-support" + DTCEnOther DocTypeCode = "encounter-other" + DTCSEP DocTypeCode = "vclaim-sep" // SEP + DTCSIPP DocTypeCode = "vclaim-sipp" // SIPP + DTCGC DocTypeCode = "general-consent" + DTCVSCL DocTypeCode = "vclaim-control-letter" // vclaim control letter + DTCResume DocTypeCode = "resume" // Resume + DTCScreening DocTypeCode = "screening" // Screening + + ETCPerson EntityTypeCode = "person" + ETCEncounter EntityTypeCode = "encounter" + ETCMCU EntityTypeCode = "mcu" + + SPCComplete StatusProtocolChemo = "complete" + SPCPlanned StatusProtocolChemo = "planned" + SPCSchedule StatusProtocolChemo = "schedule" ) func (ec EncounterClassCode) Code() string { @@ -118,3 +147,30 @@ func (ec EncounterClassCode) Code() string { return "UNKNOWN" } } + +var validUploadCodesByEntity = map[EntityTypeCode][]DocTypeCode{ + ETCPerson: { + DTCPRN, DTCPDL, DTCPP, DTCPFC, + }, + ETCEncounter: { + DTCSEP, DTCSIPP, DTCEnPatient, DTCEnSupport, DTCGC, DTCEnOther, + }, + ETCMCU: { + DTCMIR, + }, +} + +func IsValidUploadCode(entity EntityTypeCode, code DocTypeCode) (bool, string) { + allowedCodes, ok := validUploadCodesByEntity[entity] + if !ok { + return false, fmt.Sprintf("unknown entityType_code: %s", entity) + } + + for _, c := range allowedCodes { + if c == code { + return true, "" + } + } + + return false, fmt.Sprintf("invalid doctype_code '%s' for entityType_code '%s'", code, entity) +} diff --git a/internal/domain/references/organization/organization.go b/internal/domain/references/organization/organization.go index 09b19dce..d20b828e 100644 --- a/internal/domain/references/organization/organization.go +++ b/internal/domain/references/organization/organization.go @@ -1,13 +1,15 @@ package organization type ( - ContractPositionCode string - EmployeePositionCode string - InternPosisitionCode string - ItemGroupCode string - InfraGroupCode string - UnitTypeCode string - DoctorFeeTypeCode string + ContractPositionCode string + EmployeePositionCode string + InternPosisitionCode string + ItemGroupCode string + InfraGroupCode string + ProdcedureRoomTypeCode string + UnitTypeCode string + DoctorFeeTypeCode string + ActionBillingCode string ) const ( @@ -18,14 +20,17 @@ const ( EPCReg EmployeePositionCode = "reg" // Admisi/Pendaftaran EPCNur EmployeePositionCode = "nur" // Perawat EPCDoc EmployeePositionCode = "doc" // Dokter - EPCNut EmployeePositionCode = "nut" // Ahli gizi EPCMwi EmployeePositionCode = "miw" // Bidan + EPCThr EmployeePositionCode = "thr" // Terapis + EPCNut EmployeePositionCode = "nut" // Ahli gizi EPCLab EmployeePositionCode = "lab" // Laboran EPCPha EmployeePositionCode = "pha" // Farmasi - EPCPay EmployeePositionCode = "pay" // Pembayaran - EPCHur EmployeePositionCode = "hue" // Sumber Daya Manusia - EPCGea EmployeePositionCode = "gea" // Bagian Umum - EPCMan EmployeePositionCode = "man" // Manajemen + EPCNom EmployeePositionCode = "nom" // Non Medic + EPCScr EmployeePositionCode = "scr" // Screening MPP + // EPCPay EmployeePositionCode = "pay" // Pembayaran + // EPCHur EmployeePositionCode = "hue" // Sumber Daya Manusia + // EPCGea EmployeePositionCode = "gea" // Bagian Umum + // EPCMan EmployeePositionCode = "man" // Manajemen IPCSpecialist = "specialist-intern" IPCNurse = "nurse-intern" @@ -40,14 +45,17 @@ const ( ITGCDocFee ItemGroupCode = "doctor-fee" ITGCMedAct ItemGroupCode = "medical-action" - IFGCBuilding InfraGroupCode = "building" // Bangunan - IFGCFloor InfraGroupCode = "floor" // Lantai - IFGCRoom InfraGroupCode = "room" // Ruang - IFGCChamber InfraGroupCode = "chamber" // Kamar - IFGCBed InfraGroupCode = "bed" // Ranjang - IFGCWarehouse InfraGroupCode = "warehouse" // Gudang/Depo - IFGCCounter InfraGroupCode = "counter" // Counter - IFGCPubScreen InfraGroupCode = "public-screen" // Public Screen + IFGCBuilding InfraGroupCode = "building" // Bangunan + IFGCFloor InfraGroupCode = "floor" // Lantai + IFGCProcedureRoom InfraGroupCode = "procedure-room" // Ruang Tindakan + IFGCChamber InfraGroupCode = "chamber" // Kamar + IFGCBed InfraGroupCode = "bed" // Ranjang + IFGCWarehouse InfraGroupCode = "warehouse" // Gudang/Depo + IFGCCounter InfraGroupCode = "counter" // Counter + IFGCPubScreen InfraGroupCode = "public-screen" // Public Screen + + PRTCProcedure ProdcedureRoomTypeCode = "procedure" // Ringan + PRTCOperating ProdcedureRoomTypeCode = "operating" // Dikamarkan UTCReg UnitTypeCode = "reg" // Registrasi UTCExa UnitTypeCode = "exa" // Pemeriksaan @@ -60,4 +68,8 @@ const ( DFTCInp DoctorFeeTypeCode = "inpatient" // Rawat Inap DFTCEme DoctorFeeTypeCode = "emergency" // Darurat DFTCReh DoctorFeeTypeCode = "medic-rehab" // Rehab Medik + + ABCGeneral ActionBillingCode = "general" + ABCRegional ActionBillingCode = "regional" + ABCLocal ActionBillingCode = "local" ) diff --git a/internal/domain/references/person/person.go b/internal/domain/references/person/person.go index 1648b578..dfd35179 100644 --- a/internal/domain/references/person/person.go +++ b/internal/domain/references/person/person.go @@ -112,6 +112,9 @@ const ( RCNephew RelationshipCode = "nephew" // Keponakan RCGdChild RelationshipCode = "gd-child" // Cucu RCOther RelationshipCode = "other" // Lainnya + RCFriend RelationshipCode = "friend" // Teman + RCSpouse RelationshipCode = "spouse" // Pasangan (Suami / Istri) + RCSelf RelationshipCode = "self" // Diri Sendiri ALTCIdn AddressLocationTypeCode = "identity" // Sesuai Identitas ALTCDom AddressLocationTypeCode = "domicile" // Sesuai Domisili diff --git a/internal/domain/references/upload/upload.go b/internal/domain/references/upload/upload.go deleted file mode 100644 index 603be6c8..00000000 --- a/internal/domain/references/upload/upload.go +++ /dev/null @@ -1,49 +0,0 @@ -package upload - -import "fmt" - -type ( - UploadCode string - EntityTypeCode string -) - -const ( - UCPRN UploadCode = "person-resident-number" // Person Resident Number - UCPDL UploadCode = "person-driver-license" // Person Driver License - UCPP UploadCode = "person-passport" // Person Passport - UCPFC UploadCode = "person-family-card" // Person Family Card - UCMIR UploadCode = "mcu-item-result" // Mcu Item Result - UCSEP UploadCode = "vclaim-sep" // SEP - UCSIPP UploadCode = "vclaim-sipp" // SIPP - - ETCPerson EntityTypeCode = "person" - ETCEncounter EntityTypeCode = "encounter" - ETCMCU EntityTypeCode = "mcu" -) - -var validUploadCodesByEntity = map[EntityTypeCode][]UploadCode{ - ETCPerson: { - UCPRN, UCPDL, UCPP, UCPFC, - }, - ETCEncounter: { - UCSEP, UCSIPP, - }, - ETCMCU: { - UCMIR, - }, -} - -func IsValidUploadCode(entity EntityTypeCode, code UploadCode) (bool, string) { - allowedCodes, ok := validUploadCodesByEntity[entity] - if !ok { - return false, fmt.Sprintf("unknown entityType_code: %s", entity) - } - - for _, c := range allowedCodes { - if c == code { - return true, "" - } - } - - return false, fmt.Sprintf("invalid upload_code '%s' for entityType_code '%s'", code, entity) -} diff --git a/internal/domain/simgos-entities/m-instalasi/entity.go b/internal/domain/simgos-entities/m-instalasi/entity.go new file mode 100644 index 00000000..bbeb3ed7 --- /dev/null +++ b/internal/domain/simgos-entities/m-instalasi/entity.go @@ -0,0 +1,12 @@ +package m_instalasi + +type MInstalasi struct { + No_Instalasi uint `json:"no_instalasi" gorm:"primaryKey;autoIncrement;column:no_instalasi"` + Nama_Instalasi string `json:"nama_instalasi" gorm:"column:nama_instalasi"` + Status_Rawat_Inap uint `json:"status_rawat_inap" gorm:"column:status_rawat_inap"` + St_Aktif uint `json:"st_aktif" gorm:"column:st_aktif"` +} + +func (MInstalasi) TableName() string { + return "m_instalasi" +} diff --git a/internal/domain/simgos-entities/m-pasien/dto.go b/internal/domain/simgos-entities/m-pasien/dto.go new file mode 100644 index 00000000..8d2c3368 --- /dev/null +++ b/internal/domain/simgos-entities/m-pasien/dto.go @@ -0,0 +1,273 @@ +package m_pasien + +import ( + "fmt" + ecore "simrs-vx/internal/domain/base-entities/core" + e "simrs-vx/internal/domain/main-entities/patient" + pr "simrs-vx/internal/domain/main-entities/person" + pa "simrs-vx/internal/domain/main-entities/person-address" + pab "simrs-vx/internal/domain/main-entities/person-address/base" + pc "simrs-vx/internal/domain/main-entities/person-contact" + rf "simrs-vx/internal/domain/references/person" + + "time" +) + +type MPasienDto struct { + Id uint `json:"id" gorm:"primaryKey;autoIncrement;column:id"` + Nomr string `json:"nomr" gorm:"uniqueIndex;column:nomr"` + Title string `json:"title" gorm:"column:title"` + Nama string `json:"nama" gorm:"column:nama"` + Tempat string `json:"tempat" gorm:"column:tempat"` + Tgllahir string `json:"tgllahir" gorm:"column:tgllahir"` + Jeniskelamin string `json:"jeniskelamin" gorm:"column:jeniskelamin"` + Alamat string `json:"alamat" gorm:"column:alamat"` + Kelurahan uint64 `json:"kelurahan" gorm:"column:kelurahan"` + Kdkecamatan uint `json:"kdkecamatan" gorm:"column:kdkecamatan"` + Kota uint `json:"kota" gorm:"column:kota"` + Kdprovinsi uint `json:"kdprovinsi" gorm:"column:kdprovinsi"` + Notelp string `json:"notelp" gorm:"column:notelp"` + Noktp string `json:"noktp" gorm:"column:noktp"` + SuamiOrtu *string `json:"suami_ortu" gorm:"column:suami_ortu"` + Pekerjaan string `json:"pekerjaan" gorm:"column:pekerjaan"` + Status uint `json:"status" gorm:"column:status"` + Agama uint `json:"agama" gorm:"column:agama"` + Pendidikan uint `json:"pendidikan" gorm:"column:pendidikan"` + Kdcarabayar *uint `json:"kdcarabayar" gorm:"column:kdcarabayar"` + Nip *string `json:"nip" gorm:"column:nip"` + Tgldaftar string `json:"tgldaftar" gorm:"column:tgldaftar"` + AlamatKtp string `json:"alamat_ktp" gorm:"column:alamat_ktp"` + ParentNomr *string `json:"parent_nomr" gorm:"column:parent_nomr"` + Kepercayaan string `json:"kepercayaan" gorm:"column:kepercayaan"` + PenanggungjawabNama string `json:"penanggungjawab_nama" gorm:"column:penanggungjawab_nama"` + PenanggungjawabHubungan string `json:"penanggungjawab_hubungan" gorm:"column:penanggungjawab_hubungan"` + PenanggungjawabAlamat string `json:"penanggungjawab_alamat" gorm:"column:penanggungjawab_alamat"` + PenanggungjawabPhone string `json:"penanggungjawab_phone" gorm:"column:penanggungjawab_phone"` + NoKartu string `json:"no_kartu" gorm:"column:no_kartu"` + JnsPasien string `json:"jns_pasien" gorm:"column:jns_pasien"` + Nk *string `json:"nk" gorm:"column:nk"` + Kdprovider *string `json:"kdprovider" gorm:"column:kdprovider"` + Nmprovider *string `json:"nmprovider" gorm:"column:nmprovider"` + Kelas *uint `json:"kelas" gorm:"column:kelas"` + Sim *string `json:"sim" gorm:"column:sim"` + Paspor *string `json:"paspor" gorm:"column:paspor"` + Disabilitas *string `json:"disabilitas" gorm:"column:disabilitas"` + Bahasa string `json:"bahasa" gorm:"column:bahasa"` + HambatanKomunikasi string `json:"hambatan_komunikasi" gorm:"column:hambatan_komunikasi"` + Kebangsaan string `json:"kebangsaan" gorm:"column:kebangsaan"` + Notelprumah1 string `json:"notelprumah1" gorm:"column:notelprumah1"` + Notelprumah2 *string `json:"notelprumah2" gorm:"column:notelprumah2"` + Notelpkantor string `json:"notelpkantor" gorm:"column:notelpkantor"` + NoHp *string `json:"no_hp" gorm:"column:no_hp"` + AsalMasuk *string `json:"asal_masuk" gorm:"column:asal_masuk"` + Diagnosa *string `json:"diagnosa" gorm:"column:diagnosa"` + DiagnosaUtama *string `json:"diagnosa_utama" gorm:"column:diagnosa_utama"` + Suku string `json:"suku" gorm:"column:suku"` + AgamaLain string `json:"agama_lain" gorm:"column:agama_lain"` + StDisabilitas uint `json:"stDisabilitas" gorm:"column:st_disabilitas"` + TxtKelurahan string `json:"txt_kelurahan" gorm:"column:txt_kelurahan"` + TxtKecamatan string `json:"txt_kecamatan" gorm:"column:txt_kecamatan"` + TxtKota string `json:"txt_kota" gorm:"column:txt_kota"` + TxtProvinsi string `json:"txt_provinsi" gorm:"column:txt_provinsi"` + TxtStatus string `json:"txt_status" gorm:"column:txt_status"` + TxtAgama string `json:"txt_agama" gorm:"column:txt_agama"` + TxtPendidikan string `json:"txt_pendidikan" gorm:"column:txt_pendidikan"` + NamaAyah string `json:"nama_ayah" gorm:"column:nama_ayah"` + NamaIbu string `json:"nama_ibu" gorm:"column:nama_ibu"` + PendidikanAyah string `json:"pendidikan_ayah" gorm:"column:pendidikan_ayah"` + PendidikanIbu string `json:"pendidikan_ibu" gorm:"column:pendidikan_ibu"` + StIdentitasOrtu int `json:"st_identitas_ortu" gorm:"column:st_identitas_ortu"` + NomrBaru *string `json:"nomr_baru" gorm:"column:nomr_baru"` + KtpFile *string `json:"ktp_file" gorm:"column:ktp_file"` + KkFile *string `json:"kk_file" gorm:"column:kk_file"` + CreatedAt *time.Time `json:"created_at" gorm:"column:created_at"` + UpdatedAt *time.Time `json:"updated_at" gorm:"column:updated_at"` + NoKk *string `json:"no_kk" gorm:"column:no_kk"` + NoktpBaru string `json:"noktp_baru" gorm:"column:noktp_baru"` +} + +func (mp MPasienDto) ToPatient() e.Patient { + + patient := e.Patient{ + Main: ecore.Main{ + Id: mp.Id, + }, + NewBornStatus: mp.ParentNomr != nil, + RegisteredAt: parseTimeDateOnly(mp.Tgldaftar), + RegisteredBy_User_Name: mp.Nip, + Number: &mp.Nomr, + Parent_Number: mp.ParentNomr, + // Status_Code: getActiveStatus(mp.Status), + // mp.Status is marital status + // Parent + } + + // person + gc := getGender(mp.Jeniskelamin) + rc := getReligion(mp.Agama) + ec := getEducation(mp.Pendidikan) + mc := getMaritalStatus(mp.Status) + bc := getBirthRegencyCode(mp.Tempat) + et := getEthnicCode(mp.Suku) + lc := getLanguageCode(mp.Bahasa) + + person := pr.Person{ + Name: mp.Nama, + FrontTitle: &mp.Title, + BirthDate: parseTimeDateOnly(mp.Tgllahir), + BirthRegency_Code: &bc, + Gender_Code: &gc, + ResidentIdentityNumber: nilEmptyString(&mp.Noktp), + PassportNumber: nilEmptyString(mp.Paspor), + DrivingLicenseNumber: nilEmptyString(mp.Sim), + Religion_Code: &rc, + Education_Code: &ec, + Ocupation_Name: &mp.Pekerjaan, + MaritalStatus_Code: &mc, + Nationality: &mp.Kebangsaan, + Ethnic_Code: &et, + Language_Code: &lc, + CommunicationIssueStatus: mp.HambatanKomunikasi == "Y", + Disability: mp.Disabilitas, + ResidentIdentityFileUrl: mp.KtpFile, + FamilyIdentityFileUrl: mp.KkFile, + // EndTitle + // Confidence + // Ocupation_Code + } + var addresses []pa.PersonAddress + if mp.Alamat != "" { + vc := fmt.Sprintf("%d", mp.Kelurahan) + addresses = append(addresses, pa.PersonAddress{ + PersonAddress: pab.PersonAddress{ + Address: mp.Alamat, + LocationType_Code: rf.ALTCDom, + Village_Code: &vc, + }, + }) + } + if mp.AlamatKtp != "" { + addresses = append(addresses, pa.PersonAddress{ + PersonAddress: pab.PersonAddress{ + Address: mp.AlamatKtp, + LocationType_Code: rf.ALTCIdn, + }, + }) + } + + var contacts []pc.PersonContact + + if mp.NoHp != nil { + + } + + person.Addresses = &addresses + person.Contacts = &contacts + patient.Person = &person + return patient +} + +func nilEmptyString(s *string) *string { + if s == nil { + return nil + } + return s +} + +func getGender(g string) rf.GenderCode { + if g == "L" { + return rf.GCMale + } else if g == "P" { + return rf.GCFemale + } + return rf.GCUnknown + +} + +func getReligion(r uint) rf.ReligionCode { + switch r { + case 1: + return rf.RCIslam + case 2: + return rf.RCProtestan + case 3: + return rf.RCKatolik + case 4: + return rf.RCHindu + case 5: + return rf.RCBudha + case 6: + return rf.RCKonghucu + default: + // 9 "Lainnya" + // 0 "Tidak diketahui" + return "" + } +} + +func getEducation(e uint) rf.EducationCode { + switch e { + case 0: + return rf.ECTS + case 1: + return rf.ECSD + case 2: + return rf.ECSLTP + case 3: + return rf.ECSLTA + case 4: + return rf.ECD3 + case 5: + return rf.ECS1 + case 6: + return rf.ECOther + case 7: + return rf.ECUnkown + default: + return rf.ECUnkown + } +} + +func getMaritalStatus(m uint) rf.MaritalStatusCode { + switch m { + case 1: + return rf.MaritalStatusSingle // S + case 2: + return rf.MaritalStatusMarried // M + case 3: + return rf.MaritalStatusWidowed // W + case 4: + return rf.MaritalStatusDivorced // D + default: + return "" // unknown + } +} + +func getBirthRegencyCode(r string) string { + if r != "" { + // TODO get from database + } + return "3574" +} + +func getEthnicCode(s string) string { + if s != "" { + // TODO check database + } + return "jawa" +} + +func getLanguageCode(s string) string { + if s != "" { + // TODO check database + } + return "jawa" +} + +func parseTimeDateOnly(d string) *time.Time { + do, err := time.Parse("2006-01-02", d) + if err == nil { + return &do + } + return nil +} diff --git a/internal/domain/simgos-entities/m-pasien/entity.go b/internal/domain/simgos-entities/m-pasien/entity.go new file mode 100644 index 00000000..f2bacfd9 --- /dev/null +++ b/internal/domain/simgos-entities/m-pasien/entity.go @@ -0,0 +1,80 @@ +package m_pasien + +import "time" + +type MPasien struct { + Id uint `json:"id" gorm:"primaryKey;autoIncrement;column:id"` + Nomr string `json:"nomr" gorm:"uniqueIndex;column:nomr"` + Title string `json:"title" gorm:"column:title"` + Nama string `json:"nama" gorm:"column:nama"` + Tempat string `json:"tempat" gorm:"column:tempat"` + Tgllahir *time.Time `json:"tgllahir" gorm:"column:tgllahir"` + Jeniskelamin string `json:"jeniskelamin" gorm:"column:jeniskelamin"` + Alamat string `json:"alamat" gorm:"column:alamat"` + Kelurahan uint64 `json:"kelurahan" gorm:"column:kelurahan"` + Kdkecamatan uint `json:"kdkecamatan" gorm:"column:kdkecamatan"` + Kota uint `json:"kota" gorm:"column:kota"` + Kdprovinsi uint `json:"kdprovinsi" gorm:"column:kdprovinsi"` + Notelp string `json:"notelp" gorm:"column:notelp"` + Noktp string `json:"noktp" gorm:"column:noktp"` + SuamiOrtu *string `json:"suami_ortu" gorm:"column:suami_ortu"` + Pekerjaan string `json:"pekerjaan" gorm:"column:pekerjaan"` + Status uint `json:"status" gorm:"column:status"` + Agama uint `json:"agama" gorm:"column:agama"` + Pendidikan uint `json:"pendidikan" gorm:"column:pendidikan"` + Kdcarabayar *uint `json:"kdcarabayar" gorm:"column:kdcarabayar"` + Nip *string `json:"nip" gorm:"column:nip"` + Tgldaftar *time.Time `json:"tgldaftar" gorm:"column:tgldaftar"` + AlamatKtp string `json:"alamat_ktp" gorm:"column:alamat_ktp"` + ParentNomr *string `json:"parent_nomr" gorm:"column:parent_nomr"` + Kepercayaan string `json:"kepercayaan" gorm:"column:kepercayaan"` + PenanggungjawabNama string `json:"penanggungjawab_nama" gorm:"column:penanggungjawab_nama"` + PenanggungjawabHubungan string `json:"penanggungjawab_hubungan" gorm:"column:penanggungjawab_hubungan"` + PenanggungjawabAlamat string `json:"penanggungjawab_alamat" gorm:"column:penanggungjawab_alamat"` + PenanggungjawabPhone string `json:"penanggungjawab_phone" gorm:"column:penanggungjawab_phone"` + NoKartu string `json:"no_kartu" gorm:"column:no_kartu"` + JnsPasien string `json:"jns_pasien" gorm:"column:jns_pasien"` + Nk *string `json:"nk" gorm:"column:nk"` + Kdprovider *string `json:"kdprovider" gorm:"column:kdprovider"` + Nmprovider *string `json:"nmprovider" gorm:"column:nmprovider"` + Kelas *uint `json:"kelas" gorm:"column:kelas"` + Sim *string `json:"sim" gorm:"column:sim"` + Paspor *string `json:"paspor" gorm:"column:paspor"` + Disabilitas *string `json:"disabilitas" gorm:"column:disabilitas"` + Bahasa string `json:"bahasa" gorm:"column:bahasa"` + HambatanKomunikasi string `json:"hambatan_komunikasi" gorm:"column:hambatan_komunikasi"` + Kebangsaan string `json:"kebangsaan" gorm:"column:kebangsaan"` + Notelprumah1 string `json:"notelprumah1" gorm:"column:notelprumah1"` + Notelprumah2 *string `json:"notelprumah2" gorm:"column:notelprumah2"` + Notelpkantor string `json:"notelpkantor" gorm:"column:notelpkantor"` + NoHp *string `json:"no_hp" gorm:"column:no_hp"` + AsalMasuk *string `json:"asal_masuk" gorm:"column:asal_masuk"` + Diagnosa *string `json:"diagnosa" gorm:"column:diagnosa"` + DiagnosaUtama *string `json:"diagnosa_utama" gorm:"column:diagnosa_utama"` + Suku string `json:"suku" gorm:"column:suku"` + AgamaLain string `json:"agama_lain" gorm:"column:agama_lain"` + StDisabilitas uint `json:"stDisabilitas" gorm:"column:st_disabilitas"` + TxtKelurahan string `json:"txt_kelurahan" gorm:"column:txt_kelurahan"` + TxtKecamatan string `json:"txt_kecamatan" gorm:"column:txt_kecamatan"` + TxtKota string `json:"txt_kota" gorm:"column:txt_kota"` + TxtProvinsi string `json:"txt_provinsi" gorm:"column:txt_provinsi"` + TxtStatus string `json:"txt_status" gorm:"column:txt_status"` + TxtAgama string `json:"txt_agama" gorm:"column:txt_agama"` + TxtPendidikan string `json:"txt_pendidikan" gorm:"column:txt_pendidikan"` + NamaAyah string `json:"nama_ayah" gorm:"column:nama_ayah"` + NamaIbu string `json:"nama_ibu" gorm:"column:nama_ibu"` + PendidikanAyah string `json:"pendidikan_ayah" gorm:"column:pendidikan_ayah"` + PendidikanIbu string `json:"pendidikan_ibu" gorm:"column:pendidikan_ibu"` + StIdentitasOrtu uint `json:"st_identitas_ortu" gorm:"column:st_identitas_ortu"` + NomrBaru *string `json:"nomr_baru" gorm:"column:nomr_baru"` + KtpFile *string `json:"ktp_file" gorm:"column:ktp_file"` + KkFile *string `json:"kk_file" gorm:"column:kk_file"` + CreatedAt *time.Time `json:"created_at" gorm:"column:created_at"` + UpdatedAt *time.Time `json:"updated_at" gorm:"column:updated_at"` + NoKk *string `json:"no_kk" gorm:"column:no_kk"` + NoktpBaru string `json:"noktp_baru" gorm:"column:noktp_baru"` +} + +func (MPasien) TableName() string { + return "m_pasien" +} diff --git a/internal/domain/simgos-entities/m-polihfis/entity.go b/internal/domain/simgos-entities/m-polihfis/entity.go new file mode 100644 index 00000000..8bed236d --- /dev/null +++ b/internal/domain/simgos-entities/m-polihfis/entity.go @@ -0,0 +1,15 @@ +package m_polihfis + +type MPolihfis struct { + Id uint `json:"id" gorm:"primaryKey;autoIncrement;column:id"` + Code string `json:"code" gorm:"column:code"` + Poliklinik string `json:"poliklinik" gorm:"column:poliklinik"` + CodePolirs string `json:"code_polirs" gorm:"column:code_polirs"` + Poliklinikrs string `json:"poliklinikrs" gorm:"column:poliklinikrs"` + Active uint `json:"active" gorm:"column:active"` + Status uint `json:"status" gorm:"column:status"` +} + +func (MPolihfis) TableName() string { + return "m_polihfis" +} diff --git a/internal/domain/simgos-entities/m-poly/entity.go b/internal/domain/simgos-entities/m-poly/entity.go new file mode 100644 index 00000000..aff4bc1e --- /dev/null +++ b/internal/domain/simgos-entities/m-poly/entity.go @@ -0,0 +1,11 @@ +package m_poly + +type MPoly struct { + Kode uint `json:"kode" gorm:"primaryKey;column:kode"` + Nama string `json:"nama" gorm:"column:nama"` + Jenispoly uint `json:"jenispoly" gorm:"column:jenispoly"` +} + +func (MPoly) TableName() string { + return "m_poly" +} diff --git a/internal/domain/simgos-entities/m-unit/entity.go b/internal/domain/simgos-entities/m-unit/entity.go new file mode 100644 index 00000000..3d67d8fd --- /dev/null +++ b/internal/domain/simgos-entities/m-unit/entity.go @@ -0,0 +1,18 @@ +package m_unit + +type MUnit struct { + KodeUnit uint `json:"kode_unit" gorm:"primaryKey;autoIncrement;column:kode_unit"` + NamaUnit string `json:"nama_unit" gorm:"column:nama_unit"` + GrupUnit uint `json:"grup_unit" gorm:"column:grup_unit"` + NamaGrupunit string `json:"nama_grupunit" gorm:"column:nama_grupunit"` + PendapatanUnit string `json:"pendapatan_unit" gorm:"column:pendapatan_unit"` + Smf *string `json:"smf" gorm:"column:smf"` + HaveSubspecialis *uint `json:"have_subspecialis" gorm:"column:have_subspecialis"` + KelSmfTarif *string `json:"kel_smf_tarif" gorm:"column:kel_smf_tarif"` + IsPilihSatker *uint `json:"is_pilih_satker" gorm:"column:is_pilih_satker"` + NamaTempatlayanan string `json:"nama_tempatlayanan" gorm:"column:nama_tempatlayanan"` +} + +func (MUnit) TableName() string { + return "m_unit" +} diff --git a/internal/domain/simgos-entities/t-diagnosadanterapi/entity.go b/internal/domain/simgos-entities/t-diagnosadanterapi/entity.go new file mode 100644 index 00000000..9579168c --- /dev/null +++ b/internal/domain/simgos-entities/t-diagnosadanterapi/entity.go @@ -0,0 +1,51 @@ +package t_diagnosadanterapi + +import "time" + +type TDiagnosaDanTerapi struct { + Idxterapi uint `json:"idxterapi" gorm:"column:idxterapi;primaryKey"` + Idxdaftar uint `json:"idxdaftar" gorm:"column:idxdaftar"` + Nomr string `json:"nomr" gorm:"column:nomr"` + Tanggal time.Time `json:"tanggal" gorm:"column:tanggal"` + TekananDarah string `json:"tekanan_darah" gorm:"column:tekanan_darah"` + GolonganDarah string `json:"golongan_darah" gorm:"column:golongan_darah"` + TinggiBadan float64 `json:"tinggi_badan" gorm:"column:tinggi_badan"` + BeratBadan float64 `json:"berat_badan" gorm:"column:berat_badan"` + Diagnosa *string `json:"diagnosa" gorm:"column:diagnosa"` + Komplikasi *string `json:"komplikasi" gorm:"column:komplikasi"` + Terapi *string `json:"terapi" gorm:"column:terapi"` + Anamnesa *string `json:"anamnesa" gorm:"column:anamnesa"` + Kdpoly uint `json:"kdpoly" gorm:"column:kdpoly"` + Kddokter uint `json:"kddokter" gorm:"column:kddokter"` + Kdtujuanrujuk *uint `json:"kdtujuanrujuk" gorm:"column:kdtujuanrujuk"` + Nip string `json:"nip" gorm:"column:nip"` + IcdCode *string `json:"icd_code" gorm:"column:icd_code"` + KunjunganBl uint `json:"kunjungan_bl" gorm:"column:kunjungan_bl"` + KasusBl uint `json:"kasus_bl" gorm:"column:kasus_bl"` + Icdcm *string `json:"icdcm" gorm:"column:icdcm"` + Icd9 *string `json:"icd_9" gorm:"column:icd_9"` + Klb *uint `json:"klb" gorm:"column:klb"` + Bedah *uint `json:"bedah" gorm:"column:bedah"` + Jenis *uint `json:"jenis" gorm:"column:jenis"` + Perawat *string `json:"perawat" gorm:"column:perawat"` + Status *string `json:"status" gorm:"column:status"` + PemeriksaanFisik *string `json:"pemeriksaan_fisik" gorm:"column:pemeriksaan_fisik"` + RiwayatPasien *string `json:"riwayat_pasien" gorm:"column:riwayat_pasien"` + TindakanMedis *string `json:"tindakan_medis" gorm:"column:tindakan_medis"` + Rajal uint `json:"rajal" gorm:"column:rajal"` + UserBatal *string `json:"user_batal" gorm:"column:user_batal"` + TglBatal *time.Time `json:"tgl_batal" gorm:"column:tgl_batal"` + SudahVaksin string `json:"sudah_vaksin" gorm:"column:sudah_vaksin"` + CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` + DenyutJantung string `json:"denyut_jantung" gorm:"column:denyut_jantung"` + Pernapasan string `json:"pernapasan" gorm:"column:pernapasan"` + Suhu string `json:"suhu" gorm:"column:suhu"` + Sp02 string `json:"sp02" gorm:"column:sp02"` + TujuanPerawatan *string `json:"tujuan_perawatan" gorm:"column:tujuan_perawatan"` + TargetCapaian string `json:"target_capaian" gorm:"column:target_capaian"` +} + +// TableName overrides the table name used by GORM +func (TDiagnosaDanTerapi) TableName() string { + return "t_diagnosadanterapi" +} diff --git a/internal/domain/simgos-entities/t-icd-cm/entity.go b/internal/domain/simgos-entities/t-icd-cm/entity.go new file mode 100644 index 00000000..6ea7f935 --- /dev/null +++ b/internal/domain/simgos-entities/t-icd-cm/entity.go @@ -0,0 +1,23 @@ +package t_icd_cm + +import "time" + +type TIcdCm struct { + Idx uint `json:"idx" gorm:"column:idx;primaryKey"` + Nomr string `json:"nomr" gorm:"column:nomr"` + Idxdaftar uint `json:"idxdaftar" gorm:"column:idxdaftar"` + Kddokter uint `json:"kddokter" gorm:"column:kddokter"` + Icd *string `json:"icd" gorm:"column:icd"` + IcdVerified *string `json:"icd_verified" gorm:"column:icd_verified"` + StatusRajal uint16 `json:"status_rajal" gorm:"column:status_rajal"` + Tanggal time.Time `json:"tanggal" gorm:"column:tanggal"` + StatusVerif *uint16 `json:"status_verif" gorm:"column:status_verif"` + IcdVerifiedOrder *uint16 `json:"icd_verified_order" gorm:"column:icd_verified_order"` + IcdVerifBy *string `json:"icd_verif_by" gorm:"column:icd_verif_by"` + IcdVerifDate *time.Time `json:"icd_verif_date" gorm:"column:icd_verif_date"` + IcdActive *uint16 `json:"icd_active" gorm:"column:icd_active"` +} + +func (TIcdCm) TableName() string { + return "t_icd_cm" +} diff --git a/internal/domain/simgos-entities/t-icd/entity.go b/internal/domain/simgos-entities/t-icd/entity.go new file mode 100644 index 00000000..73ee49e1 --- /dev/null +++ b/internal/domain/simgos-entities/t-icd/entity.go @@ -0,0 +1,24 @@ +package t_icd + +import "time" + +type TIcd struct { + Idx uint `json:"idx" gorm:"column:idx;primaryKey"` + Nomr string `json:"nomr" gorm:"column:nomr"` + Idxdaftar uint `json:"idxdaftar" gorm:"column:idxdaftar"` + Kddokter uint `json:"kddokter" gorm:"column:kddokter"` + Icd string `json:"icd" gorm:"column:icd"` + IcdVerified *string `json:"icd_verified" gorm:"column:icd_verified"` + StatusRajal uint16 `json:"status_rajal" gorm:"column:status_rajal"` + Tanggal time.Time `json:"tanggal" gorm:"column:tanggal"` + StatusVerif *uint16 `json:"status_verif" gorm:"column:status_verif"` + IcdVerifiedOrder *uint16 `json:"icd_verified_order" gorm:"column:icd_verified_order"` + IcdVerifBy *string `json:"icd_verif_by" gorm:"column:icd_verif_by"` + IcdVerifDate *time.Time `json:"icd_verif_date" gorm:"column:icd_verif_date"` + IcdActive *uint16 `json:"icd_active" gorm:"column:icd_active"` + StSebabMati *uint16 `json:"st_sebab_mati" gorm:"column:st_sebab_mati"` +} + +func (TIcd) TableName() string { + return "t_icd" +} diff --git a/internal/domain/simgos-entities/t-pemeriksaan-hist/entity.go b/internal/domain/simgos-entities/t-pemeriksaan-hist/entity.go new file mode 100644 index 00000000..cfb0dda6 --- /dev/null +++ b/internal/domain/simgos-entities/t-pemeriksaan-hist/entity.go @@ -0,0 +1,27 @@ +package t_pemeriksaan_hist + +import "time" + +type TPemeriksaanHist struct { + IdPemeriksaanHist uint `json:"id_pemeriksaanhist" gorm:"primaryKey;column:id_pemeriksaanhist"` + Idxdaftar *uint `json:"idxdaftar" gorm:"column:idxdaftar"` + Kdpoly *uint `json:"kdpoly" gorm:"column:kdpoly"` + DokterPengonsul *uint `json:"dokter_pengonsul" gorm:"column:dokter_pengonsul"` + DokterPenerima *uint `json:"dokter_penerima" gorm:"column:dokter_penerima"` + StartKonsul *time.Time `json:"start_konsul" gorm:"column:start_konsul"` + EndKonsul *time.Time `json:"end_konsul" gorm:"column:end_konsul"` + UserKonsul *string `json:"user_konsul" gorm:"column:user_konsul;size:100"` + TglEntriKonsul *time.Time `json:"tgl_entri_konsul" gorm:"column:tgl_entri_konsul"` + IP *string `json:"ip" gorm:"column:ip;size:50"` + UserPenerima *string `json:"user_penerima" gorm:"column:user_penerima;size:100"` + MasukPoly *time.Time `json:"masuk_poly" gorm:"column:masuk_poly"` + PerawatPenerima *uint `json:"perawat_penerima" gorm:"column:perawat_penerima"` + StAktif *uint16 `json:"st_aktif" gorm:"column:st_aktif"` + UserBatal *string `json:"user_batal" gorm:"column:user_batal;size:100"` + TglBatal *time.Time `json:"tgl_batal" gorm:"column:tgl_batal"` + IdxBillRajal *uint `json:"idxbillrajal" gorm:"column:idxbillrajal"` +} + +func (TPemeriksaanHist) TableName() string { + return "t_pemeriksaan_hist" +} diff --git a/internal/domain/simgos-entities/t-pendaftaran/entity.go b/internal/domain/simgos-entities/t-pendaftaran/entity.go new file mode 100644 index 00000000..08222653 --- /dev/null +++ b/internal/domain/simgos-entities/t-pendaftaran/entity.go @@ -0,0 +1,89 @@ +package t_pendaftaran + +import "time" + +type TPendaftaran struct { + Nomr string `json:"nomr" gorm:"column:nomr"` + Tglreg *time.Time `json:"tglreg" gorm:"column:tglreg"` + Kddokter uint `json:"kddokter" gorm:"column:kddokter"` + Kdpoly uint `json:"kdpoly" gorm:"column:kdpoly"` + Subspesialis *uint `json:"subspesialis" gorm:"column:subspesialis"` + Kdrujuk uint `json:"kdrujuk" gorm:"column:kdrujuk"` + Kdcarabayar uint `json:"kdcarabayar" gorm:"column:kdcarabayar"` + Nojaminan string `json:"nojaminan" gorm:"column:nojaminan"` + Shift uint `json:"shift" gorm:"column:shift"` + Status uint `json:"status" gorm:"column:status"` + KeteranganStatus *uint `json:"keterangan_status" gorm:"column:keterangan_status"` + Pasienbaru uint `json:"pasienbaru" gorm:"column:pasienbaru"` + Nip string `json:"nip" gorm:"column:nip"` + Idxdaftar uint `json:"idxdaftar" gorm:"primaryKey;autoIncrement;column:idxdaftar"` + Masukpoly *time.Time `json:"masukpoly" gorm:"column:masukpoly"` + Keluarpoly *time.Time `json:"keluarpoly" gorm:"column:keluarpoly"` + Ketrujuk string `json:"ketrujuk" gorm:"column:ketrujuk"` + Ketbayar string `json:"ketbayar" gorm:"column:ketbayar"` + PenanggungjawabNama string `json:"penanggungjawab_nama" gorm:"column:penanggungjawab_nama"` + PenanggungjawabHubungan string `json:"penanggungjawab_hubungan" gorm:"column:penanggungjawab_hubungan"` + PenanggungjawabAlamat string `json:"penanggungjawab_alamat" gorm:"column:penanggungjawab_alamat"` + PenanggungjawabPhone string `json:"penanggungjawab_phone" gorm:"column:penanggungjawab_phone"` + Jamreg *time.Time `json:"jamreg" gorm:"column:jamreg"` + MintaRujukan string `json:"minta_rujukan" gorm:"column:minta_rujukan"` + Batal *string `json:"batal" gorm:"column:batal"` + NoSjp *string `json:"no_sjp" gorm:"column:no_sjp"` + NoPeserta *string `json:"no_peserta" gorm:"column:no_peserta"` + Nokartu string `json:"nokartu" gorm:"column:nokartu"` + Norujukan string `json:"norujukan" gorm:"column:norujukan"` + Tglrujukan *time.Time `json:"tglrujukan" gorm:"column:tglrujukan"` + DiagnosaAwal string `json:"diagnosa_awal" gorm:"column:diagnosa_awal"` + Nosep string `json:"nosep" gorm:"column:nosep"` + DiagnosaUtama string `json:"diagnosa_utama" gorm:"column:diagnosa_utama"` + KelasDaftar uint `json:"kelas_daftar" gorm:"column:kelas_daftar"` + KelasRawat *uint `json:"kelas_rawat" gorm:"column:kelas_rawat"` + TglKelasDaftar *time.Time `json:"tgl_kelas_daftar" gorm:"column:tgl_kelas_daftar"` + TglKelasRawat *time.Time `json:"tgl_kelas_rawat" gorm:"column:tgl_kelas_rawat"` + UserKelasDaftar *string `json:"user_kelas_daftar" gorm:"column:user_kelas_daftar"` + UserKelasRawat *string `json:"user_kelas_rawat" gorm:"column:user_kelas_rawat"` + StAsalMasuk string `json:"st_asal_masuk" gorm:"column:st_asal_masuk"` + StatusKecelakaan string `json:"status_kecelakaan" gorm:"column:status_kecelakaan"` + Catatan string `json:"catatan" gorm:"column:catatan"` + NoAntrian *string `json:"no_antrian" gorm:"column:no_antrian"` + StPelayanan *uint `json:"st_pelayanan" gorm:"column:st_pelayanan"` + PetugasKlinik string `json:"petugas_klinik" gorm:"column:petugas_klinik"` + Strujukan uint `json:"strujukan" gorm:"column:strujukan"` + IdPatientEklaim *uint `json:"id_patient_eklaim" gorm:"column:id_patient_eklaim"` + HakKelas *uint `json:"hak_kelas" gorm:"column:hak_kelas"` + SttsKtp string `json:"stts_ktp" gorm:"column:stts_ktp"` + StMeninggal *uint `json:"st_meninggal" gorm:"column:st_meninggal"` + DtMeninggal *time.Time `json:"dt_meninggal" gorm:"column:dt_meninggal"` + SebabMati1 *string `json:"sebab_mati_1" gorm:"column:sebab_mati_1"` + SebabMati2 *string `json:"sebab_mati_2" gorm:"column:sebab_mati_2"` + SebabMati3 *string `json:"sebab_mati_3" gorm:"column:sebab_mati_3"` + IcdMati1 *string `json:"icd_mati_1" gorm:"column:icd_mati_1"` + IcdMati2 *string `json:"icd_mati_2" gorm:"column:icd_mati_2"` + IcdMati3 *string `json:"icd_mati_3" gorm:"column:icd_mati_3"` + KeteranganLain *string `json:"keterangan_lain" gorm:"column:keterangan_lain"` + DokumenPendukung *string `json:"dokumen_pendukung" gorm:"column:dokumen_pendukung"` + NoKunjung uint `json:"no_kunjung" gorm:"column:no_kunjung"` + KdJamin *uint `json:"kd_jamin" gorm:"column:kd_jamin"` + NamaJamin *string `json:"nama_jamin" gorm:"column:nama_jamin"` + SepFile string `json:"sep_file" gorm:"column:sep_file"` + JenisFaskes *string `json:"jenis_faskes" gorm:"column:jenis_faskes"` + Nosipp *string `json:"nosipp" gorm:"column:nosipp"` + SippFile *string `json:"sipp_file" gorm:"column:sipp_file"` + Nosurkon *string `json:"nosurkon" gorm:"column:nosurkon"` + NomorBarcode *string `json:"nomor_barcode" gorm:"column:nomor_barcode"` + BarcodeCode *string `json:"barcode_code" gorm:"column:barcode_code"` + PartialType *string `json:"partial_type" gorm:"column:partial_type"` + IsPartial *uint `json:"is_partial" gorm:"column:is_partial"` + IsPenunjang *uint `json:"is_penunjang" gorm:"column:is_penunjang"` + TindakanCode *string `json:"tindakan_code" gorm:"column:tindakan_code"` + StatusSep *uint `json:"status_sep" gorm:"column:status_sep"` + PoliNameHfis *string `json:"poli_name_hfis" gorm:"column:poli_name_hfis"` + SpesialisIdHfis *string `json:"spesialis_id_hfis" gorm:"column:spesialis_id_hfis"` + DokterNameHfis *string `json:"dokter_name_hfis" gorm:"column:dokter_name_hfis"` + DokterIdHfis *string `json:"dokter_id_hfis" gorm:"column:dokter_id_hfis"` + StatusBridging *string `json:"status_bridging" gorm:"column:status_bridging"` +} + +func (TPendaftaran) TableName() string { + return "t_pendaftaran" +} diff --git a/internal/domain/simgos-entities/t-rekammedik/entity.go b/internal/domain/simgos-entities/t-rekammedik/entity.go new file mode 100644 index 00000000..84cec1ef --- /dev/null +++ b/internal/domain/simgos-entities/t-rekammedik/entity.go @@ -0,0 +1,22 @@ +package t_rekammedik + +import "time" + +type TRekammedik struct { + TglKirim *time.Time `json:"tgl_kirim" gorm:"column:tgl_kirim"` + TglTerima *time.Time `json:"tgl_terima" gorm:"column:tgl_terima"` + Idxdaftar uint `json:"idxdaftar" gorm:"column:idxdaftar"` + Kdpoly uint `json:"kdpoly" gorm:"column:kdpoly"` + Pengirim string `json:"pengirim" gorm:"column:pengirim"` + Penerima *string `json:"penerima" gorm:"column:penerima"` + Statusrm *uint `json:"statusrm" gorm:"column:statusrm"` + PenerimaPoly *string `json:"penerima_poly" gorm:"column:penerima_poly"` + JamKirimRm *time.Time `json:"jam_kirim_rm" gorm:"column:jam_kirim_rm"` + JamTerimaRm *time.Time `json:"jam_terima_rm" gorm:"column:jam_terima_rm"` + PjBerkasRm *string `json:"pj_berkas_rm" gorm:"column:pj_berkas_rm"` + StatusFisikBerkas *string `json:"status_fisik_berkas" gorm:"column:status_fisik_berkas"` +} + +func (TRekammedik) TableName() string { + return "t_rekammedik" +} diff --git a/internal/domain/sync-entities/authentication/authentication.go b/internal/domain/sync-entities/authentication/authentication.go new file mode 100644 index 00000000..f2448d9d --- /dev/null +++ b/internal/domain/sync-entities/authentication/authentication.go @@ -0,0 +1,9 @@ +package authentication + +type SyncKey struct{} + +type CredentialDto struct { + Source string `json:"X-Sync-Source"` + SecretKey string `json:"X-Sync-SecretKey"` + UserName string `json:"X-Sync-UserName"` +} diff --git a/internal/domain/sync-entities/division/entity.go b/internal/domain/sync-entities/division/entity.go new file mode 100644 index 00000000..9841c208 --- /dev/null +++ b/internal/domain/sync-entities/division/entity.go @@ -0,0 +1,29 @@ +package division + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type DivisionLink struct { + ecore.Main + Simx_Id uint `json:"simx_id" gorm:"unique"` + Simgos_Id uint `json:"simgos_id" gorm:"unique"` +} + +type DivisionSimxLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} + +type DivisionSimgosLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} diff --git a/internal/domain/sync-entities/encounter/entity.go b/internal/domain/sync-entities/encounter/entity.go new file mode 100644 index 00000000..f92d3e42 --- /dev/null +++ b/internal/domain/sync-entities/encounter/entity.go @@ -0,0 +1,31 @@ +package encounter + +import ( + "time" + + erc "simrs-vx/internal/domain/references/common" + + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type EncounterLink struct { + ecore.Main + Simx_Id uint `json:"simx_id" gorm:"unique"` + Simgos_Id uint `json:"simgos_id" gorm:"unique"` +} + +type EncounterSimxLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} + +type EncounterSimgosLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} diff --git a/internal/domain/sync-entities/installation/entity.go b/internal/domain/sync-entities/installation/entity.go new file mode 100644 index 00000000..a7818f3f --- /dev/null +++ b/internal/domain/sync-entities/installation/entity.go @@ -0,0 +1,29 @@ +package installation + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type InstallationLink struct { + ecore.Main + Simx_Id uint `json:"simx_id" gorm:"unique"` + Simgos_Id uint `json:"simgos_id" gorm:"unique"` +} + +type InstallationSimxLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} + +type InstallationSimgosLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} diff --git a/internal/domain/sync-entities/internal-reference/entity.go b/internal/domain/sync-entities/internal-reference/entity.go new file mode 100644 index 00000000..567e6489 --- /dev/null +++ b/internal/domain/sync-entities/internal-reference/entity.go @@ -0,0 +1,29 @@ +package internal_reference + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type InternalReferenceLink struct { + ecore.Main + Simx_Id uint `json:"simx_id" gorm:"unique"` + Simgos_Id uint `json:"simgos_id" gorm:"unique"` +} + +type InternalReferenceSimxLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} + +type InternalReferenceSimgosLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} diff --git a/internal/domain/sync-entities/log/dto.go b/internal/domain/sync-entities/log/dto.go new file mode 100644 index 00000000..32f5be6f --- /dev/null +++ b/internal/domain/sync-entities/log/dto.go @@ -0,0 +1,12 @@ +package log + +import ( + erc "simrs-vx/internal/domain/references/common" +) + +type SimxLogDto struct { + Payload any `json:"payload"` + IsSuccess bool `json:"isSuccess"` + ErrMessage *string `json:"errMessage"` + Method erc.CrudCode `json:"method"` +} diff --git a/internal/domain/sync-entities/patient/entity.go b/internal/domain/sync-entities/patient/entity.go new file mode 100644 index 00000000..e8c5b325 --- /dev/null +++ b/internal/domain/sync-entities/patient/entity.go @@ -0,0 +1,31 @@ +package patient + +import ( + "time" + + erc "simrs-vx/internal/domain/references/common" + + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type PatientLink struct { + ecore.Main + Simx_Id uint `json:"simx_id" gorm:"unique"` + Simgos_Id uint `json:"simgos_id" gorm:"unique"` +} + +type PatientSimxLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} + +type PatientSimgosLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} diff --git a/internal/domain/sync-entities/soapi/entity.go b/internal/domain/sync-entities/soapi/entity.go new file mode 100644 index 00000000..0a1315c7 --- /dev/null +++ b/internal/domain/sync-entities/soapi/entity.go @@ -0,0 +1,29 @@ +package Soapi + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type SoapiLink struct { + ecore.Main + Simx_Id uint `json:"simx_id" gorm:"unique"` + Simgos_Id uint `json:"simgos_id" gorm:"unique"` +} + +type SoapiSimxLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} + +type SoapiSimgosLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} diff --git a/internal/domain/sync-entities/specialist/entity.go b/internal/domain/sync-entities/specialist/entity.go new file mode 100644 index 00000000..0eb8683c --- /dev/null +++ b/internal/domain/sync-entities/specialist/entity.go @@ -0,0 +1,29 @@ +package specialist + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type SpecialistLink struct { + ecore.Main + Simx_Id uint `json:"simx_id" gorm:"unique"` + Simgos_Id uint `json:"simgos_id" gorm:"unique"` +} + +type SpecialistSimxLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} + +type SpecialistSimgosLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} diff --git a/internal/domain/sync-entities/subspecialist/entity.go b/internal/domain/sync-entities/subspecialist/entity.go new file mode 100644 index 00000000..76e16614 --- /dev/null +++ b/internal/domain/sync-entities/subspecialist/entity.go @@ -0,0 +1,29 @@ +package subspecialist + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type SubspecialistLink struct { + ecore.Main + Simx_Id uint `json:"simx_id" gorm:"unique"` + Simgos_Id uint `json:"simgos_id" gorm:"unique"` +} + +type SubspecialistSimxLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} + +type SubspecialistSimgosLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} diff --git a/internal/domain/sync-entities/unit/entity.go b/internal/domain/sync-entities/unit/entity.go new file mode 100644 index 00000000..d7491ea8 --- /dev/null +++ b/internal/domain/sync-entities/unit/entity.go @@ -0,0 +1,29 @@ +package unit + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + erc "simrs-vx/internal/domain/references/common" + "time" +) + +type UnitLink struct { + ecore.Main + Simx_Id uint `json:"simx_id" gorm:"unique"` + Simgos_Id uint `json:"simgos_id" gorm:"unique"` +} + +type UnitSimxLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} + +type UnitSimgosLog struct { + ecore.Main + Value *string `json:"value"` + Date *time.Time `json:"date"` + Status erc.ProcessStatusCode `json:"status"` + ErrMessage *string `json:"errMessage"` +} diff --git a/internal/infra/docs-cfg/docs-cfg.go b/internal/infra/docs-cfg/docs-cfg.go new file mode 100644 index 00000000..e6d32c92 --- /dev/null +++ b/internal/infra/docs-cfg/docs-cfg.go @@ -0,0 +1,17 @@ +package docscfg + +import a "github.com/karincake/apem" + +type DocsCfg struct { + Path string +} + +var O DocsCfg = DocsCfg{} + +func ParseCfg() { + a.ParseSingleCfg(&O) +} + +func (c DocsCfg) GetPath() string { + return c.Path +} diff --git a/internal/infra/simgos-db/simgos-db.go b/internal/infra/simgos-db/simgos-db.go new file mode 100644 index 00000000..4387ad7f --- /dev/null +++ b/internal/infra/simgos-db/simgos-db.go @@ -0,0 +1,9 @@ +package simgos_db + +import ( + dg "github.com/karincake/apem/db-gorm-pg" +) + +func SetInstance() { + I = dg.IS["simrs"] +} diff --git a/internal/infra/simgos-db/tycovar.go b/internal/infra/simgos-db/tycovar.go new file mode 100644 index 00000000..b9c9f2b3 --- /dev/null +++ b/internal/infra/simgos-db/tycovar.go @@ -0,0 +1,5 @@ +package simgos_db + +import "gorm.io/gorm" + +var I *gorm.DB diff --git a/internal/infra/sync-cfg/sync-cfg.go b/internal/infra/sync-cfg/sync-cfg.go index 0368a7c4..8e0e0f5a 100644 --- a/internal/infra/sync-cfg/sync-cfg.go +++ b/internal/infra/sync-cfg/sync-cfg.go @@ -7,8 +7,9 @@ import ( func SetConfig() { a.ParseSingleCfg(&O) - if O.Host == "" || O.Target == "" { - panic("sync url config host or target empty") + + if O.NewSecretKey == "" || O.NewHost == "" || O.OldSecretKey == "" || O.OldHost == "" { + panic("secret key and host of the sync partner config can not be empty") } - lo.I.Println("sync url config loaded, status: DONE!!") + lo.I.Println("sync partner config loaded, status: DONE!!") } diff --git a/internal/infra/sync-cfg/tycovar.go b/internal/infra/sync-cfg/tycovar.go index 9bb59f3d..a7534f82 100644 --- a/internal/infra/sync-cfg/tycovar.go +++ b/internal/infra/sync-cfg/tycovar.go @@ -1,8 +1,13 @@ package synccfg -var O SyncUrlCfg = SyncUrlCfg{} +var O SyncPartnerCfg = SyncPartnerCfg{} // old -type SyncUrlCfg struct { - Target string `yaml:"target"` - Host string `yaml:"host"` +// Used by sync itself, so any partner should be stated here +type SyncPartnerCfg struct { + OldSource string `yaml:"oldSource"` + OldSecretKey string `yaml:"oldSecretKey"` + OldHost string `yaml:"oldHost"` + NewSource string `yaml:"newSource"` + NewSecretKey string `yaml:"newSecretKey"` + NewHost string `yaml:"newHost"` } diff --git a/internal/infra/sync-consumer-cfg/sync-cfg.go b/internal/infra/sync-consumer-cfg/sync-cfg.go new file mode 100644 index 00000000..8ea63dac --- /dev/null +++ b/internal/infra/sync-consumer-cfg/sync-cfg.go @@ -0,0 +1,15 @@ +package synccfg + +import ( + a "github.com/karincake/apem" + lo "github.com/karincake/apem/loggero" +) + +func SetConfig() { + a.ParseSingleCfg(&O) + + if O.TargetHost == "" || O.Prefix == "" { + panic("config sync host and prefix empty") + } + lo.I.Println("sync url config loaded, status: DONE!!") +} diff --git a/internal/infra/sync-consumer-cfg/tycovar.go b/internal/infra/sync-consumer-cfg/tycovar.go new file mode 100644 index 00000000..23fd0dcf --- /dev/null +++ b/internal/infra/sync-consumer-cfg/tycovar.go @@ -0,0 +1,11 @@ +package synccfg + +var O SyncConsumerUrlCfg = SyncConsumerUrlCfg{} // new + +type SyncConsumerUrlCfg struct { + Prefix string `yaml:"prefix"` + TargetHost string `yaml:"targetHost"` + Enable bool `yaml:"enable"` + Source string `yaml:"source"` + SecretKey string `yaml:"secretKey"` +} diff --git a/internal/interface/bpjs-handler/bpjs-handler.go b/internal/interface/bpjs-handler/bpjs-handler.go index 175bb667..4f000664 100644 --- a/internal/interface/bpjs-handler/bpjs-handler.go +++ b/internal/interface/bpjs-handler/bpjs-handler.go @@ -4,12 +4,12 @@ import ( "net/http" /******************** main / transaction ********************/ - member "simrs-vx/internal/interface/bpjs-handler/member" - monitoring "simrs-vx/internal/interface/bpjs-handler/monitoring" - reference "simrs-vx/internal/interface/bpjs-handler/reference" - vclaimsep "simrs-vx/internal/interface/bpjs-handler/vclaim-sep" - vclaimsephist "simrs-vx/internal/interface/bpjs-handler/vclaim-sep-hist" - vclaimsepprint "simrs-vx/internal/interface/bpjs-handler/vclaim-sep-print" + member "simrs-vx/internal/interface/main-handler/member" + monitoring "simrs-vx/internal/interface/main-handler/monitoring" + reference "simrs-vx/internal/interface/main-handler/reference" + vclaimsep "simrs-vx/internal/interface/main-handler/vclaim-sep" + vclaimsephist "simrs-vx/internal/interface/main-handler/vclaim-sep-hist" + vclaimsepprint "simrs-vx/internal/interface/main-handler/vclaim-sep-print" /******************** actor ********************/ @@ -49,7 +49,7 @@ func SetRoutes() http.Handler { hk.GroupRoutes("/v1/vclaim-sep", r, hk.MapHandlerFunc{ "POST /": vclaimsep.O.Create, - "PATCH /{id}": vclaimsep.O.Update, + "PATCH /{id}": vclaimsep.O.GetDetail, "DELETE /{id}": vclaimsep.O.Delete, }) diff --git a/internal/interface/main-handler/antibiotic-src-category/handler.go b/internal/interface/main-handler/antibiotic-src-category/handler.go new file mode 100644 index 00000000..cc4766af --- /dev/null +++ b/internal/interface/main-handler/antibiotic-src-category/handler.go @@ -0,0 +1,74 @@ +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) { + intId := rw.ValidateInt(w, "id", r.PathValue("id")) + if intId <= 0 { + return + } + id := uint16(intId) + dto := e.ReadDetailDto{} + dto.Id = &id + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + intId := rw.ValidateInt(w, "id", r.PathValue("id")) + if intId <= 0 { + return + } + id := uint16(intId) + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = &id + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + intId := rw.ValidateInt(w, "id", r.PathValue("id")) + if intId <= 0 { + return + } + id := uint16(intId) + + dto := e.DeleteDto{} + dto.Id = &id + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/antibiotic-src/handler.go b/internal/interface/main-handler/antibiotic-src/handler.go new file mode 100644 index 00000000..5966e876 --- /dev/null +++ b/internal/interface/main-handler/antibiotic-src/handler.go @@ -0,0 +1,71 @@ +package antibioticsrc + +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/antibiotic-src" + u "simrs-vx/internal/use-case/main-use-case/antibiotic-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/authentication/handler.go b/internal/interface/main-handler/authentication/handler.go index 243ba9cd..4bf5134b 100644 --- a/internal/interface/main-handler/authentication/handler.go +++ b/internal/interface/main-handler/authentication/handler.go @@ -9,9 +9,12 @@ import ( sp "github.com/karincake/semprit" sr "github.com/karincake/serabi" + is "simrs-vx/internal/infra/sync-consumer-cfg" + pa "simrs-vx/internal/lib/auth" + m "simrs-vx/internal/domain/main-entities/user" mf "simrs-vx/internal/domain/main-entities/user-fes" - pa "simrs-vx/internal/lib/auth" + esga "simrs-vx/internal/domain/sync-entities/authentication" s "simrs-vx/internal/use-case/main-use-case/authentication" ) @@ -66,12 +69,37 @@ func Logout(w http.ResponseWriter, r *http.Request) { } func GuardMW(next http.Handler) http.Handler { + var ( + accessDetail *pa.AuthInfo + err error + ) 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 + // Check if it's from sync + credential := esga.CredentialDto{} + credential.Source = r.Header.Get("X-Sync-Source") + credential.SecretKey = r.Header.Get("X-Sync-SecretKey") + credential.UserName = r.Header.Get("X-Sync-UserName") + if credential.Source != "" || credential.SecretKey != "" || credential.UserName != "" { + // validate secretKey and source + if credential.SecretKey != is.O.SecretKey || credential.Source != is.O.Source { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "invalid consumer credential"}, nil) + return + } + + accessDetail, err = s.GetAuthInfoByUserName(credential.UserName) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, err.(d.FieldError), nil) + return + } + } else { + // Normal flow goes here + 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(), pa.AuthKey{}, accessDetail) next.ServeHTTP(w, r.WithContext(ctx)) }) diff --git a/internal/interface/main-handler/control-plan/handler.go b/internal/interface/main-handler/control-plan/handler.go new file mode 100644 index 00000000..382af58d --- /dev/null +++ b/internal/interface/main-handler/control-plan/handler.go @@ -0,0 +1,32 @@ +package controlplan + +import ( + "net/http" + + e "simrs-vx/internal/domain/bpjs-entities/control-plan" + u "simrs-vx/internal/use-case/bpjs-use-case/control-plan" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" +) + +func GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + pValue1 := rw.ValidateString(w, "controlType", r.PathValue("controlType")) + if pValue1 == "" { + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "controlType is required"}, nil) + } + pValue2 := rw.ValidateString(w, "polyCode", r.PathValue("polyCode")) + if pValue2 == "" { + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "polyCode is required"}, nil) + } + pValue3 := rw.ValidateString(w, "date", r.PathValue("date")) + if pValue3 == "" { + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "date is required"}, nil) + } + dto.PathValue1 = pValue1 + dto.PathValue2 = pValue2 + dto.PathValue3 = pValue3 + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/doctor/handler.go b/internal/interface/main-handler/doctor/handler.go index f62495d6..b700103a 100644 --- a/internal/interface/main-handler/doctor/handler.go +++ b/internal/interface/main-handler/doctor/handler.go @@ -38,6 +38,7 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { return } dto := e.ReadDetailDto{} + sf.UrlQueryParam(&dto, *r.URL) dto.Code = &code res, err := u.ReadDetail(dto) rw.DataResponse(w, res, err) diff --git a/internal/interface/main-handler/encounter-document/handler.go b/internal/interface/main-handler/encounter-document/handler.go new file mode 100644 index 00000000..0047ccec --- /dev/null +++ b/internal/interface/main-handler/encounter-document/handler.go @@ -0,0 +1,80 @@ +package encounter_document + +import ( + "net/http" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + e "simrs-vx/internal/domain/main-entities/encounter-document" + u "simrs-vx/internal/use-case/main-use-case/encounter-document" +) + +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) + + if dto.Encounter_Id == nil { + rw.DataResponse(w, nil, d.FieldError{ + Code: "data-validation-fail", + Message: "filter encounter-id required", + }) + return + } + 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{} + + sf.UrlQueryParam(&dto, *r.URL) + 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/encounter/handler.go b/internal/interface/main-handler/encounter/handler.go index 22d1d8cf..7ac31393 100644 --- a/internal/interface/main-handler/encounter/handler.go +++ b/internal/interface/main-handler/encounter/handler.go @@ -64,12 +64,17 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { } dto := e.ReadDetailDto{} sf.UrlQueryParam(&dto, *r.URL) - dto.Id = uint16(id) + dto.Id = uint(id) res, err := u.ReadDetail(dto) rw.DataResponse(w, res, err) } func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + id := rw.ValidateInt(w, "id", r.PathValue("id")) if id <= 0 { return @@ -79,25 +84,40 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } - dto.Id = uint16(id) + dto.Id = uint(id) + dto.AuthInfo = *authInfo + res, err := u.Update(dto) rw.DataResponse(w, res, err) } func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + id := rw.ValidateInt(w, "id", r.PathValue("id")) if id <= 0 { return } dto := e.DeleteDto{} - dto.Id = uint16(id) + dto.Id = uint(id) + dto.AuthInfo = *authInfo + res, err := u.Delete(dto) rw.DataResponse(w, res, err) } func (obj myBase) CheckOut(w http.ResponseWriter, r *http.Request) { dto := e.DischargeDto{} + + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + id := rw.ValidateInt(w, "id", r.PathValue("id")) if id <= 0 { return @@ -113,12 +133,20 @@ func (obj myBase) CheckOut(w http.ResponseWriter, r *http.Request) { } dto.Id = uint(id) + dto.AuthInfo = *authInfo + res, err := u.CheckOut(dto) rw.DataResponse(w, res, err) } func (obj myBase) CheckIn(w http.ResponseWriter, r *http.Request) { dto := e.CheckinDto{} + + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + id := rw.ValidateInt(w, "id", r.PathValue("id")) if id <= 0 { return @@ -134,6 +162,8 @@ func (obj myBase) CheckIn(w http.ResponseWriter, r *http.Request) { } dto.Id = uint(id) + dto.AuthInfo = *authInfo + res, err := u.CheckIn(dto) rw.DataResponse(w, res, err) } @@ -144,9 +174,15 @@ func (obj myBase) Process(w http.ResponseWriter, r *http.Request) { return } + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.UpdateStatusDto{ - Id: uint16(id), + Id: uint(id), StatusCode: erc.DSCProcess, + AuthInfo: *authInfo, } res, err := u.UpdateStatusCode(dto) @@ -159,9 +195,15 @@ func (obj myBase) Cancel(w http.ResponseWriter, r *http.Request) { return } + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.UpdateStatusDto{ - Id: uint16(id), + Id: uint(id), StatusCode: erc.DSCCancel, + AuthInfo: *authInfo, } res, err := u.UpdateStatusCode(dto) @@ -175,7 +217,7 @@ func (obj myBase) Reject(w http.ResponseWriter, r *http.Request) { } dto := e.UpdateStatusDto{ - Id: uint16(id), + Id: uint(id), StatusCode: erc.DSCRejected, } @@ -190,7 +232,7 @@ func (obj myBase) Skip(w http.ResponseWriter, r *http.Request) { } dto := e.UpdateStatusDto{ - Id: uint16(id), + Id: uint(id), StatusCode: erc.DSCSkipped, } @@ -214,13 +256,19 @@ func (obj myBase) RequestSwitchUnit(w http.ResponseWriter, r *http.Request) { return } + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + + dto.AuthInfo = *authInfo dto.Id = uint(id) res, err := u.RequestSwitchUnit(dto) rw.DataResponse(w, res, err) } func (obj myBase) ApproveSwitchUnit(w http.ResponseWriter, r *http.Request) { - dto := e.ApproveUnitDto{} + dto := e.ApproveCancelUnitDto{} id := rw.ValidateInt(w, "id", r.PathValue("id")) if id <= 0 { return @@ -230,7 +278,37 @@ func (obj myBase) ApproveSwitchUnit(w http.ResponseWriter, r *http.Request) { return } + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + + dto.AuthInfo = *authInfo dto.Id = uint(id) + res, err := u.ApproveSwitchUnit(dto) rw.DataResponse(w, res, err) } + +func (obj myBase) CancelSwitchUnit(w http.ResponseWriter, r *http.Request) { + dto := e.ApproveCancelUnitDto{} + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + + dto.AuthInfo = *authInfo + dto.Id = uint(id) + + res, err := u.CancelSwitchUnit(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/encounter/request-validation.go b/internal/interface/main-handler/encounter/request-validation.go index 79cc832c..67d8a63c 100644 --- a/internal/interface/main-handler/encounter/request-validation.go +++ b/internal/interface/main-handler/encounter/request-validation.go @@ -59,6 +59,22 @@ func validateRequestCheckIn(w http.ResponseWriter, i e.CheckinDto) (valid bool) } func validateRequestSwitchUnit(w http.ResponseWriter, i e.SwitchUnitDto) (valid bool) { + // validate poly-switch-code + if i.PolySwitchCode == nil { + rw.DataResponse(w, nil, d.FieldError{ + Code: dataValidationFail, + Message: fmt.Sprintf("polySwitchCode required"), + }) + return + } + + if *i.PolySwitchCode != ere.PSCConsulPoly && *i.PolySwitchCode != ere.PSCConsulExecutive { + rw.DataResponse(w, nil, d.FieldError{ + Code: dataValidationFail, + Message: "invalid PolySwitchCode", + }) + } + if i.InternalReferences == nil { rw.DataResponse(w, nil, d.FieldError{ Code: dataValidationFail, diff --git a/internal/interface/main-handler/general-consent/handler.go b/internal/interface/main-handler/general-consent/handler.go new file mode 100644 index 00000000..0a2e2f6a --- /dev/null +++ b/internal/interface/main-handler/general-consent/handler.go @@ -0,0 +1,72 @@ +package generalconsent + +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/general-consent" + u "simrs-vx/internal/use-case/main-use-case/general-consent" +) + +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{} + sf.UrlQueryParam(&dto, *r.URL) + 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/generate-file/handler.go b/internal/interface/main-handler/generate-file/handler.go new file mode 100644 index 00000000..c6d6c67d --- /dev/null +++ b/internal/interface/main-handler/generate-file/handler.go @@ -0,0 +1,18 @@ +package generatefile + +import ( + "net/http" + + rw "github.com/karincake/risoles" + + u "simrs-vx/internal/use-case/main-use-case/generate-file" +) + +func Generate(w http.ResponseWriter, r *http.Request) { + dto := u.GenerateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Generate(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/internal-reference/handler.go b/internal/interface/main-handler/internal-reference/handler.go index c46c974d..a3193501 100644 --- a/internal/interface/main-handler/internal-reference/handler.go +++ b/internal/interface/main-handler/internal-reference/handler.go @@ -39,7 +39,7 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { dto := eir.ReadDetailDto{} sf.UrlQueryParam(&dto, *r.URL) - dto.Id = uint16(id) + dto.Id = uint(id) res, err := uir.ReadDetail(dto) rw.DataResponse(w, res, err) } @@ -54,7 +54,7 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } - dto.Id = uint16(id) + dto.Id = uint(id) res, err := uir.Update(dto) rw.DataResponse(w, res, err) } @@ -66,7 +66,7 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { } dto := eir.DeleteDto{} - dto.Id = uint16(id) + dto.Id = uint(id) res, err := uir.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 04bef359..ebeed55a 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -16,6 +16,9 @@ import ( deviceorder "simrs-vx/internal/interface/main-handler/device-order" deviceorderitem "simrs-vx/internal/interface/main-handler/device-order-item" encounter "simrs-vx/internal/interface/main-handler/encounter" + encounterdocument "simrs-vx/internal/interface/main-handler/encounter-document" + generalconsent "simrs-vx/internal/interface/main-handler/general-consent" + generatefile "simrs-vx/internal/interface/main-handler/generate-file" internalreference "simrs-vx/internal/interface/main-handler/internal-reference" materialorder "simrs-vx/internal/interface/main-handler/material-order" materialorderitem "simrs-vx/internal/interface/main-handler/material-order-item" @@ -30,13 +33,18 @@ import ( practiceschedule "simrs-vx/internal/interface/main-handler/practice-schedule" prescription "simrs-vx/internal/interface/main-handler/prescription" prescriptionitem "simrs-vx/internal/interface/main-handler/prescription-item" + procedurereport "simrs-vx/internal/interface/main-handler/procedure-report" + procedureroom "simrs-vx/internal/interface/main-handler/procedure-room" + procedureroomorder "simrs-vx/internal/interface/main-handler/procedure-room-order" + procedureroomorderitem "simrs-vx/internal/interface/main-handler/procedure-room-order-item" responsibledoctorhist "simrs-vx/internal/interface/main-handler/responsible-doctor-hist" + resume "simrs-vx/internal/interface/main-handler/resume" sbar "simrs-vx/internal/interface/main-handler/sbar" + screening "simrs-vx/internal/interface/main-handler/screening" soapi "simrs-vx/internal/interface/main-handler/soapi" - upload "simrs-vx/internal/interface/main-handler/upload" + uploadfile "simrs-vx/internal/interface/main-handler/upload-file" /******************** actor ********************/ - authpartner "simrs-vx/internal/interface/main-handler/auth-partner" doctor "simrs-vx/internal/interface/main-handler/doctor" employee "simrs-vx/internal/interface/main-handler/employee" @@ -57,9 +65,11 @@ import ( /******************** infra ********************/ ibpjs "simrs-vx/internal/infra/bpjs" + docscfg "simrs-vx/internal/infra/docs-cfg" gs "simrs-vx/internal/infra/gorm-setting" minio "simrs-vx/internal/infra/minio" ssdb "simrs-vx/internal/infra/ss-db" + sync "simrs-vx/internal/infra/sync-consumer-cfg" /******************** pkg ********************/ cmw "simrs-vx/pkg/cors-manager-mw" @@ -70,6 +80,8 @@ import ( zlc "simrs-vx/pkg/zerolog-ctx" /******************** sources ********************/ + antibioticsrc "simrs-vx/internal/interface/main-handler/antibiotic-src" + antibioticsrccat "simrs-vx/internal/interface/main-handler/antibiotic-src-category" 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" @@ -85,12 +97,15 @@ import ( itemprice "simrs-vx/internal/interface/main-handler/item-price" language "simrs-vx/internal/interface/main-handler/language" material "simrs-vx/internal/interface/main-handler/material" + materialpackage "simrs-vx/internal/interface/main-handler/material-package" + materialpackageitem "simrs-vx/internal/interface/main-handler/material-package-item" mcusrc "simrs-vx/internal/interface/main-handler/mcu-src" mcusrccategory "simrs-vx/internal/interface/main-handler/mcu-src-category" mcusubsrc "simrs-vx/internal/interface/main-handler/mcu-sub-src" 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" + medicineform "simrs-vx/internal/interface/main-handler/medicine-form" 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" @@ -112,9 +127,19 @@ import ( regency "simrs-vx/internal/interface/main-handler/regency" village "simrs-vx/internal/interface/main-handler/village" - ///// Internal + /******************** Internal ********************/ validation "simrs-vx/internal/interface/main-handler/helper/validation" "simrs-vx/internal/interface/main-handler/home" + + /******************** BPJS ********************/ + controlplan "simrs-vx/internal/interface/main-handler/control-plan" + member "simrs-vx/internal/interface/main-handler/member" + monitoring "simrs-vx/internal/interface/main-handler/monitoring" + reference "simrs-vx/internal/interface/main-handler/reference" + referral "simrs-vx/internal/interface/main-handler/referral" + vclaimsep "simrs-vx/internal/interface/main-handler/vclaim-sep" + vclaimsephist "simrs-vx/internal/interface/main-handler/vclaim-sep-hist" + vclaimsepprint "simrs-vx/internal/interface/main-handler/vclaim-sep-print" ) // One place route to relatively easier to manage, ESPECIALLY in tracking @@ -128,6 +153,9 @@ func SetRoutes() http.Handler { a.RegisterExtCall(mh.I.SetClient) a.RegisterExtCall(ibpjs.SetConfig) a.RegisterExtCall(validation.RegisterValidation) + a.RegisterExtCall(sync.SetConfig) + a.RegisterExtCall(docscfg.ParseCfg) + a.RegisterExtCall(ibpjs.SetConfig) r := http.NewServeMux() @@ -140,15 +168,19 @@ func SetRoutes() http.Handler { hc.RegCrud(r, "/v1/auth-partner", authpartner.O) hc.RegCrud(r, "/v1/practice-schedule", practiceschedule.O) hc.RegCrud(r, "/v1/counter", counter.O) + hc.RegCrudByCode(r, "/v1/medicine-form", medicineform.O) hc.RegCrud(r, "/v1/medicine-mix", medicicinemix.O) hc.RegCrud(r, "/v1/medicine-mix-item", medicicinemixitem.O) + hc.RegCrud(r, "/v1/antibiotic-src-category", antibioticsrccat.O) + hc.RegCrud(r, "/v1/antibiotic-src", antibioticsrc.O) hc.RegCrud(r, "/v1/soapi", auth.GuardMW, soapi.O) hc.RegCrud(r, "/v1/adime", auth.GuardMW, adime.O) hc.RegCrud(r, "/v1/sbar", auth.GuardMW, sbar.O) hc.RegCrud(r, "/v1/prescription-item", prescriptionitem.O) hc.RegCrud(r, "/v1/device-order-item", deviceorderitem.O) - hc.RegCrud(r, "/v1/material-order-item", materialorderitem.O) + hc.RegCrud(r, "/v1/procedure-report", auth.GuardMW, procedurereport.O) + hc.RegCrud(r, "/v1/material-order-item", materialorderitem.O) hk.GroupRoutes("/v1/encounter", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": encounter.O.GetList, "GET /{id}": encounter.O.GetDetail, @@ -163,6 +195,7 @@ func SetRoutes() http.Handler { "PATCH /{id}/skip": encounter.O.Skip, "PATCH /{id}/req-switch-unit": encounter.O.RequestSwitchUnit, "PATCH /{id}/approve-switch-unit": encounter.O.ApproveSwitchUnit, + "PATCH /{id}/cancel-switch-unit": encounter.O.CancelSwitchUnit, }) hk.GroupRoutes("/v1/mcu-order", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": mcuorder.O.GetList, @@ -170,6 +203,7 @@ func SetRoutes() http.Handler { "POST /": mcuorder.O.Create, "PATCH /{id}": mcuorder.O.Update, "DELETE /{id}": mcuorder.O.Delete, + "PATCH /{id}/submit": mcuorder.O.Submit, "PATCH /{id}/complete": mcuorder.O.Complete, "PATCH /{id}/set-schedule": mcuorder.O.SetSchedule, }) @@ -188,6 +222,7 @@ func SetRoutes() http.Handler { "POST /": prescription.O.Create, "PATCH /{id}": prescription.O.Update, "DELETE /{id}": prescription.O.Delete, + "PATCH /{id}/submit": prescription.O.Submit, "PATCH /{id}/approve": prescription.O.Approve, }) hk.GroupRoutes("/v1/mcu-order-sub-item", r, auth.GuardMW, hk.MapHandlerFunc{ @@ -206,7 +241,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": medication.O.Delete, "PATCH /{id}/complete": medication.O.Complete, }) - hk.GroupRoutes("/v1/medication-item", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": medicationitem.O.GetList, "GET /{id}": medicationitem.O.GetDetail, @@ -215,7 +249,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": medicationitem.O.Delete, "PATCH /{id}/redeem": medicationitem.O.Redeem, }) - hk.GroupRoutes("/v1/medication-item-dist", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": medicationitemdist.O.GetList, "GET /{id}": medicationitemdist.O.GetDetail, @@ -224,7 +257,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": medicationitemdist.O.Delete, "PATCH /{id}/consume": medicationitemdist.O.Consume, }) - hk.GroupRoutes("/v1/device-order", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": deviceorder.O.GetList, "GET /{id}": deviceorder.O.GetDetail, @@ -233,7 +265,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": deviceorder.O.Delete, "PATCH /{id}/complete": deviceorder.O.Complete, }) - hk.GroupRoutes("/v1/material-order", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": materialorder.O.GetList, "GET /{id}": materialorder.O.GetDetail, @@ -242,7 +273,16 @@ func SetRoutes() http.Handler { "DELETE /{id}": materialorder.O.Delete, "PATCH /{id}/complete": materialorder.O.Complete, }) - + hc.RegCrud(r, "/v1/procedure-room", procedureroom.O) + hk.GroupRoutes("/v1/procedure-room-order", r, auth.GuardMW, hk.MapHandlerFunc{ + "GET /": procedureroomorder.O.GetList, + "GET /{id}": procedureroomorder.O.GetDetail, + "POST /": procedureroomorder.O.Create, + "PATCH /{id}": procedureroomorder.O.Update, + "DELETE /{id}": procedureroomorder.O.Delete, + "PATCH /{id}/submit": procedureroomorder.O.Submit, + }) + hc.RegCrud(r, "/v1/procedure-room-order-item", procedureroomorderitem.O) hk.GroupRoutes("/v1/consultation", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": consultation.O.GetList, "GET /{id}": consultation.O.GetDetail, @@ -251,7 +291,6 @@ func SetRoutes() http.Handler { "DELETE /{id}": consultation.O.Delete, "PATCH /{id}/reply": consultation.O.Reply, }) - hk.GroupRoutes("/v1/chemo", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": chemo.O.GetList, "GET /{id}": chemo.O.GetDetail, @@ -261,16 +300,39 @@ func SetRoutes() http.Handler { "PATCH /{id}/verify": chemo.O.Verify, "PATCH /{id}/reject": chemo.O.Reject, }) - hc.RegCrud(r, "/v1/control-letter", controlletter.O) hc.RegCrud(r, "/v1/internal-reference", internalreference.O) hc.RegCrud(r, "/v1/ambulance-transport-req", ambulancetransportrequest.O) hc.RegCrud(r, "/v1/responsible-doctor-hist", responsibledoctorhist.O) hc.RegCrud(r, "/v1/adm-employee-hist", admemployeehist.O) - hc.RegCrud(r, "/v1/therapy-protocol", therapyprotocol.O) + hk.GroupRoutes("/v1/therapy-protocol", r, auth.GuardMW, hk.MapHandlerFunc{ + "GET /": therapyprotocol.O.GetList, + "GET /{id}": therapyprotocol.O.GetDetail, + "POST /": therapyprotocol.O.Create, + "PATCH /{id}": therapyprotocol.O.Update, + "DELETE /{id}": therapyprotocol.O.Delete, + "PATCH /{id}/verify": therapyprotocol.O.Verify, + "PATCH /{id}/reject": therapyprotocol.O.Reject, + }) hc.RegCrud(r, "/v1/chemo-protocol", chemoprotocol.O) - hc.RegCrud(r, "/v1/upload", upload.O) - + hc.RegCrud(r, "/v1/upload-file", uploadfile.O) + hc.RegCrud(r, "/v1/encounter-document", encounterdocument.O) + hc.RegCrud(r, "/v1/general-consent", generalconsent.O) + r.HandleFunc("POST /v1/generate-file", generatefile.Generate) + hk.GroupRoutes("/v1/resume", r, auth.GuardMW, hk.MapHandlerFunc{ + "POST /": resume.Create, + "GET /": resume.GetList, + "GET /{id}": resume.GetDetail, + "PATCH /{id}": resume.Update, + "DELETE /{id}": resume.Delete, + "PATCH /{id}/verify": resume.Verify, + "PATCH /{id}/validate": resume.Validate, + }) + hk.GroupRoutes("/v1/screening", r, auth.GuardMW, hk.MapHandlerFunc{ + "POST /": screening.O.Create, + "GET /": screening.O.GetList, + "GET /{id}": screening.O.GetDetail, + }) /******************** actor ********************/ hc.RegCrud(r, "/v1/person", person.O) hc.RegCrud(r, "/v1/person-address", personaddress.O) @@ -291,8 +353,7 @@ func SetRoutes() http.Handler { "PATCH /{id}/active": user.O.Active, }) hc.RegCrud(r, "/v1/user-fes", userfes.O) - - hk.GroupRoutes("/v1/patient", r, hk.MapHandlerFunc{ + hk.GroupRoutes("/v1/patient", r, auth.GuardMW, hk.MapHandlerFunc{ "GET /": patient.O.GetList, "GET /{id}": patient.O.GetDetail, "POST /": patient.O.Create, @@ -329,6 +390,8 @@ func SetRoutes() http.Handler { hc.RegCrudByCode(r, "/v1/medicine", medicine.O) hc.RegCrudByCode(r, "/v1/device", device.O) hc.RegCrudByCode(r, "/v1/material", material.O) + hc.RegCrudByCode(r, "/v1/material-package", materialpackage.O) + hc.RegCrud(r, "/v1/material-package-item", materialpackageitem.O) hc.RegCrud(r, "/v1/doctor-fee", doctorfee.O) hc.RegCrudByCode(r, "/v1/medical-action-src", medicalactionsrc.O) hc.RegCrud(r, "/v1/medical-action-src-item", medicalactionsrcitem.O) @@ -344,6 +407,51 @@ func SetRoutes() http.Handler { hc.RegCrudByCode(r, "/v1/province", province.O) hc.RegCrudByCode(r, "/v1/postal-region", postalregion.O) + /******************** BPJS ********************/ + hk.GroupRoutes("/v1/vclaim-sep", r, hk.MapHandlerFunc{ + "POST /": vclaimsep.O.Create, + "GET /{number}": vclaimsep.O.GetDetail, + "DELETE /{number}": vclaimsep.O.Delete, + }) + + hk.GroupRoutes("/v1/vclaim-sep-hist", r, hk.MapHandlerFunc{ + "GET /": vclaimsephist.O.GetList, + }) + + hk.GroupRoutes("/v1/vclaim-sep-print", r, hk.MapHandlerFunc{ + "POST /": vclaimsepprint.O.Create, + }) + + hk.GroupRoutes("/v1/reference", r, hk.MapHandlerFunc{ + "GET /province": reference.GetListProvince, + "GET /regency/{provinceCode}": reference.GetListCities, + "GET /district/{regencyCode}": reference.GetListDistrict, + "GET /diagnose/{keyword}": reference.GetListDiagnose, + "GET /diagnose-prb": reference.GetListDiagnosePrb, + "GET /medicine-prb/{keyword}": reference.GetListMedicinePrb, + "GET /unit/{unitCode}": reference.GetListUnit, + "GET /healthcare/{healthcare}/{healthcareType}": reference.GetListHealthcare, + "GET /responsible-doctor/{serviceType}/{serviceDate}/{specialistCode}": reference.GetListDoctor, + }) + + hk.GroupRoutes("/v1/member", r, hk.MapHandlerFunc{ + "GET /bpjs/{cardNumber}/{sepDate}": member.GetListByBpjsNumber, + "GET /nik/{nik}/{sepDate}": member.GetListByNik, + }) + + hk.GroupRoutes("/v1/monitoring", r, hk.MapHandlerFunc{ + "GET /visit/{date}/{serviceType}": monitoring.GetListVisit, + "GET /hist/{cardNumber}/{startDate}/{endDate}": monitoring.GetListHist, + }) + + hk.GroupRoutes("/v1/control-plan", r, hk.MapHandlerFunc{ + "GET /{controlType}/{polyCode}/{date}": controlplan.GetList, + }) + + hk.GroupRoutes("/v1/referral", r, hk.MapHandlerFunc{ + "GET /{number}": referral.GetList, + }) + ///// return cmw.SetCors(handlerlogger.SetLog(r)) } diff --git a/internal/interface/main-handler/material-package-item/handler.go b/internal/interface/main-handler/material-package-item/handler.go new file mode 100644 index 00000000..11deb6d9 --- /dev/null +++ b/internal/interface/main-handler/material-package-item/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-package-item" + u "simrs-vx/internal/use-case/main-use-case/material-package-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 = 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/material-package/handler.go b/internal/interface/main-handler/material-package/handler.go new file mode 100644 index 00000000..609d983e --- /dev/null +++ b/internal/interface/main-handler/material-package/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-package" + u "simrs-vx/internal/use-case/main-use-case/material-package" +) + +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) { + code := rw.ValidateString(w, "code", r.PathValue("code")) + if code == "" { + return + } + dto := e.ReadDetailDto{} + dto.Code = &code + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + code := rw.ValidateString(w, "code", r.PathValue("code")) + if code == "" { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Code = code + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + code := rw.ValidateString(w, "code", r.PathValue("code")) + if code == "" { + return + } + + dto := e.DeleteDto{} + dto.Code = &code + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/mcu-order/handler.go b/internal/interface/main-handler/mcu-order/handler.go index ac4aca9f..bbbd1c56 100644 --- a/internal/interface/main-handler/mcu-order/handler.go +++ b/internal/interface/main-handler/mcu-order/handler.go @@ -85,6 +85,18 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { rw.DataResponse(w, res, err) } +func (obj myBase) Submit(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.Submit(dto) + rw.DataResponse(w, res, err) +} + func (obj myBase) Complete(w http.ResponseWriter, r *http.Request) { id := rw.ValidateInt(w, "id", r.PathValue("id")) if id <= 0 { diff --git a/internal/interface/main-handler/medicine-form/handler.go b/internal/interface/main-handler/medicine-form/handler.go new file mode 100644 index 00000000..a363fb30 --- /dev/null +++ b/internal/interface/main-handler/medicine-form/handler.go @@ -0,0 +1,71 @@ +package medicineform + +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-form" + u "simrs-vx/internal/use-case/main-use-case/medicine-form" +) + +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) { + code := rw.ValidateString(w, "code", r.PathValue("code")) + if code == "" { + return + } + dto := e.ReadDetailDto{} + dto.Code = &code + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + code := rw.ValidateString(w, "code", r.PathValue("code")) + if code == "" { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Code = &code + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + code := rw.ValidateString(w, "code", r.PathValue("code")) + if code == "" { + return + } + + dto := e.DeleteDto{} + dto.Code = &code + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/bpjs-handler/member/handler.go b/internal/interface/main-handler/member/handler.go similarity index 74% rename from internal/interface/bpjs-handler/member/handler.go rename to internal/interface/main-handler/member/handler.go index 80881ee3..3b4c3ba1 100644 --- a/internal/interface/bpjs-handler/member/handler.go +++ b/internal/interface/main-handler/member/handler.go @@ -14,11 +14,11 @@ func GetListByBpjsNumber(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue1 := rw.ValidateString(w, "cardNumber", r.PathValue("cardNumber")) if pValue1 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "cardNumber is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "cardNumber is required"}, nil) } pValue2 := rw.ValidateString(w, "sepDate", r.PathValue("sepDate")) if pValue2 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "sepDate is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "sepDate is required"}, nil) } dto.ReferenceType = e.RTBpjs dto.PathValue1 = pValue1 @@ -31,11 +31,11 @@ func GetListByNik(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue1 := rw.ValidateString(w, "nik", r.PathValue("nik")) if pValue1 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "nik is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "nik is required"}, nil) } pValue2 := rw.ValidateString(w, "sepDate", r.PathValue("sepDate")) if pValue2 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "sepDate is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "sepDate is required"}, nil) } dto.ReferenceType = e.RTNik dto.PathValue1 = pValue1 diff --git a/internal/interface/bpjs-handler/monitoring/handler.go b/internal/interface/main-handler/monitoring/handler.go similarity index 73% rename from internal/interface/bpjs-handler/monitoring/handler.go rename to internal/interface/main-handler/monitoring/handler.go index cf82a5b9..aa8acdf4 100644 --- a/internal/interface/bpjs-handler/monitoring/handler.go +++ b/internal/interface/main-handler/monitoring/handler.go @@ -14,11 +14,11 @@ func GetListVisit(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue1 := rw.ValidateString(w, "date", r.PathValue("date")) if pValue1 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "date is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "date is required"}, nil) } pValue2 := rw.ValidateString(w, "serviceType", r.PathValue("serviceType")) if pValue2 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "serviceType is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "serviceType is required"}, nil) } dto.ReferenceType = e.RTVisit dto.PathValue1 = pValue1 @@ -31,15 +31,15 @@ func GetListHist(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue1 := rw.ValidateString(w, "cardNumber", r.PathValue("cardNumber")) if pValue1 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "cardNumber is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "cardNumber is required"}, nil) } pValue2 := rw.ValidateString(w, "startDate", r.PathValue("startDate")) if pValue2 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "startDate is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "startDate is required"}, nil) } pValue3 := rw.ValidateString(w, "endDate", r.PathValue("endDate")) if pValue3 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "endDate is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "endDate is required"}, nil) } dto.ReferenceType = e.RTHist dto.PathValue1 = pValue1 diff --git a/internal/interface/main-handler/patient/handler.go b/internal/interface/main-handler/patient/handler.go index 9fd5fdce..dc6c3ff5 100644 --- a/internal/interface/main-handler/patient/handler.go +++ b/internal/interface/main-handler/patient/handler.go @@ -2,6 +2,7 @@ package patient import ( "net/http" + pa "simrs-vx/internal/lib/auth" rw "github.com/karincake/risoles" sf "github.com/karincake/semprit" @@ -19,10 +20,17 @@ type myBase struct{} var O myBase func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.CreateDto{} if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } + + dto.AuthInfo = *authInfo res, err := u.Create(dto) rw.DataResponse(w, res, err) } @@ -51,11 +59,18 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { return } + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.UpdateDto{} if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } + dto.Id = uint(id) + dto.AuthInfo = *authInfo res, err := u.Update(dto) rw.DataResponse(w, res, err) } @@ -67,7 +82,15 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { } dto := e.DeleteDto{} + + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto.Id = uint(id) + dto.AuthInfo = *authInfo + res, err := u.Delete(dto) rw.DataResponse(w, res, err) } diff --git a/internal/interface/main-handler/prescription/handler.go b/internal/interface/main-handler/prescription/handler.go index 24d73372..c7649d34 100644 --- a/internal/interface/main-handler/prescription/handler.go +++ b/internal/interface/main-handler/prescription/handler.go @@ -46,6 +46,7 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { return } dto := e.ReadDetailDto{} + sf.UrlQueryParam(&dto, *r.URL) dto.Id = uint(id) res, err := u.ReadDetail(dto) rw.DataResponse(w, res, err) @@ -78,6 +79,18 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { rw.DataResponse(w, res, err) } +func (obj myBase) Submit(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.Submit(dto) + rw.DataResponse(w, res, err) +} + func (obj myBase) Approve(w http.ResponseWriter, r *http.Request) { id := rw.ValidateInt(w, "id", r.PathValue("id")) if id <= 0 { diff --git a/internal/interface/main-handler/procedure-report/handler.go b/internal/interface/main-handler/procedure-report/handler.go new file mode 100644 index 00000000..a648463b --- /dev/null +++ b/internal/interface/main-handler/procedure-report/handler.go @@ -0,0 +1,80 @@ +package soapi + +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-report" + u "simrs-vx/internal/use-case/main-use-case/procedure-report" + + pa "simrs-vx/internal/lib/auth" + + d "github.com/karincake/dodol" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.AuthInfo = *authInfo + 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-room-order-item/handler.go b/internal/interface/main-handler/procedure-room-order-item/handler.go new file mode 100644 index 00000000..0caed63d --- /dev/null +++ b/internal/interface/main-handler/procedure-room-order-item/handler.go @@ -0,0 +1,71 @@ +package procedureroomorder + +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-room-order-item" + u "simrs-vx/internal/use-case/main-use-case/procedure-room-order-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 = uint64(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 = uint64(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 = uint64(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/procedure-room-order/handler.go b/internal/interface/main-handler/procedure-room-order/handler.go new file mode 100644 index 00000000..58c2c80b --- /dev/null +++ b/internal/interface/main-handler/procedure-room-order/handler.go @@ -0,0 +1,83 @@ +package procedureroomorder + +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-room-order" + u "simrs-vx/internal/use-case/main-use-case/procedure-room-order" +) + +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 = uint64(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 = uint64(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 = uint64(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Submit(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.ReadDetailDto{} + dto.Id = uint64(id) + res, err := u.Submit(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/procedure-room/handler.go b/internal/interface/main-handler/procedure-room/handler.go new file mode 100644 index 00000000..6d6aeb1c --- /dev/null +++ b/internal/interface/main-handler/procedure-room/handler.go @@ -0,0 +1,71 @@ +package procedureroom + +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-room" + u "simrs-vx/internal/use-case/main-use-case/procedure-room" +) + +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/bpjs-handler/reference/handler.go b/internal/interface/main-handler/reference/handler.go similarity index 77% rename from internal/interface/bpjs-handler/reference/handler.go rename to internal/interface/main-handler/reference/handler.go index fb972af1..b9948eb3 100644 --- a/internal/interface/bpjs-handler/reference/handler.go +++ b/internal/interface/main-handler/reference/handler.go @@ -21,7 +21,7 @@ func GetListCities(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue := rw.ValidateString(w, "provinceCode", r.PathValue("provinceCode")) if pValue == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "provinceCode is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "provinceCode is required"}, nil) } dto.ReferenceType = e.RTCities dto.PathValue1 = pValue @@ -33,7 +33,7 @@ func GetListDistrict(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue := rw.ValidateString(w, "regencyCode", r.PathValue("regencyCode")) if pValue == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "regencyCode is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "regencyCode is required"}, nil) } dto.ReferenceType = e.RTDistrict dto.PathValue1 = pValue @@ -45,7 +45,7 @@ func GetListDiagnose(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue := rw.ValidateString(w, "keyword", r.PathValue("keyword")) if pValue == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "keyword is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "keyword is required"}, nil) } dto.ReferenceType = e.RTDiagnose dto.PathValue1 = pValue @@ -64,7 +64,7 @@ func GetListMedicinePrb(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue := rw.ValidateString(w, "keyword", r.PathValue("keyword")) if pValue == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "keyword is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "keyword is required"}, nil) } dto.ReferenceType = e.RTMedicinePrb dto.PathValue1 = pValue @@ -76,7 +76,7 @@ func GetListUnit(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue := rw.ValidateString(w, "unitCode", r.PathValue("unitCode")) if pValue == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "unitCode is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "unitCode is required"}, nil) } dto.ReferenceType = e.RTUnit dto.PathValue1 = pValue @@ -88,11 +88,11 @@ func GetListHealthcare(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue1 := rw.ValidateString(w, "healthcare", r.PathValue("healthcare")) if pValue1 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "healthcare is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "healthcare is required"}, nil) } pValue2 := rw.ValidateString(w, "healthcareType", r.PathValue("healthcareType")) if pValue2 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "healthcareType is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "healthcareType is required"}, nil) } dto.ReferenceType = e.RTHealthcare dto.PathValue1 = pValue1 @@ -105,15 +105,15 @@ func GetListDoctor(w http.ResponseWriter, r *http.Request) { dto := e.ReadListDto{} pValue1 := rw.ValidateString(w, "serviceType", r.PathValue("serviceType")) if pValue1 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "serviceType is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "serviceType is required"}, nil) } pValue2 := rw.ValidateString(w, "serviceDate", r.PathValue("serviceDate")) if pValue2 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "serviceDate is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "serviceDate is required"}, nil) } pValue3 := rw.ValidateString(w, "specialistCode", r.PathValue("specialistCode")) if pValue3 == "" { - rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "specialistCode is required"}, nil) + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "specialistCode is required"}, nil) } dto.PathValue1 = pValue1 dto.PathValue2 = pValue2 diff --git a/internal/interface/main-handler/referral/handler.go b/internal/interface/main-handler/referral/handler.go new file mode 100644 index 00000000..94b66a78 --- /dev/null +++ b/internal/interface/main-handler/referral/handler.go @@ -0,0 +1,22 @@ +package referral + +import ( + "net/http" + + e "simrs-vx/internal/domain/bpjs-entities/referral" + u "simrs-vx/internal/use-case/bpjs-use-case/referral" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" +) + +func GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadDetailDto{} + number := rw.ValidateString(w, "number", r.PathValue("number")) + if number == "" { + rw.WriteJSON(w, http.StatusBadRequest, d.IS{"message": "number is required"}, nil) + } + dto.Number = &number + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/resume/handler.go b/internal/interface/main-handler/resume/handler.go new file mode 100644 index 00000000..24ac0b08 --- /dev/null +++ b/internal/interface/main-handler/resume/handler.go @@ -0,0 +1,125 @@ +package resume + +import ( + "net/http" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/resume" + u "simrs-vx/internal/use-case/main-use-case/resume" + + erc "simrs-vx/internal/domain/references/common" + + pa "simrs-vx/internal/lib/auth" +) + +func Create(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + dto.AuthInfo = *authInfo + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func 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 GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + sf.UrlQueryParam(&dto, *r.URL) + dto.Id = uint(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func Update(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + 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) + dto.AuthInfo = *authInfo + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func Delete(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint(id) + dto.AuthInfo = *authInfo + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} + +func Verify(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + dto.Id = uint(id) + dto.Status_Code = erc.DVCVerified + dto.AuthInfo = *authInfo + res, err := u.UpdateStatusCode(dto) + rw.DataResponse(w, res, err) +} + +func Validate(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + dto.Id = uint(id) + dto.Status_Code = erc.DVCValidated + dto.AuthInfo = *authInfo + res, err := u.UpdateStatusCode(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/screening/handler.go b/internal/interface/main-handler/screening/handler.go new file mode 100644 index 00000000..a6866cc9 --- /dev/null +++ b/internal/interface/main-handler/screening/handler.go @@ -0,0 +1,80 @@ +package screening + +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/screening" + u "simrs-vx/internal/use-case/main-use-case/screening" + + pa "simrs-vx/internal/lib/auth" + + d "github.com/karincake/dodol" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.AuthInfo = *authInfo + 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 = 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/soapi/handler.go b/internal/interface/main-handler/soapi/handler.go index fe50b7d2..3683bb23 100644 --- a/internal/interface/main-handler/soapi/handler.go +++ b/internal/interface/main-handler/soapi/handler.go @@ -47,7 +47,7 @@ func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { return } dto := e.ReadDetailDto{} - dto.Id = uint16(id) + dto.Id = uint(id) res, err := u.ReadDetail(dto) rw.DataResponse(w, res, err) } @@ -62,7 +62,7 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } - dto.Id = uint16(id) + dto.Id = uint(id) res, err := u.Update(dto) rw.DataResponse(w, res, err) } @@ -74,7 +74,7 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { } dto := e.DeleteDto{} - dto.Id = uint16(id) + dto.Id = uint(id) res, err := u.Delete(dto) rw.DataResponse(w, res, err) } diff --git a/internal/interface/main-handler/therapy-protocol/handler.go b/internal/interface/main-handler/therapy-protocol/handler.go index 2d9efc3b..769e5677 100644 --- a/internal/interface/main-handler/therapy-protocol/handler.go +++ b/internal/interface/main-handler/therapy-protocol/handler.go @@ -9,7 +9,12 @@ import ( // ua "github.com/karincake/tumpeng/auth/svc" e "simrs-vx/internal/domain/main-entities/therapy-protocol" + erc "simrs-vx/internal/domain/references/common" u "simrs-vx/internal/use-case/main-use-case/therapy-protocol" + + d "github.com/karincake/dodol" + + pa "simrs-vx/internal/lib/auth" ) type myBase struct{} @@ -71,3 +76,44 @@ func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { res, err := u.Delete(dto) rw.DataResponse(w, res, err) } + +func (obj myBase) Verify(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.VerifyDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + dto.Id = uint(id) + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + + dto.AuthInfo = *authInfo + dto.Status_Code = erc.DVCVerified + res, err := u.Verify(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Reject(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.VerifyDto{} + dto.Id = uint(id) + authInfo, err := pa.GetAuthInfo(r) + if err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil) + } + dto.AuthInfo = *authInfo + dto.Status_Code = erc.DVCRejected + res, err := u.Verify(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/upload/handler.go b/internal/interface/main-handler/upload-file/handler.go similarity index 84% rename from internal/interface/main-handler/upload/handler.go rename to internal/interface/main-handler/upload-file/handler.go index 9f1f45a0..ac09fb65 100644 --- a/internal/interface/main-handler/upload/handler.go +++ b/internal/interface/main-handler/upload-file/handler.go @@ -1,17 +1,15 @@ -package upload +package uploadfile import ( "net/http" "strconv" - eru "simrs-vx/internal/domain/references/upload" - d "github.com/karincake/dodol" rw "github.com/karincake/risoles" - e "simrs-vx/internal/domain/main-entities/upload" + ere "simrs-vx/internal/domain/references/encounter" - u "simrs-vx/internal/use-case/main-use-case/upload" + u "simrs-vx/internal/use-case/main-use-case/upload-file" ) type myBase struct{} @@ -50,10 +48,10 @@ func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { } } - dto := e.CreateDto{ - EntityType_Code: eru.EntityTypeCode(r.FormValue("entityType_code")), + dto := u.CreateDto{ + EntityType_Code: ere.EntityTypeCode(r.FormValue("entityType_code")), Ref_Id: refID, - Type_Code: eru.UploadCode(r.FormValue("type_code")), + Type_Code: ere.DocTypeCode(r.FormValue("type_code")), Name: r.FormValue("name"), Upload_Employee_Id: employeeId, File: file, @@ -86,4 +84,5 @@ func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { } func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + } diff --git a/internal/interface/main-handler/upload/validate-request.go b/internal/interface/main-handler/upload-file/validate-request.go similarity index 64% rename from internal/interface/main-handler/upload/validate-request.go rename to internal/interface/main-handler/upload-file/validate-request.go index 38ae492c..72161e81 100644 --- a/internal/interface/main-handler/upload/validate-request.go +++ b/internal/interface/main-handler/upload-file/validate-request.go @@ -1,10 +1,10 @@ -package upload +package uploadfile import ( - e "simrs-vx/internal/domain/main-entities/upload" + u "simrs-vx/internal/use-case/main-use-case/upload-file" ) -func validateCreate(dto e.CreateDto) string { +func validateCreate(dto u.CreateDto) string { switch { case dto.EntityType_Code == "": diff --git a/internal/interface/bpjs-handler/vclaim-sep-hist/handler.go b/internal/interface/main-handler/vclaim-sep-hist/handler.go similarity index 100% rename from internal/interface/bpjs-handler/vclaim-sep-hist/handler.go rename to internal/interface/main-handler/vclaim-sep-hist/handler.go diff --git a/internal/interface/bpjs-handler/vclaim-sep-print/handler.go b/internal/interface/main-handler/vclaim-sep-print/handler.go similarity index 100% rename from internal/interface/bpjs-handler/vclaim-sep-print/handler.go rename to internal/interface/main-handler/vclaim-sep-print/handler.go diff --git a/internal/interface/bpjs-handler/vclaim-sep/handler.go b/internal/interface/main-handler/vclaim-sep/handler.go similarity index 60% rename from internal/interface/bpjs-handler/vclaim-sep/handler.go rename to internal/interface/main-handler/vclaim-sep/handler.go index d40c76e9..1529e2d8 100644 --- a/internal/interface/bpjs-handler/vclaim-sep/handler.go +++ b/internal/interface/main-handler/vclaim-sep/handler.go @@ -1,7 +1,6 @@ package vclaimsep import ( - "io" "net/http" rw "github.com/karincake/risoles" @@ -16,14 +15,9 @@ var O myBase func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { dto := e.CreateDto{} - body, err := io.ReadAll(r.Body) - if err != nil { - http.Error(w, "failed to read body", http.StatusBadRequest) + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { return } - defer r.Body.Close() - - dto.RequestPayload = body res, err := u.Create(dto) rw.DataResponse(w, res, err) } @@ -35,39 +29,39 @@ func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { // 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 { +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + number := rw.ValidateString(w, "number", r.PathValue("number")) + if number <= "" { + return + } + dto := e.ReadDetailDto{} + dto.Number = &number + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +// func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { +// number := rw.ValidateString(w, "number", r.PathValue("number")) +// if number != "" { // return // } -// dto := e.ReadDetailDto{} -// dto.Id = uint(id) -// res, err := u.ReadDetail(dto) + +// dto := e.UpdateDto{} +// if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { +// return +// } +// dto.Number = &number +// res, err := u.Update(dto) // rw.DataResponse(w, res, err) // } -func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { - number := rw.ValidateString(w, "number", r.PathValue("number")) - if number != "" { - return - } - - dto := e.UpdateDto{} - if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { - return - } - dto.Number = &number - res, err := u.Update(dto) - rw.DataResponse(w, res, err) -} - func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { - number := rw.ValidateString(w, "number", r.PathValue("number")) - if number != "" { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { return } dto := e.DeleteDto{} - dto.Number = &number + dto.Id = uint(id) res, err := u.Delete(dto) rw.DataResponse(w, res, err) } diff --git a/internal/interface/main-sync-handler/main-sync-handler.go b/internal/interface/main-sync-handler/main-sync-handler.go deleted file mode 100644 index c8ba5144..00000000 --- a/internal/interface/main-sync-handler/main-sync-handler.go +++ /dev/null @@ -1,36 +0,0 @@ -package mainsynchandler - -import ( - "net/http" - - /******************** infra ********************/ - gs "simrs-vx/internal/infra/gorm-setting" - synccfg "simrs-vx/internal/infra/sync-cfg" - - /******************** pkg ********************/ - cmw "simrs-vx/pkg/cors-manager-mw" - lh "simrs-vx/pkg/lang-helper" - handlerlogger "simrs-vx/pkg/middleware/handler-logger" - zlc "simrs-vx/pkg/zerolog-ctx" - - /******************** external ********************/ - a "github.com/karincake/apem" - - /******************** internal ********************/ - "simrs-vx/internal/interface/main-handler/home" -) - -func SetRoutes() http.Handler { - /// - a.RegisterExtCall(gs.Adjust) - a.RegisterExtCall(zlc.Adjust) - a.RegisterExtCall(lh.Populate) - a.RegisterExtCall(synccfg.SetConfig) - - r := http.NewServeMux() - - /******************** Main ********************/ - r.HandleFunc("/", home.Home) - - return cmw.SetCors(handlerlogger.SetLog(r)) -} diff --git a/internal/interface/migration/main-entities.go b/internal/interface/migration/main-entities.go index 272cd4ce..af3b35d3 100644 --- a/internal/interface/migration/main-entities.go +++ b/internal/interface/migration/main-entities.go @@ -7,17 +7,23 @@ import ( ambulatory "simrs-vx/internal/domain/main-entities/ambulatory" antibioticinuse "simrs-vx/internal/domain/main-entities/antibiotic-in-use" antibioticsrccategory "simrs-vx/internal/domain/main-entities/antibiotic-src-category" + apmcuorder "simrs-vx/internal/domain/main-entities/ap-mcu-order" appointment "simrs-vx/internal/domain/main-entities/appointment" authpartner "simrs-vx/internal/domain/main-entities/auth-partner" chemo "simrs-vx/internal/domain/main-entities/chemo" + chemoplan "simrs-vx/internal/domain/main-entities/chemo-plan" chemoprotocol "simrs-vx/internal/domain/main-entities/chemo-protocol" consultation "simrs-vx/internal/domain/main-entities/consultation" controlletter "simrs-vx/internal/domain/main-entities/control-letter" counter "simrs-vx/internal/domain/main-entities/counter" + cpmcuorder "simrs-vx/internal/domain/main-entities/cp-mcu-order" + cpmcuorderitem "simrs-vx/internal/domain/main-entities/cp-mcu-order-item" deathcause "simrs-vx/internal/domain/main-entities/death-cause" device "simrs-vx/internal/domain/main-entities/device" deviceorder "simrs-vx/internal/domain/main-entities/device-order" deviceorderitem "simrs-vx/internal/domain/main-entities/device-order-item" + devicepackage "simrs-vx/internal/domain/main-entities/device-package" + devicepackageitem "simrs-vx/internal/domain/main-entities/device-package-item" 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" @@ -45,6 +51,8 @@ import ( material "simrs-vx/internal/domain/main-entities/material" materialorder "simrs-vx/internal/domain/main-entities/material-order" materialorderitem "simrs-vx/internal/domain/main-entities/material-order-item" + materialpackage "simrs-vx/internal/domain/main-entities/material-package" + materialpackageitem "simrs-vx/internal/domain/main-entities/material-package-item" mcuorder "simrs-vx/internal/domain/main-entities/mcu-order" mcuorderitem "simrs-vx/internal/domain/main-entities/mcu-order-item" mcuordersubitem "simrs-vx/internal/domain/main-entities/mcu-order-sub-item" @@ -57,10 +65,13 @@ import ( medicationitem "simrs-vx/internal/domain/main-entities/medication-item" medicationitemdist "simrs-vx/internal/domain/main-entities/medication-item-dist" medicine "simrs-vx/internal/domain/main-entities/medicine" + medicineform "simrs-vx/internal/domain/main-entities/medicine-form" 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" + micromcuorder "simrs-vx/internal/domain/main-entities/micro-mcu-order" + micromcuorderitem "simrs-vx/internal/domain/main-entities/micro-mcu-order-item" midwife "simrs-vx/internal/domain/main-entities/midwife" nurse "simrs-vx/internal/domain/main-entities/nurse" nutritionist "simrs-vx/internal/domain/main-entities/nutritionist" @@ -76,13 +87,21 @@ import ( practiceschedule "simrs-vx/internal/domain/main-entities/practice-schedule" prescription "simrs-vx/internal/domain/main-entities/prescription" prescriptionitem "simrs-vx/internal/domain/main-entities/prescription-item" + procedurereport "simrs-vx/internal/domain/main-entities/procedure-report" + procedureroom "simrs-vx/internal/domain/main-entities/procedure-room" + procedureroomorder "simrs-vx/internal/domain/main-entities/procedure-room-order" + procedureroomorderitem "simrs-vx/internal/domain/main-entities/procedure-room-order-item" proceduresrc "simrs-vx/internal/domain/main-entities/procedure-src" province "simrs-vx/internal/domain/main-entities/province" + radiologymcuorder "simrs-vx/internal/domain/main-entities/radiology-mcu-order" + radiologymcuorderitem "simrs-vx/internal/domain/main-entities/radiology-mcu-order-item" regency "simrs-vx/internal/domain/main-entities/regency" + registrator "simrs-vx/internal/domain/main-entities/registrator" rehab "simrs-vx/internal/domain/main-entities/rehab" responsibledoctorhist "simrs-vx/internal/domain/main-entities/responsible-doctor-hist" - room "simrs-vx/internal/domain/main-entities/room" + resume "simrs-vx/internal/domain/main-entities/resume" sbar "simrs-vx/internal/domain/main-entities/sbar" + screening "simrs-vx/internal/domain/main-entities/screening" soapi "simrs-vx/internal/domain/main-entities/soapi" specialist "simrs-vx/internal/domain/main-entities/specialist" specialistintern "simrs-vx/internal/domain/main-entities/specialist-intern" @@ -101,7 +120,9 @@ import ( ///BPJS vclaimmember "simrs-vx/internal/domain/bpjs-entities/vclaim-member" + vclaimreference "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" vclaimsep "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + vclaimsepcontrolletter "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" vclaimsephist "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-hist" vclaimsepprint "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-print" ) @@ -128,6 +149,7 @@ func getMainEntities() []any { &proceduresrc.ProcedureSrc{}, &employee.Employee{}, &intern.Intern{}, + ®istrator.Registrator{}, &doctor.Doctor{}, &nurse.Nurse{}, &nutritionist.Nutritionist{}, @@ -138,6 +160,7 @@ func getMainEntities() []any { &item.Item{}, &itemprice.ItemPrice{}, &infra.Infra{}, + &procedureroom.ProcedureRoom{}, &medicinegroup.MedicineGroup{}, &medicinemethod.MedicineMethod{}, &mcusrccategory.McuSrcCategory{}, @@ -145,6 +168,7 @@ func getMainEntities() []any { ðnic.Ethnic{}, &insurancecompany.InsuranceCompany{}, &medicine.Medicine{}, + &medicineform.MedicineForm{}, &medicinemix.MedicineMix{}, &medicinemixitem.MedicineMixItem{}, &medicalactionsrc.MedicalActionSrc{}, @@ -156,13 +180,17 @@ func getMainEntities() []any { &personrelative.PersonRelative{}, &patient.Patient{}, &appointment.Appointment{}, + &devicepackage.DevicePackage{}, + &devicepackageitem.DevicePackageItem{}, + &materialpackage.MaterialPackage{}, + &materialpackageitem.MaterialPackageItem{}, + &vclaimsep.VclaimSep{}, &encounter.Encounter{}, &laborant.Laborant{}, &specialist.Specialist{}, &subspecialist.Subspecialist{}, &specialistintern.SpecialistIntern{}, - &room.Room{}, &soapi.Soapi{}, &sbar.Sbar{}, &adime.Adime{}, @@ -182,6 +210,13 @@ func getMainEntities() []any { &mcuorderitem.McuOrderItem{}, &mcusubsrc.McuSubSrc{}, &mcuordersubitem.McuOrderSubItem{}, + &apmcuorder.ApMcuOrder{}, + &radiologymcuorder.RadiologyMcuOrder{}, + &radiologymcuorderitem.RadiologyMcuOrderItem{}, + &cpmcuorder.CpMcuOrder{}, + &cpmcuorderitem.CpMcuOrderItem{}, + µmcuorder.MicroMcuOrder{}, + µmcuorderitem.MicroMcuOrderItem{}, &antibioticsrccategory.AntibioticSrcCategory{}, &antibioticinuse.AntibioticInUse{}, &consultation.Consultation{}, @@ -189,6 +224,9 @@ func getMainEntities() []any { &midwife.Midwife{}, &postalregion.PostalRegion{}, &internalreference.InternalReference{}, + &procedureroomorder.ProcedureRoomOrder{}, + &procedureroomorderitem.ProcedureRoomOrderItem{}, + &vclaimsephist.VclaimSepHist{}, &vclaimsepprint.VclaimSepPrint{}, &vehicle.Vehicle{}, @@ -209,5 +247,11 @@ func getMainEntities() []any { &rehab.Rehab{}, &chemoprotocol.ChemoProtocol{}, &fileattachemnt.EncounterDocument{}, + &vclaimsepcontrolletter.VclaimSepControlLetter{}, + &resume.Resume{}, + &vclaimreference.VclaimReference{}, + &screening.Screening{}, + &procedurereport.ProcedureReport{}, + &chemoplan.ChemoPlan{}, } } diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 6cec68dc..15341164 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -31,6 +31,8 @@ func getEntities(input string) []any { return getMainEntities() case "satusehat": return getSatuSehatEntities() + case "simgossync": + return getSyncEntities() } return nil } diff --git a/internal/interface/migration/simgossync-entities.go b/internal/interface/migration/simgossync-entities.go new file mode 100644 index 00000000..2c479521 --- /dev/null +++ b/internal/interface/migration/simgossync-entities.go @@ -0,0 +1,46 @@ +package migration + +import ( + /************** Source ***************/ + division "simrs-vx/internal/domain/sync-entities/division" + encounter "simrs-vx/internal/domain/sync-entities/encounter" + installation "simrs-vx/internal/domain/sync-entities/installation" + internalreference "simrs-vx/internal/domain/sync-entities/internal-reference" + patient "simrs-vx/internal/domain/sync-entities/patient" + soapi "simrs-vx/internal/domain/sync-entities/soapi" + specialist "simrs-vx/internal/domain/sync-entities/specialist" + subspecialist "simrs-vx/internal/domain/sync-entities/subspecialist" + unit "simrs-vx/internal/domain/sync-entities/unit" +) + +func getSyncEntities() []any { + return []any{ + &installation.InstallationLink{}, + &installation.InstallationSimxLog{}, + &installation.InstallationSimgosLog{}, + &unit.UnitLink{}, + &unit.UnitSimxLog{}, + &unit.UnitSimgosLog{}, + &division.DivisionLink{}, + &division.DivisionSimxLog{}, + &division.DivisionSimgosLog{}, + &specialist.SpecialistLink{}, + &specialist.SpecialistSimxLog{}, + &specialist.SpecialistSimgosLog{}, + &subspecialist.SubspecialistLink{}, + &subspecialist.SubspecialistSimxLog{}, + &subspecialist.SubspecialistSimgosLog{}, + &patient.PatientLink{}, + &patient.PatientSimxLog{}, + &patient.PatientSimgosLog{}, + &encounter.EncounterLink{}, + &encounter.EncounterSimxLog{}, + &encounter.EncounterSimgosLog{}, + &internalreference.InternalReferenceLink{}, + &internalreference.InternalReferenceSimxLog{}, + &internalreference.InternalReferenceSimgosLog{}, + &soapi.SoapiLink{}, + &soapi.SoapiSimxLog{}, + &soapi.SoapiSimgosLog{}, + } +} diff --git a/internal/interface/migration/tycovar.go b/internal/interface/migration/tycovar.go index f86f855d..f6c57b4b 100644 --- a/internal/interface/migration/tycovar.go +++ b/internal/interface/migration/tycovar.go @@ -2,6 +2,7 @@ package migration const ( - Main = "main" - SatuSehat = "satusehat" + Main = "main" + SatuSehat = "satusehat" + SimgosSync = "simgossync" ) diff --git a/internal/interface/simgos-sync-handler/new/division/handler.go b/internal/interface/simgos-sync-handler/new/division/handler.go new file mode 100644 index 00000000..28920d21 --- /dev/null +++ b/internal/interface/simgos-sync-handler/new/division/handler.go @@ -0,0 +1,67 @@ +package division + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/division" + esync "simrs-vx/internal/domain/sync-entities/log" + + u "simrs-vx/internal/use-case/simgos-sync-use-case/new/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) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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 + } + + val := uint16(id) + dto.Id = &val + + 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{} + val := uint16(id) + dto.Id = &val + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/new/encounter/handler.go b/internal/interface/simgos-sync-handler/new/encounter/handler.go new file mode 100644 index 00000000..aef2f7d2 --- /dev/null +++ b/internal/interface/simgos-sync-handler/new/encounter/handler.go @@ -0,0 +1,118 @@ +package encounter + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/encounter" + esync "simrs-vx/internal/domain/sync-entities/log" + + u "simrs-vx/internal/use-case/simgos-sync-use-case/new/encounter" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.Encounter{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + dto := e.Encounter{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + 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) +} + +func (obj myBase) Checkin(w http.ResponseWriter, r *http.Request) { + dto := e.Encounter{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + res, err := u.CheckIn(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Checkout(w http.ResponseWriter, r *http.Request) { + dto := e.Encounter{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + res, err := u.CheckOut(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) UpdateStatus(w http.ResponseWriter, r *http.Request) { + dto := e.Encounter{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + res, err := u.UpdateStatus(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) RequestSwitchUnit(w http.ResponseWriter, r *http.Request) { + dto := e.Encounter{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + res, err := u.RequestSwitchUnit(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) ApproveSwitchUnit(w http.ResponseWriter, r *http.Request) { + dto := e.ApproveCancelUnitDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + res, err := u.ApproveSwitchUnit(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) CancelSwitchUnit(w http.ResponseWriter, r *http.Request) { + dto := e.ApproveCancelUnitDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + res, err := u.CancelSwitchUnit(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/new/installation/handler.go b/internal/interface/simgos-sync-handler/new/installation/handler.go new file mode 100644 index 00000000..3a1eca93 --- /dev/null +++ b/internal/interface/simgos-sync-handler/new/installation/handler.go @@ -0,0 +1,67 @@ +package installation + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/installation" + esync "simrs-vx/internal/domain/sync-entities/log" + + u "simrs-vx/internal/use-case/simgos-sync-use-case/new/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) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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 + } + + val := uint16(id) + dto.Id = &val + + 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{} + val := uint16(id) + dto.Id = &val + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/new/patient/handler.go b/internal/interface/simgos-sync-handler/new/patient/handler.go new file mode 100644 index 00000000..f3c3951b --- /dev/null +++ b/internal/interface/simgos-sync-handler/new/patient/handler.go @@ -0,0 +1,69 @@ +package patient + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/patient" + esync "simrs-vx/internal/domain/sync-entities/log" + + u "simrs-vx/internal/use-case/simgos-sync-use-case/new/patient" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.Patient{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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.Patient{} + 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) +} + +func (obj myBase) GenerateNomr(w http.ResponseWriter, r *http.Request) { + res, err := u.GenerateNomr() + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/new/soapi/handler.go b/internal/interface/simgos-sync-handler/new/soapi/handler.go new file mode 100644 index 00000000..3a52a581 --- /dev/null +++ b/internal/interface/simgos-sync-handler/new/soapi/handler.go @@ -0,0 +1,58 @@ +package soapi + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/soapi" + esync "simrs-vx/internal/domain/sync-entities/log" + + u "simrs-vx/internal/use-case/simgos-sync-use-case/new/soapi" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.Soapi{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + dto := e.Soapi{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + + 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/simgos-sync-handler/new/specialist/handler.go b/internal/interface/simgos-sync-handler/new/specialist/handler.go new file mode 100644 index 00000000..2afe3f13 --- /dev/null +++ b/internal/interface/simgos-sync-handler/new/specialist/handler.go @@ -0,0 +1,67 @@ +package specialist + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/specialist" + esync "simrs-vx/internal/domain/sync-entities/log" + + u "simrs-vx/internal/use-case/simgos-sync-use-case/new/specialist" +) + +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) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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 + } + + val := uint16(id) + dto.Id = &val + + 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{} + val := uint16(id) + dto.Id = &val + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/new/subspecialist/handler.go b/internal/interface/simgos-sync-handler/new/subspecialist/handler.go new file mode 100644 index 00000000..0bfd2226 --- /dev/null +++ b/internal/interface/simgos-sync-handler/new/subspecialist/handler.go @@ -0,0 +1,66 @@ +package subspecialist + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/subspecialist" + esync "simrs-vx/internal/domain/sync-entities/log" + u "simrs-vx/internal/use-case/simgos-sync-use-case/new/subspecialist" +) + +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) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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 + } + + val := uint16(id) + dto.Id = &val + + 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{} + val := uint16(id) + dto.Id = &val + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/new/unit/handler.go b/internal/interface/simgos-sync-handler/new/unit/handler.go new file mode 100644 index 00000000..95808728 --- /dev/null +++ b/internal/interface/simgos-sync-handler/new/unit/handler.go @@ -0,0 +1,67 @@ +package unit + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/unit" + esync "simrs-vx/internal/domain/sync-entities/log" + + u "simrs-vx/internal/use-case/simgos-sync-use-case/new/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) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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 + } + + val := uint16(id) + dto.Id = &val + + 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{} + val := uint16(id) + dto.Id = &val + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/domain/simgos-sync-entities/.keep b/internal/interface/simgos-sync-handler/old/.keep similarity index 100% rename from internal/domain/simgos-sync-entities/.keep rename to internal/interface/simgos-sync-handler/old/.keep diff --git a/internal/interface/simgos-sync-handler/old/authentication/authentication.go b/internal/interface/simgos-sync-handler/old/authentication/authentication.go new file mode 100644 index 00000000..282e1ea6 --- /dev/null +++ b/internal/interface/simgos-sync-handler/old/authentication/authentication.go @@ -0,0 +1,52 @@ +package authentication + +import ( + "context" + "net/http" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" + + sc "simrs-vx/internal/lib/sync-credential" + + e "simrs-vx/internal/domain/sync-entities/authentication" + is "simrs-vx/internal/infra/sync-cfg" +) + +func NewGuardMW(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // check the data format + input := e.CredentialDto{} + if success := sc.CheckCredentialData(&input, r, w); !success { + return + } + + // check the validity + if input.Source != is.O.NewSource || input.SecretKey != is.O.NewSecretKey { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "invalid consumer credential"}, nil) + return + } + + ctx := context.WithValue(r.Context(), e.SyncKey{}, input) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +func OldGuardMW(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // check the data format + input := e.CredentialDto{} + if success := sc.CheckCredentialData(&input, r, w); !success { + return + } + + // check the validity + if input.Source != is.O.OldSource || input.SecretKey != is.O.OldSecretKey { + rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": "invalid consumer credential"}, nil) + return + } + + ctx := context.WithValue(r.Context(), e.SyncKey{}, input) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} diff --git a/internal/interface/simgos-sync-handler/old/patient/handler.go b/internal/interface/simgos-sync-handler/old/patient/handler.go new file mode 100644 index 00000000..4c697fd4 --- /dev/null +++ b/internal/interface/simgos-sync-handler/old/patient/handler.go @@ -0,0 +1,48 @@ +package patient + +import ( + "net/http" + + p "simrs-vx/internal/domain/simgos-entities/m-pasien" + uo "simrs-vx/internal/use-case/simgos-sync-use-case/old/patient" + + rw "github.com/karincake/risoles" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := p.MPasienDto{} + if !rw.ValidateStructByIOR(w, r.Body, &dto) { + return + } + + // mapping m_patient to patient + patient := dto.ToPatient() + res, err := uo.Create(patient) + rw.DataResponse(w, res, err) + +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + + dto := p.MPasienDto{} + if !rw.ValidateStructByIOR(w, r.Body, &dto) { + return + } + patient := dto.ToPatient() + res, err := uo.Update(patient) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + dto := p.MPasienDto{} + if !rw.ValidateStructByIOR(w, r.Body, &dto) { + return + } + patient := dto.ToPatient() + res, err := uo.Delete(patient) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/simgos-sync-handler.go b/internal/interface/simgos-sync-handler/simgos-sync-handler.go index f51106a9..a47b38d4 100644 --- a/internal/interface/simgos-sync-handler/simgos-sync-handler.go +++ b/internal/interface/simgos-sync-handler/simgos-sync-handler.go @@ -5,19 +5,34 @@ import ( /******************** infra ********************/ gs "simrs-vx/internal/infra/gorm-setting" - synccfg "simrs-vx/internal/infra/sync-cfg" + simgosdb "simrs-vx/internal/infra/simgos-db" + sync "simrs-vx/internal/infra/sync-cfg" /******************** 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" zlc "simrs-vx/pkg/zerolog-ctx" /******************** external ********************/ a "github.com/karincake/apem" + hk "github.com/karincake/hongkue" /******************** internal ********************/ "simrs-vx/internal/interface/main-handler/home" + "simrs-vx/internal/interface/simgos-sync-handler/new/division" + "simrs-vx/internal/interface/simgos-sync-handler/new/encounter" + "simrs-vx/internal/interface/simgos-sync-handler/new/installation" + "simrs-vx/internal/interface/simgos-sync-handler/new/patient" + "simrs-vx/internal/interface/simgos-sync-handler/new/soapi" + "simrs-vx/internal/interface/simgos-sync-handler/new/specialist" + "simrs-vx/internal/interface/simgos-sync-handler/new/subspecialist" + "simrs-vx/internal/interface/simgos-sync-handler/new/unit" + + oldpatient "simrs-vx/internal/interface/simgos-sync-handler/old/patient" + + oauth "simrs-vx/internal/interface/simgos-sync-handler/old/authentication" // just a reminder, an openauth ) func SetRoutes() http.Handler { @@ -25,12 +40,48 @@ func SetRoutes() http.Handler { a.RegisterExtCall(gs.Adjust) a.RegisterExtCall(zlc.Adjust) a.RegisterExtCall(lh.Populate) - a.RegisterExtCall(synccfg.SetConfig) + a.RegisterExtCall(sync.SetConfig) + a.RegisterExtCall(simgosdb.SetInstance) r := http.NewServeMux() /******************** Main ********************/ r.HandleFunc("/", home.Home) + /******************** SvcToOld ******************/ + prefixnew := "/new-to-old" + hc.SyncCrud(r, prefixnew+"/v1/installation", installation.O) + hc.SyncCrud(r, prefixnew+"/v1/unit", unit.O) + hc.SyncCrud(r, prefixnew+"/v1/division", division.O) + hc.SyncCrud(r, prefixnew+"/v1/specialist", specialist.O) + hc.SyncCrud(r, prefixnew+"/v1/subspecialist", subspecialist.O) + hk.GroupRoutes(prefixnew+"/v1/patient", r, hk.MapHandlerFunc{ + "POST /": patient.O.Create, + "POST /log": patient.O.CreateLog, + "PATCH /{id}": patient.O.Update, + "DELETE /{id}": patient.O.Delete, + "POST /nomr": patient.O.GenerateNomr, + }) + hk.GroupRoutes(prefixnew+"/v1/encounter", r, hk.MapHandlerFunc{ + "POST /": encounter.O.Create, + "POST /log": encounter.O.CreateLog, + "PATCH /{id}": encounter.O.Update, + "DELETE /{id}": encounter.O.Delete, + "PATCH /{id}/checkin": encounter.O.Checkin, + "PATCH /{id}/checkout": encounter.O.Checkout, + "PATCH /{id}/update-status": encounter.O.UpdateStatus, + "PATCH /{id}/req-switch-unit": encounter.O.RequestSwitchUnit, + "PATCH /{id}/approve-switch-unit": encounter.O.ApproveSwitchUnit, + "PATCH /{id}/cancel-switch-unit": encounter.O.CancelSwitchUnit, + }) + hc.SyncCrud(r, prefixnew+"/v1/soapi", soapi.O) + + /******************** SvcToNew ******************/ + prefixold := "/old-to-new" + hk.GroupRoutes(prefixold+"/v1/patient", r, oauth.OldGuardMW, hk.MapHandlerFunc{ + "POST /": oldpatient.O.Create, + "PATCH /{id}": oldpatient.O.Update, + "DELETE /{id}": oldpatient.O.Delete, + }) // FINISH THIS return cmw.SetCors(handlerlogger.SetLog(r)) } diff --git a/internal/lib/auth/tycovar.go b/internal/lib/auth/tycovar.go index 467bd1b6..ba5be2fc 100644 --- a/internal/lib/auth/tycovar.go +++ b/internal/lib/auth/tycovar.go @@ -11,7 +11,7 @@ type AuthInfo struct { Uuid string User_Id uint User_Name string - User_ContractPosition_code string + User_ContractPosition_Code string Employee_Position_Code *string Employee_Id *uint Doctor_Code *string @@ -22,6 +22,7 @@ type AuthInfo struct { Pharmachist_Code *string Intern_Position_Code *string Roles []string + Sync bool // User_DivisionPositions []DivisionPosition } @@ -65,19 +66,26 @@ func (a AuthInfo) IsPharmacist() bool { return *a.Employee_Position_Code == string(ero.EPCPha) } -func (a AuthInfo) IsPayment() bool { +func (a AuthInfo) IsScreener() bool { // MPP, petugas skrining if a.Employee_Position_Code == nil { return false } - return *a.Employee_Position_Code == string(ero.EPCPay) + return *a.Employee_Position_Code == string(ero.EPCScr) } -func (a AuthInfo) IsManagement() bool { - if a.Employee_Position_Code == nil { - return false - } - return *a.Employee_Position_Code == string(ero.EPCMan) -} +// func (a AuthInfo) IsPayment() bool { +// if a.Employee_Position_Code == nil { +// return false +// } +// return *a.Employee_Position_Code == string(ero.EPCPay) +// } + +// func (a AuthInfo) IsManagement() bool { +// if a.Employee_Position_Code == nil { +// return false +// } +// return *a.Employee_Position_Code == string(ero.EPCMan) +// } func (a AuthInfo) IsSpecialistIntern() bool { if a.Intern_Position_Code == nil { @@ -92,3 +100,15 @@ func (a AuthInfo) IsNurseIntern() bool { } return *a.Intern_Position_Code == string(ero.IPCNurse) } + +func (a AuthInfo) HasEmployeePosition() bool { + return a.Employee_Position_Code != nil +} + +func (a AuthInfo) IsReg() bool { + return a.Employee_Position_Code != nil && *a.Employee_Position_Code == string(ero.EPCReg) +} + +func (a AuthInfo) IsSys() bool { + return a.User_ContractPosition_Code == string(ero.CSCSys) +} diff --git a/internal/lib/sync-credential/helper.go b/internal/lib/sync-credential/helper.go new file mode 100644 index 00000000..e6c5952f --- /dev/null +++ b/internal/lib/sync-credential/helper.go @@ -0,0 +1,23 @@ +package authentication + +import ( + "net/http" + + d "github.com/karincake/dodol" + rw "github.com/karincake/risoles" + sr "github.com/karincake/serabi" + + e "simrs-vx/internal/domain/sync-entities/authentication" +) + +func CheckCredentialData(input *e.CredentialDto, r *http.Request, w http.ResponseWriter) bool { + input.Source = r.Header.Get("X-Sync-Source") + input.SecretKey = r.Header.Get("X-Sync-SecretKey") + input.UserName = r.Header.Get("X-Sync-UserName") + if err := sr.Validate(input); err != nil { + rw.WriteJSON(w, http.StatusUnauthorized, d.II{"errors": err}, nil) + return false + } + return true + +} diff --git a/internal/use-case/bpjs-plugin/control-plan/helper.go b/internal/use-case/bpjs-plugin/control-plan/helper.go new file mode 100644 index 00000000..15af7238 --- /dev/null +++ b/internal/use-case/bpjs-plugin/control-plan/helper.go @@ -0,0 +1,11 @@ +package controlplan + +import ( + "fmt" + e "simrs-vx/internal/domain/bpjs-entities/control-plan" + ibpjs "simrs-vx/internal/infra/bpjs" +) + +func endpointMapper(input *e.ReadListDto) string { + return fmt.Sprintf("%sRencanaKontrol/jadwalDokter?jeniskontrol=%s&kodepoli=%s&tanggalkontrol=%s", ibpjs.O.BaseUrl, input.PathValue1, input.PathValue2, input.PathValue3) +} diff --git a/internal/use-case/bpjs-plugin/control-plan/plugin.go b/internal/use-case/bpjs-plugin/control-plan/plugin.go new file mode 100644 index 00000000..276750ca --- /dev/null +++ b/internal/use-case/bpjs-plugin/control-plan/plugin.go @@ -0,0 +1,37 @@ +package controlplan + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + e "simrs-vx/internal/domain/bpjs-entities/control-plan" + + "gorm.io/gorm" +) + +func ReadList(input *e.ReadListDto, data *e.Response, tx *gorm.DB) error { + endpoint := endpointMapper(input) + req, err := http.NewRequest("GET", endpoint, nil) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if err := json.Unmarshal(body, &data); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } + + return nil +} diff --git a/internal/use-case/bpjs-plugin/referral/helper.go b/internal/use-case/bpjs-plugin/referral/helper.go new file mode 100644 index 00000000..169834be --- /dev/null +++ b/internal/use-case/bpjs-plugin/referral/helper.go @@ -0,0 +1,11 @@ +package referral + +import ( + "fmt" + e "simrs-vx/internal/domain/bpjs-entities/referral" + ibpjs "simrs-vx/internal/infra/bpjs" +) + +func endpointMapper(input *e.ReadDetailDto) string { + return fmt.Sprintf("%sRujukan/RS/%s", ibpjs.O.BaseUrl, *input.Number) +} diff --git a/internal/use-case/bpjs-plugin/referral/plugin.go b/internal/use-case/bpjs-plugin/referral/plugin.go new file mode 100644 index 00000000..225181e4 --- /dev/null +++ b/internal/use-case/bpjs-plugin/referral/plugin.go @@ -0,0 +1,37 @@ +package referral + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + e "simrs-vx/internal/domain/bpjs-entities/referral" + + "gorm.io/gorm" +) + +func ReadDetail(input *e.ReadDetailDto, data *e.Response, tx *gorm.DB) error { + endpoint := endpointMapper(input) + req, err := http.NewRequest("GET", endpoint, nil) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if err := json.Unmarshal(body, &data); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } + + return nil +} diff --git a/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go b/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go index fd18763f..4588029f 100644 --- a/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go +++ b/internal/use-case/bpjs-plugin/vclaim-sep/plugin.go @@ -14,7 +14,11 @@ import ( ) func CreateSep(input *e.CreateDto, data *e.VclaimSep, tx *gorm.DB) error { - req, err := http.NewRequest("POST", ibpjs.O.BaseUrl+"/sep", bytes.NewReader(input.RequestPayload)) + payload, err := input.RequestPayloadIntoJson() + if err != nil { + return err + } + req, err := http.NewRequest("POST", ibpjs.O.BaseUrl+"sep", bytes.NewBuffer(payload)) if err != nil { return err } @@ -43,7 +47,11 @@ func CreateSep(input *e.CreateDto, data *e.VclaimSep, tx *gorm.DB) error { } // Save request/response details in DTO for further use - input.VclaimSepHist.RequestPayload = string(input.RequestPayload) + reqPayload, err := input.RequestPayloadWithEncounterId() + if err != nil { + return err + } + input.VclaimSepHist.RequestPayload = string(reqPayload) input.VclaimSepHist.ResponseBody = string(body) input.VclaimSepHist.Message = msg input.Number = func() *string { @@ -56,3 +64,72 @@ func CreateSep(input *e.CreateDto, data *e.VclaimSep, tx *gorm.DB) error { return nil } + +func ReadDetailSep(input *e.ReadDetailDto, data *e.VclaimSep, tx *gorm.DB) error { + endpoint := fmt.Sprintf("sep/%s", input.Number) + req, err := http.NewRequest("GET", ibpjs.O.BaseUrl+endpoint, nil) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + var detail e.SepResponse + if err := json.Unmarshal(body, &detail); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } + + data.Detail = detail.Response + + return nil +} + +func DeleteSep(input *e.DeleteDto, data *e.VclaimSep, tx *gorm.DB) error { + payload := e.SepDeleteRequest{} + payload.Request.TSep.NoSep = *input.Number + payload.Request.TSep.User = "Coba Ws" + + jsonPayload, err := json.Marshal(payload) + if err != nil { + return err + } + + req, err := http.NewRequest("DELETE", ibpjs.O.BaseUrl+"sep", bytes.NewBuffer(jsonPayload)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + var detail e.SepResponse + if err := json.Unmarshal(body, &detail); err != nil { + return fmt.Errorf("failed to parse response JSON: %w", err) + } + + if detail.MetaData.Message == SepNotFound { + return fmt.Errorf("sep with number %s not found", *data.Number) + } + + return nil +} diff --git a/internal/use-case/bpjs-plugin/vclaim-sep/tycovar.go b/internal/use-case/bpjs-plugin/vclaim-sep/tycovar.go index f057726e..7c19c44c 100644 --- a/internal/use-case/bpjs-plugin/vclaim-sep/tycovar.go +++ b/internal/use-case/bpjs-plugin/vclaim-sep/tycovar.go @@ -10,3 +10,5 @@ type vclaimResponse struct { } `json:"sep"` } `json:"response"` } + +const SepNotFound = "Data Tidak Ditemukan" diff --git a/internal/use-case/bpjs-use-case/control-plan/case.go b/internal/use-case/bpjs-use-case/control-plan/case.go new file mode 100644 index 00000000..764ea2ea --- /dev/null +++ b/internal/use-case/bpjs-use-case/control-plan/case.go @@ -0,0 +1,50 @@ +package controlplan + +import ( + e "simrs-vx/internal/domain/bpjs-entities/control-plan" + + dg "github.com/karincake/apem/db-gorm-pg" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "control-plan" + +func ReadList(input e.ReadListDto) (*e.Response, error) { + var data e.Response + 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 + } + + 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 &data, nil +} diff --git a/internal/use-case/bpjs-use-case/control-plan/middleware-runner.go b/internal/use-case/bpjs-use-case/control-plan/middleware-runner.go new file mode 100644 index 00000000..4c3db3d8 --- /dev/null +++ b/internal/use-case/bpjs-use-case/control-plan/middleware-runner.go @@ -0,0 +1,42 @@ +package controlplan + +import ( + e "simrs-vx/internal/domain/bpjs-entities/control-plan" + 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, + } +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Response) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/bpjs-use-case/control-plan/middleware.go b/internal/use-case/bpjs-use-case/control-plan/middleware.go new file mode 100644 index 00000000..3478bb19 --- /dev/null +++ b/internal/use-case/bpjs-use-case/control-plan/middleware.go @@ -0,0 +1,12 @@ +package controlplan + +import ( + pcp "simrs-vx/internal/use-case/bpjs-plugin/control-plan" +) + +func init() { + readListPreMw = append(readListPreMw, + readListMw{Name: "readList-control-plan", Func: pcp.ReadList}, + ) + +} diff --git a/internal/use-case/bpjs-use-case/control-plan/tycovar.go b/internal/use-case/bpjs-use-case/control-plan/tycovar.go new file mode 100644 index 00000000..ea2b39a9 --- /dev/null +++ b/internal/use-case/bpjs-use-case/control-plan/tycovar.go @@ -0,0 +1,18 @@ +/* +member is peserta +*/ +package controlplan + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/control-plan" +) + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Response, tx *gorm.DB) error +} + +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. diff --git a/internal/use-case/bpjs-use-case/referral/case.go b/internal/use-case/bpjs-use-case/referral/case.go new file mode 100644 index 00000000..8818dc58 --- /dev/null +++ b/internal/use-case/bpjs-use-case/referral/case.go @@ -0,0 +1,50 @@ +package referral + +import ( + e "simrs-vx/internal/domain/bpjs-entities/referral" + + dg "github.com/karincake/apem/db-gorm-pg" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +const source = "referral" + +func ReadDetail(input e.ReadDetailDto) (*e.Response, error) { + var data e.Response + 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 + } + + 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 &data, nil +} diff --git a/internal/use-case/bpjs-use-case/referral/middleware-runner.go b/internal/use-case/bpjs-use-case/referral/middleware-runner.go new file mode 100644 index 00000000..10c26241 --- /dev/null +++ b/internal/use-case/bpjs-use-case/referral/middleware-runner.go @@ -0,0 +1,42 @@ +package referral + +import ( + e "simrs-vx/internal/domain/bpjs-entities/referral" + 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, + } +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Response) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/bpjs-use-case/referral/middleware.go b/internal/use-case/bpjs-use-case/referral/middleware.go new file mode 100644 index 00000000..0296ae5a --- /dev/null +++ b/internal/use-case/bpjs-use-case/referral/middleware.go @@ -0,0 +1,12 @@ +package referral + +import ( + pr "simrs-vx/internal/use-case/bpjs-plugin/referral" +) + +func init() { + readDetailPreMw = append(readDetailPreMw, + readDetailMw{Name: "read-detail-referral", Func: pr.ReadDetail}, + ) + +} diff --git a/internal/use-case/bpjs-use-case/referral/tycovar.go b/internal/use-case/bpjs-use-case/referral/tycovar.go new file mode 100644 index 00000000..b1950977 --- /dev/null +++ b/internal/use-case/bpjs-use-case/referral/tycovar.go @@ -0,0 +1,18 @@ +/* +member is peserta +*/ +package referral + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/referral" +) + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Response, tx *gorm.DB) error +} + +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw diff --git a/internal/use-case/bpjs-use-case/vclaim-reference/case.go b/internal/use-case/bpjs-use-case/vclaim-reference/case.go new file mode 100644 index 00000000..bfbfea34 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-reference/case.go @@ -0,0 +1,277 @@ +package vclaimreference + +import ( + "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" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" +) + +const source = "vclaim-reference" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.VclaimReference{} + + 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.VclaimReference + var dataList []e.VclaimReference + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.VclaimReference + 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.VclaimReference + 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.VclaimReference + 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/bpjs-use-case/vclaim-reference/helper.go b/internal/use-case/bpjs-use-case/vclaim-reference/helper.go new file mode 100644 index 00000000..9127921f --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-reference/helper.go @@ -0,0 +1,25 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package vclaimreference + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimReference) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Date = inputSrc.Date + data.SrcCode = inputSrc.SrcCode + data.SrcName = inputSrc.SrcName + data.Number = inputSrc.Number +} diff --git a/internal/use-case/bpjs-use-case/vclaim-reference/lib.go b/internal/use-case/bpjs-use-case/vclaim-reference/lib.go new file mode 100644 index 00000000..3f784edf --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-reference/lib.go @@ -0,0 +1,140 @@ +package vclaimreference + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "github.com/AzureAD/microsoft-authentication-library-for-go/apps/errors" + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" +) + +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimReference, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.VclaimReference{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.VclaimReference, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.VclaimReference{} + 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.VclaimReference{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimReference, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.VclaimReference{} + + 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.VclaimReference, 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.VclaimReference, 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/bpjs-use-case/vclaim-reference/middleware-runner.go b/internal/use-case/bpjs-use-case/vclaim-reference/middleware-runner.go new file mode 100644 index 00000000..c8ad1e8f --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-reference/middleware-runner.go @@ -0,0 +1,103 @@ +package vclaimreference + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" + 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.VclaimReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.VclaimReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.VclaimReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.VclaimReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.VclaimReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/bpjs-use-case/vclaim-reference/middleware.go b/internal/use-case/bpjs-use-case/vclaim-reference/middleware.go new file mode 100644 index 00000000..defdfa84 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-reference/middleware.go @@ -0,0 +1,9 @@ +package vclaimreference + +// 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/bpjs-use-case/vclaim-reference/tycovar.go b/internal/use-case/bpjs-use-case/vclaim-reference/tycovar.go new file mode 100644 index 00000000..29add547 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-reference/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 vclaimreference + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.VclaimReference, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.VclaimReference, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.VclaimReference, 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/bpjs-use-case/vclaim-sep-control-letter/case.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/case.go new file mode 100644 index 00000000..7c19819f --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/case.go @@ -0,0 +1,277 @@ +package vclaimsepcontrolletter + +import ( + "strconv" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" + + 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 = "vclaim-sep-control-letter" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.VclaimSepControlLetter{} + + 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.VclaimSepControlLetter + var dataList []e.VclaimSepControlLetter + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.VclaimSepControlLetter + 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{Number: input.Number} + var data *e.VclaimSepControlLetter + 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{Number: input.Number} + var data *e.VclaimSepControlLetter + 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/bpjs-use-case/vclaim-sep-control-letter/helper.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/helper.go new file mode 100644 index 00000000..891e7c4d --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package vclaimsepcontrolletter + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.VclaimSepControlLetter) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.VclaimSep_Number = inputSrc.VclaimSep_Number + data.Number = inputSrc.Number + data.Value = inputSrc.Value + data.FileUrl = inputSrc.FileUrl +} diff --git a/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/lib.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/lib.go new file mode 100644 index 00000000..9f66baff --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/lib.go @@ -0,0 +1,148 @@ +package vclaimsepcontrolletter + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" + + plh "simrs-vx/pkg/lib-helper" + 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.VclaimSepControlLetter, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.VclaimSepControlLetter{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + setData(&input, &data) + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.VclaimSepControlLetter, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.VclaimSepControlLetter{} + 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.VclaimSepControlLetter{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.VclaimSepControlLetter, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.VclaimSepControlLetter{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if input.Number != nil { + tx = tx.Where("\"Number\" = ?", *input.Number) + } + if input.Id != nil { + tx = tx.Where("\"Id\" = ?", *input.Id) + } + + if err := tx.First(&data).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.VclaimSepControlLetter, 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.VclaimSepControlLetter, 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/bpjs-use-case/vclaim-sep-control-letter/middleware-runner.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware-runner.go new file mode 100644 index 00000000..c0a0ecae --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware-runner.go @@ -0,0 +1,103 @@ +package vclaimsepcontrolletter + +import ( + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" + 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.VclaimSepControlLetter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.VclaimSepControlLetter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.VclaimSepControlLetter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.VclaimSepControlLetter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.VclaimSepControlLetter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/bpjs-use-case/vclaim-sep-control-letter/middleware.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware.go new file mode 100644 index 00000000..57262cc2 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/middleware.go @@ -0,0 +1,9 @@ +package vclaimsepcontrolletter + +// 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/bpjs-use-case/vclaim-sep-control-letter/tycovar.go b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/tycovar.go new file mode 100644 index 00000000..2e921ae9 --- /dev/null +++ b/internal/use-case/bpjs-use-case/vclaim-sep-control-letter/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 vclaimsepcontrolletter + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.VclaimSepControlLetter, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.VclaimSepControlLetter, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.VclaimSepControlLetter, 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/bpjs-use-case/vclaim-sep/case.go b/internal/use-case/bpjs-use-case/vclaim-sep/case.go index ac72d648..1d0e4aab 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/case.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/case.go @@ -1,6 +1,7 @@ package vclaimsep import ( + "fmt" "strconv" e "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" @@ -31,6 +32,17 @@ func Create(input e.CreateDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "create") err := dg.I.Transaction(func(tx *gorm.DB) error { + rDto := e.ReadDetailDto{Encounter_Id: input.Encounter_Id} + if vSep, err := ReadDetailData(rDto, &event, tx); err != nil { + if !pu.IsDataNotFoundError(err) { + return err + } + + if vSep != nil { + return fmt.Errorf("sep with encounter id %d already exist with number %s", input.Encounter_Id, *vSep.Number) + } + } + mwRunner := newMiddlewareRunner(&event, tx) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware @@ -38,12 +50,12 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } - if _, err := uvsh.CreateData(input.VclaimSepHist, &event, tx); err != nil { + if _, err := uvsh.CreateData(input.VclaimSepHist, &event); err != nil { return err } if !input.IsMessageSuccess() { - return nil + return fmt.Errorf("%s", input.VclaimSepHist.Message) } if resData, err := CreateData(input, &event, tx); err != nil { @@ -234,7 +246,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { } func Delete(input e.DeleteDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Number: input.Number} + rdDto := e.ReadDetailDto{Id: input.Id} var data *e.VclaimSep var err error @@ -255,7 +267,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { mwRunner := newMiddlewareRunner(&event, tx) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &e.DeleteDto{}, data); err != nil { return err } @@ -265,7 +277,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { mwRunner.setMwType(pu.MWTPost) // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + if err := mwRunner.RunDeleteMiddleware(deletePostMw, &e.DeleteDto{}, data); err != nil { return err } diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/lib.go b/internal/use-case/bpjs-use-case/vclaim-sep/lib.go index 817c357c..82da0d45 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/lib.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/lib.go @@ -87,6 +87,9 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e if input.Id != 0 { tx = tx.Where("\"Id\" = ?", input.Id) } + if input.Encounter_Id != nil { + tx = tx.Where("\"Encounter_Id\" = ?", *input.Encounter_Id) + } if err := tx.First(&data).Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/middleware-runner.go b/internal/use-case/bpjs-use-case/vclaim-sep/middleware-runner.go index dee35276..8e8522a6 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/middleware-runner.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/middleware-runner.go @@ -83,7 +83,7 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.VclaimSep) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto, data *e.VclaimSep) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go b/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go index 1ad0a853..08caba00 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/middleware.go @@ -9,5 +9,10 @@ func init() { createPreMw = append(createPreMw, createMw{Name: "create-sep", Func: pvs.CreateSep}, ) - + readDetailPostMw = append(readDetailPostMw, + readDetailMw{Name: "read-detail-sep", Func: pvs.ReadDetailSep}, + ) + deletePreMw = append(deletePreMw, + deleteMw{Name: "delete-sep", Func: pvs.DeleteSep}, + ) } diff --git a/internal/use-case/bpjs-use-case/vclaim-sep/tycovar.go b/internal/use-case/bpjs-use-case/vclaim-sep/tycovar.go index 932bc355..be3b5d11 100644 --- a/internal/use-case/bpjs-use-case/vclaim-sep/tycovar.go +++ b/internal/use-case/bpjs-use-case/vclaim-sep/tycovar.go @@ -29,8 +29,12 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.VclaimSep, tx *gorm.DB) error } +type deleteMw struct { + Name string + Func func(input *e.DeleteDto, data *e.VclaimSep, tx *gorm.DB) error +} + type UpdateMw = readDetailMw -type DeleteMw = readDetailMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware @@ -40,5 +44,5 @@ var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw var updatePreMw []readDetailMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw -var deletePostMw []readDetailMw +var deletePreMw []deleteMw +var deletePostMw []deleteMw diff --git a/internal/use-case/main-sync-use-case/.keep b/internal/use-case/main-sync-use-case/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/internal/use-case/main-use-case/antibiotic-in-use/case.go b/internal/use-case/main-use-case/antibiotic-in-use/case.go new file mode 100644 index 00000000..20d95639 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-in-use/case.go @@ -0,0 +1,389 @@ +package antibioticinuse + +import ( + "errors" + "strconv" + + e "simrs-vx/internal/domain/main-entities/antibiotic-in-use" + + ue "simrs-vx/internal/use-case/main-use-case/encounter" + umo "simrs-vx/internal/use-case/main-use-case/mcu-order" + + 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 = "antibiotic-in-use" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.AntibioticInUse{} + + 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 + } + + // check if encounter is done + if ue.IsDone(*input.McuOrder_Id, &event, tx) { + return errors.New("encounter is already done") + } + + // check if mcu-order is completed + if umo.IsCompleted(*input.McuOrder_Id, &event, tx) { + return errors.New("mcu-order is already completed") + } + + // if !input.AuthInfo.IsDoctor() { + // event.Status = "failed" + // event.ErrInfo = pl.ErrorInfo{ + // Code: "auth-forbidden", + // Detail: "user position is not allowed", + // Raw: errors.New("authentication failed"), + // } + // return pl.SetLogError(&event, input) + // } + + // doctor_id, err := ud.GetIdByUserId(&input.AuthInfo.User_Id, &event, tx) + // if err != nil { + // return err + // } + + // verify the mcu-order belongs to the same doctor + // rdDto := e.ReadDetailDto{Id: *input.McuOrder_Id} + // if err := ValidateMcuOrderDoctor(rdDto, doctor_id, &event, tx); 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.AntibioticInUse + var dataList []e.AntibioticInUse + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.AntibioticInUse + 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.AntibioticInUse + 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 + } + + // if data.IsCompleted() { + // return errors.New("data already completed") + // } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + return err + } + + // if !input.AuthInfo.IsDoctor() { + // event.Status = "failed" + // event.ErrInfo = pl.ErrorInfo{ + // Code: "auth-forbidden", + // Detail: "user position is not allowed", + // Raw: errors.New("authentication failed"), + // } + // return pl.SetLogError(&event, input) + // } + + // doctor_id, err := ud.GetIdByUserId(&input.AuthInfo.User_Id, &event, tx) + // if err != nil { + // return err + // } + + // verify the mcu-order belongs to the same doctor + // if err := ValidateMcuOrderDoctor(e.ReadDetailDto{Id: *data.McuOrder_Id}, doctor_id, &event, tx); 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.AntibioticInUse + 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 + +} + +func SetSchedule(input e.SetScheduleDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.AntibioticInUse + var err error + + event := pl.Event{ + Feature: "SetSchedule", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "setSchedule") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + data, err = ReadDetailData(rdDto, &event, tx) + if err != nil { + return err + } + // if data.IsCompleted() { + // return errors.New("data already completed") + // } + + // data.ExaminationDate = input.ExaminationDate + // if err := tx.Save(&data).Error; err != nil { + // event.Status = "failed" + // event.ErrInfo = pl.ErrorInfo{ + // Code: "data-update-fail", + // Detail: "Database update failed", + // Raw: err, + // } + // return pl.SetLogError(&event, input) + // } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "setSchedule", + }, + Data: data.ToResponse(), + }, nil +} diff --git a/internal/use-case/main-use-case/antibiotic-in-use/helper.go b/internal/use-case/main-use-case/antibiotic-in-use/helper.go new file mode 100644 index 00000000..20741ce1 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-in-use/helper.go @@ -0,0 +1,56 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package antibioticinuse + +import ( + "errors" + + e "simrs-vx/internal/domain/main-entities/antibiotic-in-use" + emo "simrs-vx/internal/domain/main-entities/mcu-order" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.AntibioticInUse) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + // data.Status_Code = erc.DSCNew + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.McuOrder_Id = inputSrc.McuOrder_Id + data.AntibioticSrc_Id = inputSrc.AntibioticSrc_Id + // data.ExaminationDate = inputSrc.ExaminationDate +} + +func ValidateMcuOrderDoctor(input e.ReadDetailDto, doctorCode string, event *pl.Event, tx *gorm.DB) error { + pl.SetLogInfo(event, input, "started", "ValidateMcuOrderDoctor") + + var mcuOrder emo.McuOrder + if err := tx.First(&mcuOrder, input.Id).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return errors.New("mcu-order not found") + } + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Failed to get mcu-order", + Raw: err, + } + return pl.SetLogError(event, input) + } + + if mcuOrder.Doctor_Code == nil || *mcuOrder.Doctor_Code != doctorCode { + return errors.New("doctor is not authorized for this mcu-order") + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/antibiotic-in-use/lib.go b/internal/use-case/main-use-case/antibiotic-in-use/lib.go new file mode 100644 index 00000000..4a64ef2d --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-in-use/lib.go @@ -0,0 +1,140 @@ +package antibioticinuse + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-in-use" + + plh "simrs-vx/pkg/lib-helper" + 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.AntibioticInUse, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.AntibioticInUse{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.AntibioticInUse, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.AntibioticInUse{} + 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.AntibioticInUse{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + 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, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.AntibioticInUse, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.AntibioticInUse{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Scopes(gh.Preload(input.Includes)).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.AntibioticInUse, 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.AntibioticInUse, 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/antibiotic-in-use/middleware-runner.go b/internal/use-case/main-use-case/antibiotic-in-use/middleware-runner.go new file mode 100644 index 00000000..580a47ba --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-in-use/middleware-runner.go @@ -0,0 +1,103 @@ +package antibioticinuse + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-in-use" + 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.AntibioticInUse) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticInUse) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticInUse) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticInUse) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticInUse) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/antibiotic-in-use/middleware.go b/internal/use-case/main-use-case/antibiotic-in-use/middleware.go new file mode 100644 index 00000000..a232aec5 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-in-use/middleware.go @@ -0,0 +1,9 @@ +package antibioticinuse + +// 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/antibiotic-in-use/tycovar.go b/internal/use-case/main-use-case/antibiotic-in-use/tycovar.go new file mode 100644 index 00000000..81e502c0 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-in-use/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 antibioticinuse + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/antibiotic-in-use" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.AntibioticInUse, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.AntibioticInUse, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.AntibioticInUse, 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/antibiotic-src-category/case.go b/internal/use-case/main-use-case/antibiotic-src-category/case.go new file mode 100644 index 00000000..2eaceb0c --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-src-category/case.go @@ -0,0 +1,276 @@ +package antibioticsrccategory + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-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 = "antibiotic-src-category" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.AntibioticSrcCategory{} + + 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.AntibioticSrcCategory + var dataList []e.AntibioticSrcCategory + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.AntibioticSrcCategory + 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.AntibioticSrcCategory + 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.AntibioticSrcCategory + 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/antibiotic-src-category/helper.go b/internal/use-case/main-use-case/antibiotic-src-category/helper.go new file mode 100644 index 00000000..7bbe8d80 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-src-category/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package antibioticsrccategory + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-src-category" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.AntibioticSrcCategory) { + 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/antibiotic-src-category/lib.go b/internal/use-case/main-use-case/antibiotic-src-category/lib.go new file mode 100644 index 00000000..31f2eee1 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-src-category/lib.go @@ -0,0 +1,140 @@ +package antibioticsrccategory + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-src-category" + + plh "simrs-vx/pkg/lib-helper" + 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.AntibioticSrcCategory, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.AntibioticSrcCategory{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.AntibioticSrcCategory, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.AntibioticSrcCategory{} + 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.AntibioticSrcCategory{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.AntibioticSrcCategory, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.AntibioticSrcCategory{} + + 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.AntibioticSrcCategory, 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.AntibioticSrcCategory, 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/antibiotic-src-category/middleware-runner.go b/internal/use-case/main-use-case/antibiotic-src-category/middleware-runner.go new file mode 100644 index 00000000..6ab4e880 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-src-category/middleware-runner.go @@ -0,0 +1,103 @@ +package antibioticsrccategory + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-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.AntibioticSrcCategory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticSrcCategory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticSrcCategory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticSrcCategory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticSrcCategory) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/antibiotic-src-category/middleware.go b/internal/use-case/main-use-case/antibiotic-src-category/middleware.go new file mode 100644 index 00000000..55091880 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-src-category/middleware.go @@ -0,0 +1,9 @@ +package antibioticsrccategory + +// 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/antibiotic-src-category/tycovar.go b/internal/use-case/main-use-case/antibiotic-src-category/tycovar.go new file mode 100644 index 00000000..0980e65a --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-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 antibioticsrccategory + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/antibiotic-src-category" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.AntibioticSrcCategory, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.AntibioticSrcCategory, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.AntibioticSrcCategory, 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/antibiotic-src/case.go b/internal/use-case/main-use-case/antibiotic-src/case.go new file mode 100644 index 00000000..9b108f65 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-src/case.go @@ -0,0 +1,280 @@ +package antibioticsrc + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-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 = "antibiotic-src" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.AntibioticSrc{} + + 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 err := createItem(&input, &event, tx); 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.AntibioticSrc + var dataList []e.AntibioticSrc + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.AntibioticSrc + 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.AntibioticSrc + 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.AntibioticSrc + 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/antibiotic-src/helper.go b/internal/use-case/main-use-case/antibiotic-src/helper.go new file mode 100644 index 00000000..69dfb986 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-src/helper.go @@ -0,0 +1,30 @@ +package antibioticsrc + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-src" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +func setData(input any, data *e.AntibioticSrc) { + switch input.(type) { + case *e.CreateDto: + data.Code = input.(*e.CreateDto).Code + data.Name = input.(*e.CreateDto).Name + data.AntibioticSrcCategory_Code = input.(*e.CreateDto).AntibioticSrcCategory_Code + // data.Item_Id = input.(*e.CreateDto).Item_Id + case *e.UpdateDto: + data.Code = input.(*e.UpdateDto).Code + data.Name = input.(*e.UpdateDto).Name + data.AntibioticSrcCategory_Code = input.(*e.UpdateDto).AntibioticSrcCategory_Code + // data.Item_Id = input.(*e.UpdateDto).Item_Id + } +} + +func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { + // For antibiotic-src, we don't need to create items since Item_Id is commented out + // This function is kept for consistency with the pattern but does nothing + return nil +} diff --git a/internal/use-case/main-use-case/antibiotic-src/lib.go b/internal/use-case/main-use-case/antibiotic-src/lib.go new file mode 100644 index 00000000..c9ede312 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-src/lib.go @@ -0,0 +1,140 @@ +package antibioticsrc + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-src" + + plh "simrs-vx/pkg/lib-helper" + 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.AntibioticSrc, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.AntibioticSrc{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.AntibioticSrc, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.AntibioticSrc{} + 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.AntibioticSrc{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.AntibioticSrc, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.AntibioticSrc{} + + 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.AntibioticSrc, 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.AntibioticSrc, 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/antibiotic-src/middleware-runner.go b/internal/use-case/main-use-case/antibiotic-src/middleware-runner.go new file mode 100644 index 00000000..2a939f32 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-src/middleware-runner.go @@ -0,0 +1,111 @@ +package antibioticsrc + +import ( + e "simrs-vx/internal/domain/main-entities/antibiotic-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.AntibioticSrc) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticSrc) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticSrc) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticSrc) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.AntibioticSrc) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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 +} + +// 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/antibiotic-src/tycovar.go b/internal/use-case/main-use-case/antibiotic-src/tycovar.go new file mode 100644 index 00000000..94e36fd4 --- /dev/null +++ b/internal/use-case/main-use-case/antibiotic-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 antibioticsrc + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/antibiotic-src" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.AntibioticSrc, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.AntibioticSrc, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.AntibioticSrc, 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/ap-mcu-order/case.go b/internal/use-case/main-use-case/ap-mcu-order/case.go new file mode 100644 index 00000000..845b8eeb --- /dev/null +++ b/internal/use-case/main-use-case/ap-mcu-order/case.go @@ -0,0 +1,276 @@ +package apmcuorder + +import ( + e "simrs-vx/internal/domain/main-entities/ap-mcu-order" + "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.ApMcuOrder{} + + 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.ApMcuOrder + var dataList []e.ApMcuOrder + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ApMcuOrder + 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.ApMcuOrder + 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.ApMcuOrder + 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/ap-mcu-order/helper.go b/internal/use-case/main-use-case/ap-mcu-order/helper.go new file mode 100644 index 00000000..4b91b7aa --- /dev/null +++ b/internal/use-case/main-use-case/ap-mcu-order/helper.go @@ -0,0 +1,27 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package apmcuorder + +import ( + e "simrs-vx/internal/domain/main-entities/ap-mcu-order" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ApMcuOrder) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Substances = inputSrc.Substances + data.Fictations = inputSrc.Fictations + data.Localization = inputSrc.Localization + data.ClinicalDiagnoses = inputSrc.ClinicalDiagnoses + data.Stadium = inputSrc.Stadium + data.PastHistory = inputSrc.PastHistory + data.CurrentHistory = inputSrc.CurrentHistory +} diff --git a/internal/use-case/main-use-case/ap-mcu-order/lib.go b/internal/use-case/main-use-case/ap-mcu-order/lib.go new file mode 100644 index 00000000..8b6d8a74 --- /dev/null +++ b/internal/use-case/main-use-case/ap-mcu-order/lib.go @@ -0,0 +1,140 @@ +package apmcuorder + +import ( + e "simrs-vx/internal/domain/main-entities/ap-mcu-order" + + plh "simrs-vx/pkg/lib-helper" + 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.ApMcuOrder, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.ApMcuOrder{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ApMcuOrder, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ApMcuOrder{} + 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.ApMcuOrder{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.ApMcuOrder, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ApMcuOrder{} + + 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.ApMcuOrder, 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.ApMcuOrder, 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/ap-mcu-order/middleware-runner.go b/internal/use-case/main-use-case/ap-mcu-order/middleware-runner.go new file mode 100644 index 00000000..dc7f2495 --- /dev/null +++ b/internal/use-case/main-use-case/ap-mcu-order/middleware-runner.go @@ -0,0 +1,103 @@ +package apmcuorder + +import ( + e "simrs-vx/internal/domain/main-entities/ap-mcu-order" + 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.ApMcuOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ApMcuOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ApMcuOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ApMcuOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ApMcuOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/ap-mcu-order/middleware.go b/internal/use-case/main-use-case/ap-mcu-order/middleware.go new file mode 100644 index 00000000..38161afe --- /dev/null +++ b/internal/use-case/main-use-case/ap-mcu-order/middleware.go @@ -0,0 +1,9 @@ +package apmcuorder + +// 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/ap-mcu-order/tycovar.go b/internal/use-case/main-use-case/ap-mcu-order/tycovar.go new file mode 100644 index 00000000..7f301ff1 --- /dev/null +++ b/internal/use-case/main-use-case/ap-mcu-order/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 apmcuorder + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/ap-mcu-order" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ApMcuOrder, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ApMcuOrder, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ApMcuOrder, 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/authentication/case.go b/internal/use-case/main-use-case/authentication/case.go index 15f18ef8..04a88c9b 100644 --- a/internal/use-case/main-use-case/authentication/case.go +++ b/internal/use-case/main-use-case/authentication/case.go @@ -179,6 +179,10 @@ func VerifyToken(r *http.Request, tokenType TokenType) (data *jwt.Token, errCode return token, "", "" } +func GetAuthInfoByUserName(userName string) (data *pa.AuthInfo, err error) { + return getAuthByUserName(userName) +} + func ExtractToken(r *http.Request, tokenType TokenType) (data *pa.AuthInfo, err error) { token, errCode, errDetail := VerifyToken(r, tokenType) if errCode != "" { @@ -205,7 +209,7 @@ func ExtractToken(r *http.Request, tokenType TokenType) (data *pa.AuthInfo, err User_Name: fmt.Sprintf("%v", claims["user_name"]), } - data.User_ContractPosition_code = checkStrClaims(claims, "contractPosition_code") + data.User_ContractPosition_Code = checkStrClaims(claims, "contractPosition_code") data.Employee_Position_Code = checkStrPtrClaims(claims, "employee_position_code") data.Doctor_Code = checkStrPtrClaims(claims, "doctor_code") data.Nurse_Code = checkStrPtrClaims(claims, "nurse_code") diff --git a/internal/use-case/main-use-case/authentication/case.go.bu b/internal/use-case/main-use-case/authentication/case.go.bu new file mode 100644 index 00000000..1743407a --- /dev/null +++ b/internal/use-case/main-use-case/authentication/case.go.bu @@ -0,0 +1,463 @@ +package authentication + +import ( + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "github.com/golang-jwt/jwt" + "github.com/google/uuid" + a "github.com/karincake/apem" + dg "github.com/karincake/apem/db-gorm-pg" + ms "github.com/karincake/apem/ms-redis" + d "github.com/karincake/dodol" + l "github.com/karincake/lepet" + + pa "simrs-vx/internal/lib/auth" + pl "simrs-vx/pkg/logger" + p "simrs-vx/pkg/password" + +<<<<<<< HEAD + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/employee" + "simrs-vx/internal/domain/main-entities/intern" + em "simrs-vx/internal/domain/main-entities/midwife" + en "simrs-vx/internal/domain/main-entities/nurse" + ep "simrs-vx/internal/domain/main-entities/pharmacist" + eu "simrs-vx/internal/domain/main-entities/user" + +======= + eu "simrs-vx/internal/domain/main-entities/user" + euf "simrs-vx/internal/domain/main-entities/user-fes" +>>>>>>> fc7e74b (feat/sso-auth: wip) + erc "simrs-vx/internal/domain/references/common" +) + +const source = "authentication" + +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 eu.LoginDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Get User + user := &eu.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: pl.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: pl.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: pl.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: pl.GenMessage("auth-login-incorrect")}} + } else if user.Status_Code == erc.USCBlocked { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-blocked", Message: pl.GenMessage("auth-login-blocked")}} + } else if user.Status_Code == erc.USCNew { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-login-unverified", Message: pl.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 + + // Create Claim + atClaims := jwt.MapClaims{} + atClaims["user_id"] = user.Id + atClaims["user_name"] = user.Name + atClaims["user_contractPosition_code"] = user.ContractPosition_Code + atClaims["uuid"] = aUuid + atClaims["exp"] = atExpires + + // Create output + outputData := d.II{ + "user_id": strconv.Itoa(int(user.Id)), + "user_name": user.Name, + "user_contractPosition_code": user.ContractPosition_Code, + } + + // extra + // role := []string{} + // switch user.ContractPosition_Code { + // case erg.CSCEmp: + // // employee + // employee := ee.Employee{} + // dg.I.Where("\"User_Id\" = ?", user.Id).First(&employee) + // if employee.Id == 0 { + // return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noEmployee", Message: pl.GenMessage("auth-noEmployee")}} + // } + // atClaims["employee_id"] = employee.Id + // outputData["employee_id"] = employee.Id + // role = append(role, "emp-"+string(*employee.Position_Code)) + + // //if employee.Division_Code != nil { + // // atClaims["employee_division_code"] = employee.Division_Code + // // outputData["employee_division_code"] = employee.Division_Code + // //} + + // // employee position + // if employee.Id > 0 && employee.Position_Code != nil { + // atClaims["employee_position_code"] = *employee.Position_Code + // switch *employee.Position_Code { + // case erg.EPCDoc: + // doctor := ed.Doctor{} + // dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&doctor) + // if doctor.Id == 0 { + // return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noDoctor", Message: pl.GenMessage("auth-noDoctor")}} + // } + // atClaims["doctor_code"] = doctor.Code + // outputData["doctor_code"] = doctor.Code + +<<<<<<< HEAD + // specialist + if doctor.Specialist_Code != nil { + atClaims["specialist_code"] = doctor.Specialist_Code + outputData["specialist_code"] = doctor.Specialist_Code + } + if doctor.Subspecialist_Code != nil { + atClaims["subspecialist_code"] = doctor.Subspecialist_Code + outputData["subspecialist_code"] = doctor.Subspecialist_Code + } + case erg.EPCNur: + empData := en.Nurse{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&empData) + if empData.Id == 0 { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noNurse", Message: pl.GenMessage("auth-noNurse")}} + } + atClaims["nurse_code"] = empData.Code + outputData["nurse_code"] = empData.Code + case erg.EPCMwi: + empData := em.Midwife{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&empData) + if empData.Id == 0 { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noMidwife", Message: pl.GenMessage("auth-noMidwife")}} + } + atClaims["midwife_code"] = empData.Code + outputData["midwife_code"] = empData.Code + case erg.EPCPha: + empData := ep.Pharmacist{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&empData) + if empData.Id == 0 { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noPharmacist", Message: pl.GenMessage("auth-noPharmacist")}} + } + atClaims["pharmacist_code"] = empData.Code + outputData["pharmacist_code"] = empData.Code + } +======= + // // specialist + // if doctor.Specialist_Code != nil { + // atClaims["specialist_code"] = doctor.Specialist_Code + // outputData["specialist_code"] = doctor.Specialist_Code + // } + // if doctor.Subspecialist_Code != nil { + // atClaims["subspecialist_code"] = doctor.Subspecialist_Code + // outputData["subspecialist_code"] = doctor.Subspecialist_Code + // } + // case erg.EPCNur: + // empData := en.Nurse{} + // dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&empData) + // if empData.Id == 0 { + // return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noNurse", Message: pl.GenMessage("auth-noNurse")}} + // } + // atClaims["nurse_code"] = empData.Code + // outputData["nurse_code"] = empData.Code + // case erg.EPCMwi: + // empData := em.Midwife{} + // dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&empData) + // if empData.Id == 0 { + // return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-noMidwife", Message: pl.GenMessage("auth-noMidwife")}} + // } + // atClaims["midwife_code"] = empData.Code + // outputData["midwife_code"] = empData.Code + // } +>>>>>>> fc7e74b (feat/sso-auth: wip) + + // errorGetPosition := d.FieldErrors{"authentication": d.FieldError{Code: "auth-getData-failed", Message: pl.GenMessage("auth-getData-failed")}} + + // // division position + // divisionPositions, err := getDivisionPosition(employee.Id, &event) + // if err != nil { + // return nil, errorGetPosition + // } + + // // installation position + // installationPositions, err := getInstallationPosition(employee.Id, &event) + // if err != nil { + // return nil, errorGetPosition + // } + + // // unit position + // unitPositions, err := getUnitPosition(employee.Id, &event) + // if err != nil { + // return nil, errorGetPosition + // } + + // // specialist position + // specialistPositions, err := getSpecialistPosition(employee.Id, &event) + // if err != nil { + // return nil, errorGetPosition + // } + + // // subspecialist position + // subspecialistPositions, err := getSubspecialistPosition(employee.Id, &event) + // if err != nil { + // return nil, errorGetPosition + // } + + // role = append(role, divisionPositions...) + // role = append(role, installationPositions...) + // role = append(role, unitPositions...) + // role = append(role, specialistPositions...) + // role = append(role, subspecialistPositions...) + // // atClaims["division_positions"] = divsionPositions + // // outputData["division_positions"] = divsionPositions + // } + // case erg.CSCInt: + // intern := intern.Intern{} + // dg.I.Where("\"User_Id\" = ?", user.Id).First(&intern) + // role = append(role, "int-"+string(*intern.Position_Code)) + // case erg.CSCSys: + // role = append(role, "system") + // } + // atClaims["roles"] = role + // outputData["roles"] = role + if err := populateRoles(user, atClaims, outputData, event); err != nil { + return nil, err + } + + // Generate jwt + 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: pl.GenMessage("token-sign-err")}} + } + outputData["accessToken"] = ats + + // 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: outputData, + }, 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 *pa.AuthInfo, err error) { + token, errCode, errDetail := VerifyToken(r, tokenType) + if errCode != "" { + return nil, d.FieldError{Code: errCode, Message: pl.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: pl.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: pl.GenMessage("token-invalid", "uuid is not available")} + } + accessUuidRedis := ms.I.Get(accessUuid) + if accessUuidRedis.String() == "" { + return nil, d.FieldError{Code: "token-unidentified", Message: pl.GenMessage("token-unidentified")} + } + + data = &pa.AuthInfo{ + Uuid: accessUuid, + User_Id: uint(user_id), + User_Name: fmt.Sprintf("%v", claims["user_name"]), + } + + data.User_ContractPosition_code = checkStrClaims(claims, "contractPosition_code") + data.Employee_Position_Code = checkStrPtrClaims(claims, "employee_position_code") + data.Doctor_Code = checkStrPtrClaims(claims, "doctor_code") + data.Nurse_Code = checkStrPtrClaims(claims, "nurse_code") + data.Midwife_Code = checkStrPtrClaims(claims, "midwife_code") + data.Nutritionist_Code = checkStrPtrClaims(claims, "nutritionist_code") + data.Laborant_Code = checkStrPtrClaims(claims, "laborant_code") + data.Pharmachist_Code = checkStrPtrClaims(claims, "pharmachist_code") + data.Intern_Position_Code = checkStrPtrClaims(claims, "intern_position_code") + data.Employee_Id = checkUntPtrClaims(claims, "employee_id") + return + } + return nil, d.FieldError{Code: "token", Message: "token-invalid"} +} + +func GetConfig() { + a.ParseCfg(&authCfg) +} + +func GenTokenFes(input euf.LoginDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Get User Fes + userFes := &euf.UserFes{Name: input.Name, AuthPartner_Code: input.AuthPartner_Code} + if errCode := getAndCheck(userFes, userFes); errCode != "" { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: errCode, Message: pl.GenMessage(errCode)}} + } + if userFes.AuthPartner.SecretKey != input.AuthPartner_SecretKey { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: "auth-secretKey-invalid", Message: pl.GenMessage("auth-secretKey-invalid")}} + } + + user := &eu.User{Name: userFes.User_Name} + if errCode := getAndCheck(user, user); errCode != "" { + return nil, d.FieldErrors{"authentication": d.FieldError{Code: errCode, Message: pl.GenMessage(errCode)}} + } + + // 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 + + // Create Claim + atClaims := jwt.MapClaims{} + atClaims["user_id"] = user.Id + atClaims["user_name"] = user.Name + atClaims["user_contractPosition_code"] = user.ContractPosition_Code + atClaims["uuid"] = aUuid + atClaims["exp"] = atExpires + + // Create output + outputData := d.II{ + "user_id": strconv.Itoa(int(user.Id)), + "user_name": user.Name, + "user_contractPosition_code": user.ContractPosition_Code, + } + + // extra + if err := populateRoles(user, atClaims, outputData, event); err != nil { + return nil, err + } + + // Generate jwt + 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: pl.GenMessage("token-sign-err")}} + } + outputData["accessToken"] = ats + + // 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: outputData, + }, nil +} diff --git a/internal/use-case/main-use-case/authentication/helper.go b/internal/use-case/main-use-case/authentication/helper.go index c0a3bd0f..3a8154b6 100644 --- a/internal/use-case/main-use-case/authentication/helper.go +++ b/internal/use-case/main-use-case/authentication/helper.go @@ -2,6 +2,7 @@ package authentication import ( "fmt" + pa "simrs-vx/internal/lib/auth" "strconv" "time" @@ -10,10 +11,13 @@ import ( dg "github.com/karincake/apem/db-gorm-pg" ms "github.com/karincake/apem/ms-redis" d "github.com/karincake/dodol" + gh "github.com/karincake/getuk" l "github.com/karincake/lepet" pl "simrs-vx/pkg/logger" + erg "simrs-vx/internal/domain/references/organization" + edp "simrs-vx/internal/domain/main-entities/division-position" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/employee" @@ -22,11 +26,11 @@ import ( em "simrs-vx/internal/domain/main-entities/midwife" en "simrs-vx/internal/domain/main-entities/nurse" ep "simrs-vx/internal/domain/main-entities/pharmacist" + er "simrs-vx/internal/domain/main-entities/registrator" esp "simrs-vx/internal/domain/main-entities/specialist-position" essp "simrs-vx/internal/domain/main-entities/subspecialist-position" eup "simrs-vx/internal/domain/main-entities/unit-position" eu "simrs-vx/internal/domain/main-entities/user" - erg "simrs-vx/internal/domain/references/organization" udp "simrs-vx/internal/use-case/main-use-case/division-position" uip "simrs-vx/internal/use-case/main-use-case/installation-position" @@ -226,6 +230,10 @@ func populateRoles(user *eu.User, input eu.LoginDto, atClaims jwt.MapClaims, out outputData["doctor_code"] = doctor.Code // specialist + if doctor.Unit_Code != nil { + atClaims["unit_code"] = doctor.Unit_Code + outputData["unit_code"] = doctor.Unit_Code + } if doctor.Specialist_Code != nil { atClaims["specialist_code"] = doctor.Specialist_Code outputData["specialist_code"] = doctor.Specialist_Code @@ -258,6 +266,16 @@ func populateRoles(user *eu.User, input eu.LoginDto, atClaims jwt.MapClaims, out } atClaims["pharmacist_code"] = empData.Code outputData["pharmacist_code"] = empData.Code + case erg.EPCReg: + empData := er.Registrator{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&empData) + if empData.Id == 0 { + return d.FieldErrors{"authentication": d.FieldError{Code: "auth-noRegistrator", Message: pl.GenMessage("auth-noRegistrator")}} + } + atClaims["registrator_id"] = empData.Id + outputData["registrator_id"] = empData.Id + atClaims["installation_code"] = empData.Installation_Code + outputData["installation_code"] = empData.Installation_Code } errorGetPosition := d.FieldErrors{"authentication": d.FieldError{Code: "auth-getData-failed", Message: pl.GenMessage("auth-getData-failed")}} @@ -330,3 +348,71 @@ func populateRoles(user *eu.User, input eu.LoginDto, atClaims jwt.MapClaims, out return nil } + +func getAuthByUserName(username string) (auth *pa.AuthInfo, err error) { + // get employee + emp := ee.Employee{} + if err = dg.I. + Joins(`JOIN "User" u ON u."Id" = "Employee"."User_Id"`). + Where(`u."Name" = ?`, username). + Scopes(gh.Preload("User")). + First(&emp).Error; err != nil { + return nil, err + } + + auth = &pa.AuthInfo{ + User_Id: *emp.User_Id, + User_Name: emp.User.Name, + User_ContractPosition_Code: string(emp.User.ContractPosition_Code), + Employee_Position_Code: strPtr(string(*emp.Position_Code)), + Employee_Id: &emp.Id, + Sync: true, + } + + // set map table + tableMap := map[erg.EmployeePositionCode]string{ + erg.EPCDoc: "Doctor", + erg.EPCNur: "Nurse", + erg.EPCMwi: "Midwife", + erg.EPCNut: "Nutritionist", + erg.EPCLab: "Laborant", + erg.EPCPha: "Pharmachist", + } + + table := tableMap[*emp.Position_Code] + if table == "" { + return + } + + type CodeResult struct { + Code string + } + var result CodeResult + + err = dg.I.Table(table). + Select("Code"). + Where("\"Employee_Id\" = ?", emp.Id). + First(&result).Error + if err != nil { + return nil, err + } + + // set map for code + setterMap := map[erg.EmployeePositionCode]func(string){ + erg.EPCDoc: func(v string) { auth.Doctor_Code = &v }, + erg.EPCNur: func(v string) { auth.Nurse_Code = &v }, + erg.EPCMwi: func(v string) { auth.Midwife_Code = &v }, + erg.EPCNut: func(v string) { auth.Nutritionist_Code = &v }, + erg.EPCLab: func(v string) { auth.Laborant_Code = &v }, + erg.EPCPha: func(v string) { auth.Pharmachist_Code = &v }, + } + + setter := setterMap[*emp.Position_Code] + setter(result.Code) + + return +} + +func strPtr(s string) *string { + return &s +} diff --git a/internal/use-case/main-use-case/authentication/helper.go.bu b/internal/use-case/main-use-case/authentication/helper.go.bu new file mode 100644 index 00000000..b7ccc660 --- /dev/null +++ b/internal/use-case/main-use-case/authentication/helper.go.bu @@ -0,0 +1,323 @@ +package authentication + +import ( + "fmt" + "strconv" + "time" + + "github.com/golang-jwt/jwt" + "github.com/google/uuid" + dg "github.com/karincake/apem/db-gorm-pg" + ms "github.com/karincake/apem/ms-redis" + d "github.com/karincake/dodol" + l "github.com/karincake/lepet" + + pl "simrs-vx/pkg/logger" + + edp "simrs-vx/internal/domain/main-entities/division-position" + ed "simrs-vx/internal/domain/main-entities/doctor" + ee "simrs-vx/internal/domain/main-entities/employee" + eip "simrs-vx/internal/domain/main-entities/installation-position" + "simrs-vx/internal/domain/main-entities/intern" + em "simrs-vx/internal/domain/main-entities/midwife" + en "simrs-vx/internal/domain/main-entities/nurse" + esp "simrs-vx/internal/domain/main-entities/specialist-position" + essp "simrs-vx/internal/domain/main-entities/subspecialist-position" + eup "simrs-vx/internal/domain/main-entities/unit-position" + eu "simrs-vx/internal/domain/main-entities/user" + erg "simrs-vx/internal/domain/references/organization" + + udp "simrs-vx/internal/use-case/main-use-case/division-position" + uip "simrs-vx/internal/use-case/main-use-case/installation-position" + usp "simrs-vx/internal/use-case/main-use-case/specialist-position" + ussp "simrs-vx/internal/use-case/main-use-case/subspecialist-position" + uup "simrs-vx/internal/use-case/main-use-case/unit-position" +) + +// just return the error code +func getAndCheck(input, condition any, includes any) (eCode string) { + qry := dg.I.Where(condition) + + // WARNING THIS PRELOAD FAILS + if includes != nil { + if val := includes.(string); val != "" { + qry = qry.Preload(val) + } else if vals := includes.([]string); len(vals) > 0 { + for _, val := range vals { + qry = qry.Preload(val) + } + } + } + + result := qry.First(&input) + if result.Error != nil { + return "fetch-fail" + } else if result.RowsAffected == 0 { + return "auth-login-incorrect" + } + + return "" +} + +func getDivisionPosition(employee_id uint, event *pl.Event) ([]string, error) { + var result []string + + // get data division_position based on employee_id + data, _, err := udp.ReadListData(edp.ReadListDto{FilterDto: edp.FilterDto{Employee_Id: &employee_id}}, event) + if err != nil { + return nil, err + } + + if len(data) > 0 { + for _, dp := range data { + result = append(result, "div-"+*dp.Division_Code) + } + } + + return result, nil +} + +func getInstallationPosition(employeeId uint, event *pl.Event) ([]string, error) { + var result []string + + // get data unit_position based on employee_id + data, _, err := uip.ReadListData(eip.ReadListDto{ + FilterDto: eip.FilterDto{Employee_Id: &employeeId}, + Includes: "installation"}, event) + if err != nil { + return nil, err + } + + if len(data) > 0 { + for _, dp := range data { + result = append(result, "inst-"+*dp.Installation_Code+"-"+dp.Code) + } + } + + return result, nil +} + +func getUnitPosition(employeeId uint, event *pl.Event) ([]string, error) { + var result []string + + // get data unit_position based on employee_id + data, _, err := uup.ReadListData(eup.ReadListDto{FilterDto: eup.FilterDto{Employee_Id: &employeeId}}, event) + if err != nil { + return nil, err + } + + if len(data) > 0 { + for _, dp := range data { + result = append(result, "unit-"+*dp.Unit_Code+"-"+dp.Code) + } + } + + return result, nil +} + +func getSpecialistPosition(employeeId uint, event *pl.Event) ([]string, error) { + var result []string + + // get data unit_position based on employee_id + data, _, err := usp.ReadListData(esp.ReadListDto{FilterDto: esp.FilterDto{Employee_Id: &employeeId}}, event) + if err != nil { + return nil, err + } + + if len(data) > 0 { + for _, dp := range data { + result = append(result, "spec-"+*dp.Specialist_Code+"-"+dp.Code) + } + } + + return result, nil +} + +func getSubspecialistPosition(employeeId uint, event *pl.Event) ([]string, error) { + var result []string + + // get data unit_position based on employee_id + data, _, err := ussp.ReadListData(essp.ReadListDto{ + FilterDto: essp.FilterDto{Employee_Id: &employeeId}, + Includes: "subspecialist"}, event) + if err != nil { + return nil, err + } + + if len(data) > 0 { + for _, dp := range data { + result = append(result, "subspec-"+dp.Subspecialist.Code+"-"+dp.Code) + } + } + + return result, nil +} + +func checkStrClaims(claim map[string]interface{}, key string) string { + if v, exist := claim[key]; exist && v != nil { + return v.(string) + } + return "" +} + +func checkStrPtrClaims(claim map[string]interface{}, key string) *string { + if v, exist := claim[key]; exist && v != nil { + val := v.(string) + return &val + } + return nil +} + +func checkUntPtrClaims(claim map[string]interface{}, key string) *uint { + if v, exist := claim[key]; exist && v != nil { + val := uint(v.(float64)) + return &val + } + return nil +} + +func populateRoles(user *eu.User, input eu.LoginDto, atClaims jwt.MapClaims, outputData d.II, event pl.Event) error { + 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() + + atClaims["uuid"] = aUuid + atClaims["exp"] = atExpires + atClaims["user_id"] = user.Id + atClaims["user_name"] = user.Name + atClaims["user_contractPosition_code"] = user.ContractPosition_Code + + outputData["user_id"] = user.Id + outputData["user_name"] = user.Name + outputData["user_contractPosition_code"] = user.ContractPosition_Code + + roles := []string{} + switch user.ContractPosition_Code { + case erg.CSCEmp: + // employee + employee := ee.Employee{} + dg.I.Where("\"User_Id\" = ?", user.Id).First(&employee) + if employee.Id == 0 { + return d.FieldErrors{"authentication": d.FieldError{Code: "auth-noEmployee", Message: pl.GenMessage("auth-noEmployee")}} + } + atClaims["employee_id"] = employee.Id + outputData["employee_id"] = employee.Id + roles = append(roles, "emp-"+string(*employee.Position_Code)) + + // employee position + if employee.Id > 0 && employee.Position_Code != nil { + atClaims["employee_position_code"] = *employee.Position_Code + switch *employee.Position_Code { + case erg.EPCDoc: + doctor := ed.Doctor{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&doctor) + if doctor.Id == 0 { + return d.FieldErrors{"authentication": d.FieldError{Code: "auth-noDoctor", Message: pl.GenMessage("auth-noDoctor")}} + } + atClaims["doctor_code"] = doctor.Code + outputData["doctor_code"] = doctor.Code + + // specialist + if doctor.Specialist_Code != nil { + atClaims["specialist_code"] = doctor.Specialist_Code + outputData["specialist_code"] = doctor.Specialist_Code + } + if doctor.Subspecialist_Code != nil { + atClaims["subspecialist_code"] = doctor.Subspecialist_Code + outputData["subspecialist_code"] = doctor.Subspecialist_Code + } + case erg.EPCNur: + empData := en.Nurse{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&empData) + if empData.Id == 0 { + return d.FieldErrors{"authentication": d.FieldError{Code: "auth-noNurse", Message: pl.GenMessage("auth-noNurse")}} + } + atClaims["nurse_code"] = empData.Code + outputData["nurse_code"] = empData.Code + case erg.EPCMwi: + empData := em.Midwife{} + dg.I.Where("\"Employee_Id\" = ?", employee.Id).First(&empData) + if empData.Id == 0 { + return d.FieldErrors{"authentication": d.FieldError{Code: "auth-noMidwife", Message: pl.GenMessage("auth-noMidwife")}} + } + atClaims["midwife_code"] = empData.Code + outputData["midwife_code"] = empData.Code + } + + errorGetPosition := d.FieldErrors{"authentication": d.FieldError{Code: "auth-getData-failed", Message: pl.GenMessage("auth-getData-failed")}} + + // division position + divisionPositions, err := getDivisionPosition(employee.Id, &event) + if err != nil { + return errorGetPosition + } + + // installation position + installationPositions, err := getInstallationPosition(employee.Id, &event) + if err != nil { + return errorGetPosition + } + + // unit position + unitPositions, err := getUnitPosition(employee.Id, &event) + if err != nil { + return errorGetPosition + } + + // specialist position + specialistPositions, err := getSpecialistPosition(employee.Id, &event) + if err != nil { + return errorGetPosition + } + + // subspecialist position + subspecialistPositions, err := getSubspecialistPosition(employee.Id, &event) + if err != nil { + return errorGetPosition + } + + roles = append(roles, divisionPositions...) + roles = append(roles, installationPositions...) + roles = append(roles, unitPositions...) + roles = append(roles, specialistPositions...) + roles = append(roles, subspecialistPositions...) + // atClaims["division_positions"] = divsionPositions + // outputData["division_positions"] = divsionPositions + } + case erg.CSCInt: + intern := intern.Intern{} + dg.I.Where("\"User_Id\" = ?", user.Id).First(&intern) + roles = append(roles, "int-"+string(*intern.Position_Code)) + case erg.CSCSys: + roles = append(roles, "system") + } + atClaims["roles"] = roles + outputData["roles"] = roles + + // Generate jwt + atSecretKey := authCfg.AtSecretKey + at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims) + ats, err := at.SignedString([]byte(atSecretKey)) + if err != nil { + return d.FieldErrors{"user": d.FieldError{Code: "token-sign-err", Message: pl.GenMessage("token-sign-err")}} + } + outputData["accessToken"] = ats + + // Save to redis + exp, _ := atClaims["exp"].(int64) + now := time.Now() + atx := time.Unix(exp, 0) //converting Unix to UTC(to Time object) + err = ms.I.Set(atClaims["uuid"].(string), strconv.Itoa(int(user.Id)), atx.Sub(now)).Err() + if err != nil { + panic(fmt.Sprintf(l.I.Msg("redis-store-fail"), err.Error())) + } + + return nil +} diff --git a/internal/use-case/main-use-case/chemo-protocol/helper.go b/internal/use-case/main-use-case/chemo-protocol/helper.go index 885e6fbb..66a63dcc 100644 --- a/internal/use-case/main-use-case/chemo-protocol/helper.go +++ b/internal/use-case/main-use-case/chemo-protocol/helper.go @@ -17,12 +17,9 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ChemoProtocol) { inputSrc = &inputTemp.CreateDto } - data.Encounter_Id = inputSrc.Encounter_Id data.Patient_Weight = inputSrc.Patient_Weight data.Patient_Height = inputSrc.Patient_Height data.Diagnoses = inputSrc.Diagnoses - data.Duration = inputSrc.Duration - data.DurationUnit_Code = inputSrc.DurationUnit_Code data.StartDate = inputSrc.StartDate data.EndDate = inputSrc.EndDate } diff --git a/internal/use-case/main-use-case/device-order-item/helper.go b/internal/use-case/main-use-case/device-order-item/helper.go index 8c0be91f..6f3f7ce8 100644 --- a/internal/use-case/main-use-case/device-order-item/helper.go +++ b/internal/use-case/main-use-case/device-order-item/helper.go @@ -19,5 +19,5 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.DeviceOrderItem) { data.DeviceOrder_Id = inputSrc.DeviceOrder_Id data.Device_Code = inputSrc.Device_Code - data.Count = inputSrc.Count + data.Quantity = inputSrc.Quantity } diff --git a/internal/use-case/main-use-case/device-order-item/lib.go b/internal/use-case/main-use-case/device-order-item/lib.go index 70ccc5d7..84838096 100644 --- a/internal/use-case/main-use-case/device-order-item/lib.go +++ b/internal/use-case/main-use-case/device-order-item/lib.go @@ -52,8 +52,8 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.De Scopes(gh.Preload(input.Includes)). Scopes(gh.Filter(input.FilterDto)). Count(&count). - Scopes(gh.Paginate(input, &pagination)). - Order("\"CreatedAt\" DESC") + Scopes(gh.Sort(input.Sort)). + Scopes(gh.Paginate(input, &pagination)) if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { diff --git a/internal/use-case/main-use-case/division/case.go b/internal/use-case/main-use-case/division/case.go index c955aed7..8f2e8488 100644 --- a/internal/use-case/main-use-case/division/case.go +++ b/internal/use-case/main-use-case/division/case.go @@ -1,16 +1,19 @@ package division import ( - e "simrs-vx/internal/domain/main-entities/division" "strconv" dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" + "gorm.io/gorm" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" - "gorm.io/gorm" + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/division" + esync "simrs-vx/internal/domain/sync-entities/log" ) const source = "division" @@ -25,36 +28,32 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event) 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 + id := uint(data.Id) + input.Id = &id } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -80,7 +79,7 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { @@ -131,7 +130,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { @@ -177,6 +176,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -184,32 +184,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -233,6 +227,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -240,30 +235,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -274,3 +265,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/division/middleware-runner.go b/internal/use-case/main-use-case/division/middleware-runner.go index 915cce28..76e1c873 100644 --- a/internal/use-case/main-use-case/division/middleware-runner.go +++ b/internal/use-case/main-use-case/division/middleware-runner.go @@ -1,35 +1,64 @@ 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" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/division" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Division) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +// ExecuteCreateMiddleware executes createlog middleware +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +68,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Division) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +87,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Division) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +105,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Division) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +124,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Division) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/division/middleware.go b/internal/use-case/main-use-case/division/middleware.go index f066ffb8..159ae4a3 100644 --- a/internal/use-case/main-use-case/division/middleware.go +++ b/internal/use-case/main-use-case/division/middleware.go @@ -1,9 +1,20 @@ package division +import ( + plugin "simrs-vx/internal/use-case/simgos-sync-plugin/new/division" +) + // example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +func init() { + createPreMw = append(createPreMw, + createMw{Name: "sync-create-division", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-sync-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "sync-update-division", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "sync-delete-division", Func: plugin.Delete}) +} diff --git a/internal/use-case/main-use-case/division/tycovar.go b/internal/use-case/main-use-case/division/tycovar.go index c7733117..cef873ee 100644 --- a/internal/use-case/main-use-case/division/tycovar.go +++ b/internal/use-case/main-use-case/division/tycovar.go @@ -12,11 +12,27 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/division" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Division, tx *gorm.DB) error + Func func(input *e.CreateDto) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,16 +45,17 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/doctor/helper.go b/internal/use-case/main-use-case/doctor/helper.go index 344d1c0e..9ddc2027 100644 --- a/internal/use-case/main-use-case/doctor/helper.go +++ b/internal/use-case/main-use-case/doctor/helper.go @@ -22,6 +22,6 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Doctor) { data.IHS_Number = inputSrc.IHS_Number data.SIP_Number = inputSrc.SIP_Number data.Unit_Code = inputSrc.Unit_Code - data.Specialist_Code = inputSrc.Code - data.Subspecialist_Code = inputSrc.Code + data.Specialist_Code = inputSrc.Specialist_Code + data.Subspecialist_Code = inputSrc.Subspecialist_Code } diff --git a/internal/use-case/main-use-case/doctor/lib.go b/internal/use-case/main-use-case/doctor/lib.go index 12b62176..9efe2239 100644 --- a/internal/use-case/main-use-case/doctor/lib.go +++ b/internal/use-case/main-use-case/doctor/lib.go @@ -1,6 +1,7 @@ package doctor import ( + "fmt" e "simrs-vx/internal/domain/main-entities/doctor" plh "simrs-vx/pkg/lib-helper" @@ -87,7 +88,11 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e if input.Id != nil { tx = tx.Where("\"Id\" = ?", input.Id) } - if err := tx.First(&data).Error; err != nil { + if input.Code != nil { + tx = tx.Where("\"Code\" = ?", input.Code) + } + fmt.Println(input.Includes) + if err := tx.Scopes(gh.Preload(input.Includes)).First(&data).Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { return nil, processedErr } diff --git a/internal/use-case/main-use-case/edu-assessment/case.go b/internal/use-case/main-use-case/edu-assessment/case.go index 230f0679..525274ca 100644 --- a/internal/use-case/main-use-case/edu-assessment/case.go +++ b/internal/use-case/main-use-case/edu-assessment/case.go @@ -37,7 +37,7 @@ func Create(input e.CreateDto) (*d.Data, error) { } // validate encounter_id - _, err := ue.ReadDetail(ee.ReadDetailDto{Id: uint16(*input.Encounter_Id)}) + _, err := ue.ReadDetail(ee.ReadDetailDto{Id: *input.Encounter_Id}) if err != nil { return err } diff --git a/internal/use-case/main-use-case/encounter-document/case.go b/internal/use-case/main-use-case/encounter-document/case.go index 206b5e1d..979c6611 100644 --- a/internal/use-case/main-use-case/encounter-document/case.go +++ b/internal/use-case/main-use-case/encounter-document/case.go @@ -10,7 +10,7 @@ import ( d "github.com/karincake/dodol" "gorm.io/gorm" - eru "simrs-vx/internal/domain/references/upload" + ere "simrs-vx/internal/domain/references/encounter" e "simrs-vx/internal/domain/main-entities/encounter-document" ) @@ -244,14 +244,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { 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 := removeUploadedFile(string(eru.ETCEncounter), *data.FilePath, &event); err != nil { + if err := removeUploadedFile(string(ere.ETCEncounter), *data.FilePath, &event); err != nil { return err } @@ -259,12 +252,6 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - 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/encounter/case.go b/internal/use-case/main-use-case/encounter/case.go index 9381e639..62a7c992 100644 --- a/internal/use-case/main-use-case/encounter/case.go +++ b/internal/use-case/main-use-case/encounter/case.go @@ -3,7 +3,7 @@ package encounter import ( "errors" "fmt" - us "simrs-vx/internal/use-case/main-use-case/soapi" + "simrs-vx/internal/lib/auth" "strconv" "time" @@ -16,20 +16,19 @@ import ( erc "simrs-vx/internal/domain/references/common" ere "simrs-vx/internal/domain/references/encounter" + erg "simrs-vx/internal/domain/references/organization" - eaeh "simrs-vx/internal/domain/main-entities/adm-employee-hist" + ev "simrs-vx/internal/domain/bpjs-entities/vclaim-reference" edc "simrs-vx/internal/domain/main-entities/death-cause" - eem "simrs-vx/internal/domain/main-entities/employee" e "simrs-vx/internal/domain/main-entities/encounter" eir "simrs-vx/internal/domain/main-entities/internal-reference" - erdh "simrs-vx/internal/domain/main-entities/responsible-doctor-hist" es "simrs-vx/internal/domain/main-entities/soapi" + esync "simrs-vx/internal/domain/sync-entities/log" - uaeh "simrs-vx/internal/use-case/main-use-case/adm-employee-hist" + uv "simrs-vx/internal/use-case/bpjs-use-case/vclaim-reference" udc "simrs-vx/internal/use-case/main-use-case/death-cause" - uem "simrs-vx/internal/use-case/main-use-case/employee" uir "simrs-vx/internal/use-case/main-use-case/internal-reference" - urdh "simrs-vx/internal/use-case/main-use-case/responsible-doctor-hist" + us "simrs-vx/internal/use-case/main-use-case/soapi" ) const source = "encounter" @@ -51,16 +50,28 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") - // validate rehab bpjs - if input.RefTypeCode == ere.RTCBpjs && input.Class_Code == ere.ECAmbulatory && ere.AmbulatoryClassCode(*input.SubClass_Code) == ere.ACCRehab { + roleAllowed := []string{string(erg.EPCReg)} + err = validateAuth(input.AuthInfo, roleAllowed, "create-encounter", &event) + if err != nil { + return nil, err + } + + // validate rehab by bpjs + if input.RefTypeCode == ere.RTCBpjs && + input.Class_Code == ere.ECAmbulatory && + ere.AmbulatoryClassCode(*input.SubClass_Code) == ere.ACCRehab { // get latest rehab data recentRehabData, err := getLatestRehabData(input, &event) if err != nil { return nil, err } + // If recentRehabData is nil, then visitMode_Code = "adm" if recentRehabData != nil { - // determine VisitModeCode + // If recentRehabData is not nil, determine the visitMode_Code: + // If the mode is "series", verify whether the visit count still remains + // and whether the series has not expired. + // If visitMode is "series", then get encounterAdm input.VisitMode_Code, input.RecentEncounterAdm, err = determineVisitMode(recentRehabData, input, &event) if err != nil { return nil, err @@ -69,7 +80,7 @@ func Create(input e.CreateDto) (*d.Data, error) { input.VisitMode_Code = ere.VMCAdm } - // if visitMode_Code is series, then get data soapi for copy + // When visitMode_Code is "series", load the associated SOAPI record to copy its values. if input.VisitMode_Code == ere.VMCSeries { // get data soapi recentSoapiDataforCopy, err = getSoapiEncounterAdm(*input.RecentEncounterAdm, &event) @@ -81,21 +92,11 @@ func Create(input e.CreateDto) (*d.Data, error) { // check if patient is new in the hospital input.NewStatus, err = identifyPatientStatus(input) + input.Adm_Employee_Id = input.AuthInfo.Employee_Id + + mwRunner := newMiddlewareRunner(&event, input.Sync) 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 emp, err := uem.ReadDetailData(eem.ReadDetailDto{User_Id: &input.AuthInfo.User_Id}, &event, tx); err != nil { - return err - } else { - input.Adm_Employee_Id = &emp.Id - } - // create encounter if resData, err := CreateData(input, &event, tx); err != nil { return err @@ -110,29 +111,43 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } - // insert adm_employee_hist - if _, err := uaeh.CreateData(eaeh.CreateDto{ - Encounter_Id: &data.Id, - Employee_Id: data.Adm_Employee_Id, - StartedAt: &now}, &event, tx); err != nil { + // insert vclaimReference + if vr := input.VclaimReference; vr != nil { + t, _ := time.Parse("2006-01-02", vr.TglRujukan) + _, err = uv.CreateData(ev.CreateDto{ + Encounter_Id: &data.Id, + Date: &t, + SrcCode: input.Ref_Number, + SrcName: input.RefSource_Name, + Number: &vr.NoSep}, &event, tx) + } + + dataEncounter, err := ReadDetailData(e.ReadDetailDto{ + Id: data.Id, + Includes: "Adm_Employee.User,Adm_Employee.Person," + + "Patient.Person.Relatives," + + "Patient.Person.VclaimMember,VclaimReference," + + "Patient.Person.Contacts,Patient.Person.Addresses"}, + &event, tx) + if err != nil { return err } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, dataEncounter); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -144,7 +159,6 @@ func Create(input e.CreateDto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Encounter var dataList []e.Encounter var metaList *e.MetaDto var err error @@ -158,23 +172,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -209,23 +209,9 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -244,7 +230,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { } func Update(input e.UpdateDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + rdDto := e.ReadDetailDto{Id: input.Id} var data *e.Encounter var err error @@ -256,6 +242,15 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + roleAllowed := []string{string(erg.EPCReg)} + err = validateAuth(input.AuthInfo, roleAllowed, "update-encounter", &event) + if err != nil { + return nil, err + } + input.Adm_Employee_Id = input.AuthInfo.Employee_Id + + mwRunner := newMiddlewareRunner(&event, input.Sync) + err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") if data, err = ReadDetailData(rdDto, &event, tx); err != nil { @@ -272,32 +267,33 @@ func Update(input e.UpdateDto) (*d.Data, error) { return pl.SetLogError(&event, input) } - 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") + dataEncounter, err := ReadDetailData(e.ReadDetailDto{ + Id: data.Id, + Includes: "Adm_Employee.User,Patient.Person.Relatives,Patient.Person.VclaimMember"}, + &event, tx) + if err != nil { + return err + } - mwRunner.setMwType(pu.MWTPost) + mwRunner.setMwType(pu.MWTPre) // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + if err := mwRunner.RunUpdateMiddleware(updatePreMw, dataEncounter); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -310,7 +306,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { } func Delete(input e.DeleteDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id)} + rdDto := e.ReadDetailDto{Id: input.Id} var data *e.Encounter var err error @@ -322,36 +318,66 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + roleAllowed := []string{string(erg.EPCReg)} + err = validateAuth(input.AuthInfo, roleAllowed, "delete-encounter", &event) + if err != nil { + return nil, err + } + + mwRunner := newMiddlewareRunner(&event, input.Sync) + 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 { + if data.IsDone() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "encounter is done", + Raw: errors.New("encounter is done"), + } + return pl.SetLogError(&event, input) + } + + // Prevent delete if soapi exist + dataSoapi, _, err := us.ReadListData(es.ReadListDto{ + FilterDto: es.FilterDto{Encounter_Id: &data.Id}}, &event, tx) + if err != nil { return err } + if len(dataSoapi) > 0 { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "cancel-not-allowed", + Detail: "encounter can't be deleted because SOAPI already exists", + Raw: errors.New("encounter has SOAPI records"), + } + return pl.SetLogError(&event, input) + } + if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -364,7 +390,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { } func CheckOut(input e.DischargeDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Ambulatory,Rehab"} + rdDto := e.ReadDetailDto{Id: input.Id, Includes: "Ambulatory,Rehab,InternalReferences"} var data *e.Encounter var err error @@ -376,6 +402,14 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "checkOut") + roleAllowed := []string{string(erg.EPCNur)} + err = validateAuth(input.AuthInfo, roleAllowed, "checkOut-encounter", &event) + if err != nil { + return nil, err + } + + mwRunner := newMiddlewareRunner(&event, input.Sync) + err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") if data, err = ReadDetailData(rdDto, &event, tx); err != nil { @@ -393,24 +427,25 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) { } if data.Ambulatory != nil && (data.Ambulatory.Class_Code == ere.ACCReg || data.Ambulatory.Class_Code == ere.ACCRehab) { - // validate if soapi exist + // Validate SOAPI completeness: abort checkout if any required SOAPI is missing. if err = getSoapiByTypeCode(data, &event, "check-out"); err != nil { return err } if data.Ambulatory.Class_Code == ere.ACCRehab { - // verify and update rehabData if visit count has reached the allowed limit + // verify and update rehabData to DONE if visit count has reached the allowed limit if err = verifyRehabLimit(data, &event, tx); err != nil { return err } } } else { - // chemo TBC + // TODO: chemo TBC (to be confirm) if err := checkSoapiByDocExists(data.Id, &event, tx); err != nil { return err } } + // update encounter if err := updateDischargeData(input, data, &event, tx); err != nil { return err } @@ -425,16 +460,6 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) { } } - // update finishedAt in latest responsible_doctor_hist - if err = updateLatestResponsibleDoctorHist(e.CheckinDto{Id: input.Id, FinishedAt: &now}, &event, tx); err != nil { - return err - } - - // update finishedAt in latest adm_employee_hist - if err = updateLatestAdmEmployeeHist(e.CheckinDto{Id: input.Id, FinishedAt: &now}, &event, tx); err != nil { - return err - } - // insert data death-cause if *input.Discharge_Method_Code == ere.DMCDeath { if _, err = udc.CreateData(edc.CreateDto{Encounter_Id: &input.Id, Value: input.DeathCause}, &event, tx); err != nil { @@ -442,15 +467,42 @@ func CheckOut(input e.DischargeDto) (*d.Data, error) { } } - pl.SetLogInfo(&event, nil, "complete") + // perform additional validation when discharge_method_code is "consul-poly" or "consul-executive" + if *data.Discharge_Method_Code == ere.DMCConsulPoly || *data.Discharge_Method_Code == ere.DMCConsulExecutive { + for _, v := range *data.InternalReferences { + if *v.Status_Code == erc.DACNew { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "checkout is not allowed because the internal-reference status is 'new'", + Raw: errors.New("internal-referral status not done yet"), + } + return pl.SetLogError(&event, input) + } + } + } + + // read the newest data encounter for sync + dataEncounter, err := ReadDetailData(e.ReadDetailDto{Id: data.Id, Includes: "DeathCause"}, &event, tx) + if err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCheckoutMiddleware(checkoutEncounter, dataEncounter); err != nil { + return err + } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -474,6 +526,14 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + roleAllowed := []string{string(erg.EPCReg), string(erg.EPCNur), string(erg.EPCDoc)} + err = validateAuth(input.AuthInfo, roleAllowed, "update-status-encounter", &event) + if err != nil { + return nil, err + } + + mwRunner := newMiddlewareRunner(&event, input.Sync) + err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") if data, err = ReadDetailData(rdDto, &event, tx); err != nil { @@ -493,14 +553,9 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) { if input.StatusCode == erc.DSCCancel { // TODO: Prevent cancellation if the billing has been verified - // TODO: Only "supervisi pendaftaran" could cancel encounter - // Prevent cancellation if soapi exist - encounterId := uint(input.Id) dataSoapi, _, err := us.ReadListData(es.ReadListDto{ - FilterDto: es.FilterDto{ - Encounter_Id: &encounterId, - }}, &event, tx) + FilterDto: es.FilterDto{Encounter_Id: &data.Id}}, &event, tx) if err != nil { return err } @@ -516,32 +571,34 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) { } } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { + if err := UpdateStatusData(input, &event, tx); err != nil { return err } - if err := UpdateStatusData(input, data, &event, tx); err != nil { + // get data encounter + if data, err = ReadDetailData(e.ReadDetailDto{ + Id: input.Id, + Includes: "Adm_Employee.User"}, &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 + if input.StatusCode == erc.DSCProcess || input.StatusCode == erc.DSCCancel { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateStatusMiddleware(updatestatusEncounter, data); err != nil { + return err + } } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -554,7 +611,7 @@ func UpdateStatusCode(input e.UpdateStatusDto) (*d.Data, error) { } func CheckIn(input e.CheckinDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Rehab,Ambulatory"} + rdDto := e.ReadDetailDto{Id: input.Id, Includes: "Rehab,Ambulatory"} var data *e.Encounter var err error @@ -566,8 +623,15 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "checkIn") + roleAllowed := []string{string(erg.EPCNur), string(erg.EPCDoc)} + err = validateAuth(input.AuthInfo, roleAllowed, "checkIn-encounter", &event) + if err != nil { + return nil, err + } + input.Responsible_Nurse_Code = input.AuthInfo.Nurse_Code + // validate foreign key - if err := validateForeignKey(input); err != nil { + if err := validateForeignKey(input, &event); err != nil { return nil, err } @@ -576,6 +640,8 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { input.StartedAt = &now } + mwRunner := newMiddlewareRunner(&event, input.Sync) + err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") if data, err = ReadDetailData(rdDto, &event, tx); err != nil { @@ -592,7 +658,7 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { return pl.SetLogError(&event, input) } - // validate if soapi exist + // prevent repeated check-in. If SOAPI already exists, block the check-in process. if data.Ambulatory != nil && (data.Ambulatory.Class_Code == ere.ACCReg || data.Ambulatory.Class_Code == ere.ACCRehab) { err = getSoapiByTypeCode(data, &event, "check-in") if err != nil { @@ -600,44 +666,32 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { } } - // Upsert responsible_doctor_hist if responsible_doctor_code has changed - if data.Responsible_Doctor_Code == nil || *input.Responsible_Doctor_Code != *data.Responsible_Doctor_Code { - // upsert responsibleDoctorHist - if err = upsertResponsibleDoctorHist(erdh.CreateDto{ - Encounter_Id: &data.Id, - Doctor_Code: input.Responsible_Doctor_Code, - StartedAt: input.StartedAt, - }, &event, tx); err != nil { - return err - } - } - - // Upsert adm_employee_hist if adm_employee_id has changed - if input.Adm_Employee_Id != nil && *input.Adm_Employee_Id != *data.Adm_Employee_Id { - // upsert admEmployeeHist - if err = upsertAdmEmployeeHist(eaeh.CreateDto{ - Encounter_Id: &data.Id, - Employee_Id: input.Adm_Employee_Id, - StartedAt: input.StartedAt, - }, &event, tx); err != nil { - return err - } - } - // update encounter data if err := updateCheckInData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") + // read the newest data encounter for sync + dataEncounter, err := ReadDetailData(e.ReadDetailDto{Id: data.Id, Includes: "Responsible_Nurse.Employee.User"}, &event, tx) + if err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCheckinMiddleware(checkinEncounterMw, dataEncounter); err != nil { + return err + } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -649,7 +703,7 @@ func CheckIn(input e.CheckinDto) (*d.Data, error) { } func RequestSwitchUnit(input e.SwitchUnitDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Responsible_Doctor"} + rdDto := e.ReadDetailDto{Id: input.Id, Includes: "Responsible_Nurse.Employee.User,Responsible_Doctor.Employee"} var data *e.Encounter var err error @@ -682,23 +736,33 @@ func RequestSwitchUnit(input e.SwitchUnitDto) (*d.Data, error) { return nil, err } + roleAllowed := []string{string(erg.EPCNur)} + err = validateAuth(input.AuthInfo, roleAllowed, "request-switch-poly", &event) + if err != nil { + return nil, err + } + input.Src_Nurse_Code = input.AuthInfo.Nurse_Code + + mwRunner := newMiddlewareRunner(&event, input.Sync) + 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 } + input.Src_Doctor_Code = data.Responsible_Doctor_Code - //if data.IsDone() { - // event.Status = "failed" - // event.ErrInfo = pl.ErrorInfo{ - // Code: "data-state-mismatch", - // Detail: "encounter is done", - // Raw: errors.New("encounter is done"), - // } - // return pl.SetLogError(&event, input) - //} + if data.IsDone() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "encounter is done", + Raw: errors.New("encounter is done"), + } + return pl.SetLogError(&event, input) + } - // verify Soapi exist for current responsible doctor + // Poly-Switch-Requests can only be processed if the previous responsible doctor has completed their SOAPI. dataSoapi, err := getSoapiByResponsibleDoctor(*data, &event) if err != nil { return err @@ -707,24 +771,41 @@ func RequestSwitchUnit(input e.SwitchUnitDto) (*d.Data, error) { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "missing-soapi", - Detail: fmt.Sprintf("Missing soapi from latest responsible doctor"), + Detail: "Missing soapi from latest responsible doctor", } return pl.SetLogError(&event, input) } - // bulk internal references - if err := uir.CreateBulkData(*input.InternalReferences, input.Id, &event, tx); err != nil { + // update encounter discharge_method_code + if err = UpdateDischargeMethod(input, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") + // bulk internal references + if err := uir.CreateBulkData(&input, &event, tx); err != nil { + return err + } + + // read the newest data encounter for sync + dataEncounter, err := ReadDetailData(e.ReadDetailDto{Id: data.Id, Includes: "InternalReferences,Responsible_Nurse.Employee.User"}, &event, tx) + if err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunRequestSwitchUnitMiddleware(requestSwitchEncounter, dataEncounter); err != nil { + return err + } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -735,10 +816,12 @@ func RequestSwitchUnit(input e.SwitchUnitDto) (*d.Data, error) { }, nil } -func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) { - rdDto := e.ReadDetailDto{Id: uint16(input.Id), Includes: "Responsible_Doctor"} - var data *e.Encounter - var err error +func ApproveSwitchUnit(input e.ApproveCancelUnitDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id, Includes: "Responsible_Doctor.Employee"} + var ( + data *e.Encounter + err error + ) event := pl.Event{ Feature: "ApproveSwitchUnit", @@ -748,13 +831,31 @@ func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "approveSwitchUnit") + roleAllowed := []string{string(erg.EPCNur)} + err = validateAuth(input.AuthInfo, roleAllowed, "request-switch-poly", &event) + if err != nil { + return nil, err + } + + mwRunner := newMiddlewareRunner(&event, input.Sync) + 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 } - // get internal reference + if data.IsDone() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "encounter is done", + Raw: errors.New("encounter is done"), + } + return pl.SetLogError(&event, input) + } + + // get internalReference based on internalReferences_Id irData, err := uir.ReadDetailData(eir.ReadDetailDto{ Id: input.InternalReferences_Id, Includes: "Doctor"}, &event, tx) if err != nil { @@ -771,17 +872,7 @@ func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) { return pl.SetLogError(&event, input) } - //if data.IsDone() { - // event.Status = "failed" - // event.ErrInfo = pl.ErrorInfo{ - // Code: "data-state-mismatch", - // Detail: "encounter is done", - // Raw: errors.New("encounter is done"), - // } - // return pl.SetLogError(&event, input) - //} - - // verify Soapi exist for current responsible doctor + // Approve-Switch-Requests can only be processed if the previous responsible doctor has completed their SOAPI. dataSoapi, err := getSoapiByResponsibleDoctor(*data, &event) if err != nil { return err @@ -790,56 +881,45 @@ func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "missing-soapi", - Detail: fmt.Sprintf("Missing soapi from latest responsible doctor"), + Detail: "Missing soapi from latest responsible doctor", } return pl.SetLogError(&event, input) } + // Set doctor_code; nil indicates no change. + if input.Dst_Doctor_Code == nil { + input.Dst_Doctor_Code = irData.Doctor_Code + } + // update internal reference if err = uir.UpdateData(eir.UpdateDto{ Id: input.InternalReferences_Id, CreateDto: eir.CreateDto{ - Encounter_Id: &input.Id, - Doctor_Code: irData.Doctor_Code, - Unit_Code: irData.Unit_Code, - Status_Code: erc.DACApproved, - }}, irData, &event, tx); err != nil { + Status_Code: erc.DACApproved, + Doctor_Code: input.Dst_Doctor_Code, + Nurse_Code: input.Nurse_Code}}, irData, &event, tx); err != nil { return err } // update encounter - if err = updateEncounterApproveSwitchUnit(*irData, &event, tx); err != nil { + if err = updateEncounterApproveSwitchUnit(input, &event, tx); err != nil { return err } - // update latest responsible doctor hist - if err = updateLatestResponsibleDoctorHist(e.CheckinDto{Id: input.Id, FinishedAt: &now}, &event, tx); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunApproveSwitchUnitMiddleware(approveSwitchEncounter, &input); err != nil { return err } - - // create responsible doctor based on internal reference data - if _, err = urdh.CreateData(erdh.CreateDto{ - Encounter_Id: &input.Id, - Doctor_Code: irData.Doctor_Code, - StartedAt: &now, - }, &event, tx); err != nil { - return err - } - - // update data response - data.Responsible_Doctor_Code = irData.Doctor_Code - data.Unit_Code = irData.Unit_Code // - data.Specialist_Code = irData.Doctor.Specialist_Code - data.Subspecialist_Code = irData.Doctor.Subspecialist_Code - - pl.SetLogInfo(&event, nil, "complete") return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -850,3 +930,148 @@ func ApproveSwitchUnit(input e.ApproveUnitDto) (*d.Data, error) { }, nil } + +func CancelSwitchUnit(input e.ApproveCancelUnitDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var ( + data *e.Encounter + err error + ) + + event := pl.Event{ + Feature: "CancelSwitchUnit", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "cancelSwitchUnit") + + roleAllowed := []string{string(erg.EPCNur)} + err = validateAuth(input.AuthInfo, roleAllowed, "request-switch-poly", &event) + if err != nil { + return nil, err + } + + mwRunner := newMiddlewareRunner(&event, input.Sync) + + 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.IsDone() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "encounter is done", + Raw: errors.New("encounter is done"), + } + return pl.SetLogError(&event, input) + } + + // get internalReference based on internalReferences_Id + irData, err := uir.ReadDetailData(eir.ReadDetailDto{ + Id: input.InternalReferences_Id}, &event, tx) + if err != nil { + return err + } + + if *irData.Status_Code != erc.DACNew { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "internal references is approve", + Raw: errors.New("internal references is approve"), + } + return pl.SetLogError(&event, input) + } + + // update internal reference + if err = uir.UpdateData(eir.UpdateDto{ + Id: input.InternalReferences_Id, + CreateDto: eir.CreateDto{ + Status_Code: erc.DACCanceled, + Nurse_Code: input.Nurse_Code}}, irData, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCancelSwitchUnitMiddleware(cancelSwitchEncounter, &input); err != nil { + return err + } + return nil + }) + + if err = runLogMiddleware(err, input, mwRunner); err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} + +func validateAuth(a auth.AuthInfo, roleAllowed []string, action string, event *pl.Event) error { + // check if user has employee position + if !a.HasEmployeePosition() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: "missing employee position", + Raw: errors.New("authentication failed"), + } + return pl.SetLogError(event, a) + } + + // check only roleAllowed position is allowed to create encounter + if a.Employee_Position_Code != nil && !pu.Contains(roleAllowed, *a.Employee_Position_Code) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: fmt.Sprintf("position '%s' is not allowed to %s", *a.Employee_Position_Code, action), + Raw: errors.New("authentication failed"), + } + return pl.SetLogError(event, a) + } + + return nil +} diff --git a/internal/use-case/main-use-case/encounter/helper.go b/internal/use-case/main-use-case/encounter/helper.go index 1de331b8..f606eb7c 100644 --- a/internal/use-case/main-use-case/encounter/helper.go +++ b/internal/use-case/main-use-case/encounter/helper.go @@ -7,6 +7,7 @@ package encounter import ( "errors" "fmt" + un "simrs-vx/internal/use-case/main-use-case/nurse" "strings" "time" @@ -29,7 +30,6 @@ import ( edo "simrs-vx/internal/domain/main-entities/device-order" ed "simrs-vx/internal/domain/main-entities/doctor" ee "simrs-vx/internal/domain/main-entities/emergency" - eem "simrs-vx/internal/domain/main-entities/employee" e "simrs-vx/internal/domain/main-entities/encounter" ei "simrs-vx/internal/domain/main-entities/inpatient" emo "simrs-vx/internal/domain/main-entities/material-order" @@ -38,6 +38,7 @@ import ( emei "simrs-vx/internal/domain/main-entities/medication-item" emi "simrs-vx/internal/domain/main-entities/medicine-mix" emmi "simrs-vx/internal/domain/main-entities/medicine-mix-item" + en "simrs-vx/internal/domain/main-entities/nurse" ep "simrs-vx/internal/domain/main-entities/prescription" epi "simrs-vx/internal/domain/main-entities/prescription-item" er "simrs-vx/internal/domain/main-entities/rehab" @@ -51,12 +52,12 @@ import ( uc "simrs-vx/internal/use-case/main-use-case/chemo" ud "simrs-vx/internal/use-case/main-use-case/doctor" ue "simrs-vx/internal/use-case/main-use-case/emergency" - uem "simrs-vx/internal/use-case/main-use-case/employee" ui "simrs-vx/internal/use-case/main-use-case/inpatient" um "simrs-vx/internal/use-case/main-use-case/medication" umei "simrs-vx/internal/use-case/main-use-case/medication-item" umi "simrs-vx/internal/use-case/main-use-case/medicine-mix" ummi "simrs-vx/internal/use-case/main-use-case/medicine-mix-item" + _ "simrs-vx/internal/use-case/main-use-case/nurse" up "simrs-vx/internal/use-case/main-use-case/prescription" upi "simrs-vx/internal/use-case/main-use-case/prescription-item" ur "simrs-vx/internal/use-case/main-use-case/rehab" @@ -64,44 +65,71 @@ import ( us "simrs-vx/internal/use-case/main-use-case/soapi" ) -func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Encounter) { - var inputSrc *e.CreateDto - if inputT, ok := any(input).(*e.CreateDto); ok { - inputSrc = inputT - } else { - inputTemp := any(input).(*e.UpdateDto) - inputSrc = &inputTemp.CreateDto - } - - data.Patient_Id = inputSrc.Patient_Id - data.RegisteredAt = inputSrc.RegisteredAt - data.Class_Code = inputSrc.Class_Code - data.Unit_Code = inputSrc.Unit_Code - data.Specialist_Code = inputSrc.Specialist_Code - data.Subspecialist_Code = inputSrc.Subspecialist_Code - data.VisitDate = inputSrc.VisitDate - data.PaymentMethod_Code = inputSrc.PaymentMethod_Code - data.InsuranceCompany_Code = inputSrc.InsuranceCompany_Code - data.Member_Number = inputSrc.Member_Number - data.Ref_Number = inputSrc.Ref_Number - data.Trx_Number = inputSrc.Trx_Number - data.Appointment_Doctor_Code = inputSrc.Appointment_Doctor_Code - data.Adm_Employee_Id = inputSrc.Adm_Employee_Id - data.Responsible_Doctor_Code = inputSrc.Responsible_Doctor_Code - data.RefSource_Name = inputSrc.RefSource_Name - data.Appointment_Id = inputSrc.Appointment_Id - data.Status_Code = erc.DSCProcess - data.RefType_Code = &inputSrc.RefTypeCode - data.NewStatus = inputSrc.NewStatus +func setDataCreate(input *e.CreateDto, data *e.Encounter) { + data.Patient_Id = input.Patient_Id + data.RegisteredAt = input.RegisteredAt + data.Class_Code = input.Class_Code + data.Unit_Code = input.Unit_Code + data.Specialist_Code = input.Specialist_Code + data.Subspecialist_Code = input.Subspecialist_Code + data.VisitDate = input.VisitDate + data.PaymentMethod_Code = input.PaymentMethod_Code + data.InsuranceCompany_Code = input.InsuranceCompany_Code + data.Member_Number = input.Member_Number + data.RefType_Code = &input.RefTypeCode + data.Ref_Number = input.Ref_Number + data.Trx_Number = input.Trx_Number + data.Appointment_Doctor_Code = input.Appointment_Doctor_Code + data.Adm_Employee_Id = input.Adm_Employee_Id + data.RefSource_Name = input.RefSource_Name + data.Appointment_Id = input.Appointment_Id + data.Status_Code = erc.DSCNew + data.NewStatus = input.NewStatus } func setDataUpdate(src e.UpdateDto, dst *e.Encounter) { - dst.Appointment_Doctor_Code = src.Appointment_Doctor_Code - dst.Responsible_Doctor_Code = src.Responsible_Doctor_Code dst.Unit_Code = src.Unit_Code dst.Specialist_Code = src.Specialist_Code dst.Subspecialist_Code = src.Subspecialist_Code dst.VisitDate = src.VisitDate + dst.Appointment_Doctor_Code = src.Appointment_Doctor_Code + dst.Adm_Employee_Id = src.Adm_Employee_Id + dst.Appointment_Id = src.Appointment_Id + dst.RefSource_Name = src.RefSource_Name + dst.Trx_Number = src.Trx_Number + dst.Ref_Number = src.Ref_Number + dst.Member_Number = src.Member_Number +} + +func setDataUpdateFromSource(input *e.UpdateDto, data *e.Encounter) { + data.Patient_Id = input.Patient_Id + data.RegisteredAt = input.RegisteredAt + data.Unit_Code = input.Unit_Code + data.Specialist_Code = input.Specialist_Code + data.Subspecialist_Code = input.Subspecialist_Code + data.VisitDate = input.VisitDate + data.StartedAt = input.StartedAt + data.FinishedAt = input.FinishedAt + data.PaymentMethod_Code = input.PaymentMethod_Code + data.InsuranceCompany_Code = input.InsuranceCompany_Code + data.Member_Number = input.Member_Number + data.RefType_Code = &input.RefTypeCode + data.Ref_Number = input.Ref_Number + data.Trx_Number = input.Trx_Number + data.Appointment_Doctor_Code = input.Appointment_Doctor_Code + data.Adm_Employee_Id = input.Adm_Employee_Id + data.Responsible_Doctor_Code = input.Responsible_Doctor_Code + data.Discharge_Method_Code = input.Discharge_Method_Code + data.RefSource_Name = input.RefSource_Name + data.Appointment_Id = input.Appointment_Id + data.EarlyEducation = input.EarlyEducation + data.MedicalDischargeEducation = input.MedicalDischargeEducation + data.AdmDischargeEducation = input.AdmDischargeEducation + data.DischargeReason = input.DischargeReason + data.Status_Code = input.Status_Code + data.Discharge_Date = input.Discharge_Date + data.NewStatus = input.NewStatus + data.Responsible_Nurse_Code = input.Responsible_Nurse_Code } func setDataDischarge(src e.DischargeDto, dst *e.Encounter) { @@ -117,17 +145,24 @@ func setDataDischarge(src e.DischargeDto, dst *e.Encounter) { dst.FinishedAt = &now } -func setDataUpdateStatus(src e.UpdateStatusDto, dst *e.Encounter) { - dst.Status_Code = src.StatusCode -} - func setDataCheckIn(src e.CheckinDto, dst *e.Encounter) { - if src.Adm_Employee_Id != nil { - dst.Adm_Employee_Id = src.Adm_Employee_Id - } - + dst.Responsible_Nurse_Code = src.Responsible_Nurse_Code dst.Responsible_Doctor_Code = src.Responsible_Doctor_Code dst.StartedAt = src.StartedAt + dst.Status_Code = erc.DSCProcess +} + +func setDischargeMethodCode(code ere.PolySwitchCode) *ere.DischargeMethodCode { + var dcm ere.DischargeMethodCode + + switch code { + case ere.PSCConsulPoly: + dcm = ere.DMCConsulPoly + case ere.PSCConsulExecutive: + dcm = ere.DMCConsulExecutive + } + + return &dcm } func checkSoapiByDocExists(encounter_id uint, event *pl.Event, tx *gorm.DB) error { @@ -556,6 +591,7 @@ func getSoapiByResponsibleDoctor(enc e.Encounter, event *pl.Event) (data []es.So Code: "no responsible-doctor found", Detail: "Encounter does not have responsible-doctor", } + return nil, pl.SetLogError(event, enc) } err = dg.I. @@ -601,7 +637,7 @@ func getSoapiEncounterAdm(enc e.Encounter, event *pl.Event) (dataSoapi []es.Crea event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "missing-soapi", - Detail: fmt.Sprintf("Missing required Soapi types"), + Detail: "Missing required Soapi types", } return nil, pl.SetLogError(event, enc) } @@ -617,7 +653,7 @@ func getSoapiByTypeCode(encounter *e.Encounter, event *pl.Event, mode string) (e rehab = encounter.Rehab ) - // Set Query for get data Soapi + // Set Query for get data Soapi by doc tx := dg.I. Model(&es.Soapi{}). Joins("JOIN \"Employee\" ON \"Employee\".\"Id\" = \"Soapi\".\"Employee_Id\""). @@ -904,17 +940,17 @@ func updateRehabStatus(input er.UpdateDto, event *pl.Event, dbx ...*gorm.DB) err return nil } -func validateForeignKey(input e.CheckinDto) error { +func validateForeignKey(input e.CheckinDto, event *pl.Event) error { // validate employee_Id - if input.Adm_Employee_Id != nil { - if _, err := uem.ReadDetail(eem.ReadDetailDto{Id: uint16(*input.Adm_Employee_Id)}); err != nil { + if input.Responsible_Nurse_Code != nil { + if _, err := un.ReadDetailData(en.ReadDetailDto{Code: input.Responsible_Nurse_Code}, event); err != nil { return err } } // validate doctor_Code if input.Responsible_Doctor_Code != nil { - if _, err := ud.ReadDetail(ed.ReadDetailDto{Code: input.Responsible_Doctor_Code}); err != nil { + if _, err := ud.ReadDetailData(ed.ReadDetailDto{Code: input.Responsible_Doctor_Code}, event); err != nil { return err } } diff --git a/internal/use-case/main-use-case/encounter/lib.go b/internal/use-case/main-use-case/encounter/lib.go index 5eac2db5..33f68af5 100644 --- a/internal/use-case/main-use-case/encounter/lib.go +++ b/internal/use-case/main-use-case/encounter/lib.go @@ -3,7 +3,6 @@ package encounter import ( // std "errors" - eir "simrs-vx/internal/domain/main-entities/internal-reference" // external dg "github.com/karincake/apem/db-gorm-pg" gh "github.com/karincake/getuk" @@ -26,7 +25,7 @@ func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Encount pl.SetLogInfo(event, nil, "started", "DBCreate") data := e.Encounter{} - setData(&input, &data) + setDataCreate(&input, &data) var tx *gorm.DB if len(dbx) > 0 { @@ -66,12 +65,43 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.En tx.Where("\"Responsible_Doctor_Code\" = ?", *input.AuthInfo.Doctor_Code) // } - tx.Scopes(gh.Preload(input.Includes)). - Scopes(gh.Filter(input.FilterDto)). + if input.StartDate != nil && input.EndDate != nil { + tx = tx.Where( + "DATE(\"Encounter\".\"RegisteredAt\") >= DATE(?) AND DATE(\"Encounter\".\"RegisteredAt\") <= DATE(?)", + input.StartDate, + input.EndDate, + ) + } + + if input.Patient_Identifier != nil { + tx = tx.Joins("JOIN \"Patient\" ON \"Patient\".\"Id\" = \"Encounter\".\"Patient_Id\""). + Joins("JOIN \"Person\" ON \"Person\".\"Id\" = \"Patient\".\"Person_Id\"").Where("\"Person\".\"Name\" ILIKE ? OR \"Patient\".\"Number\" = ?", "%"+*input.Patient_Identifier+"%", *input.Patient_Identifier) + } + + // TODO: getuk lib need to be updated to support this + if input.Status_Code != nil { + tx = tx.Where("\"Encounter\".\"Status_Code\" = ?", *input.Status_Code) + } + + if input.Unit_Code != nil { + tx = tx.Where("\"Encounter\".\"Unit_Code\" = ?", *input.Unit_Code) + } + + if input.PaymentMethod_Code != nil { + tx = tx.Where("\"Encounter\".\"PaymentMethod_Code\" = ?", *input.PaymentMethod_Code) + } + + tx = tx.Scopes(gh.Preload(input.Includes)). Count(&count). Scopes(gh.Paginate(input, &pagination)). Order("\"CreatedAt\" DESC") + // tx.Debug().Scopes(gh.Preload(input.Includes)). + // Scopes(gh.Filter(input.FilterDto)). + // 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 @@ -110,7 +140,12 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e func UpdateData(input e.UpdateDto, data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, data, "started", "DBUpdate") - setDataUpdate(input, data) + + if input.Sync { + setDataUpdateFromSource(&input, data) + } else { + setDataUpdate(input, data) + } var tx *gorm.DB if len(dbx) > 0 { @@ -205,9 +240,8 @@ func IsDone(encounter_id uint, event *pl.Event, dbx ...*gorm.DB) bool { return data.IsDone() } -func UpdateStatusData(input e.UpdateStatusDto, data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error { - pl.SetLogInfo(event, data, "started", "DBUpdate") - setDataUpdateStatus(input, data) +func UpdateStatusData(input e.UpdateStatusDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdateStatus") var tx *gorm.DB if len(dbx) > 0 { @@ -216,22 +250,52 @@ func UpdateStatusData(input e.UpdateStatusDto, data *e.Encounter, event *pl.Even tx = dg.I } - if err := tx.Save(&data).Error; err != nil { + if err := tx.Model(&e.Encounter{}). + Where("\"Id\" = ?", input.Id). + Updates(map[string]interface{}{ + "Status_Code": input.StatusCode, + "Adm_Employee_Id": input.Employee_Id, + }).Error; err != nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ - Code: "data-update-fail", - Detail: "Database update failed", + Code: "update-fail", + Detail: "Failed to update status code", + Raw: err, + } + return pl.SetLogError(event, input) + } + + return nil +} + +func UpdateDischargeMethod(input e.SwitchUnitDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdateDischargeMethod") + dischargeCode := setDischargeMethodCode(*input.PolySwitchCode) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Model(&e.Encounter{}). + Where("\"Id\" = ?", input.Id). + Update("Discharge_Method_Code", dischargeCode).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "update-fail", + Detail: "Failed to update discharge method code", Raw: err, } return pl.SetLogError(event, input) } - pl.SetLogInfo(event, nil, "complete") return nil } func updateCheckInData(input e.CheckinDto, data *e.Encounter, event *pl.Event, dbx ...*gorm.DB) error { - pl.SetLogInfo(event, data, "started", "DBUpdate") + pl.SetLogInfo(event, data, "started", "DBUpdateCheckin") setDataCheckIn(input, data) var tx *gorm.DB @@ -318,7 +382,7 @@ func verifyAllocatedVisitCount(i e.CreateDto, event *pl.Event) (e.Encounter, boo return recentEncounterAdm, valid, nil } -func updateEncounterApproveSwitchUnit(input eir.InternalReference, event *pl.Event, dbx ...*gorm.DB) (err error) { +func updateEncounterApproveSwitchUnit(input e.ApproveCancelUnitDto, event *pl.Event, dbx ...*gorm.DB) (err error) { pl.SetLogInfo(event, nil, "started", "DBCreate") var tx *gorm.DB @@ -329,12 +393,10 @@ func updateEncounterApproveSwitchUnit(input eir.InternalReference, event *pl.Eve } if err := tx.Model(&e.Encounter{}). - Where("\"Id\" = ?", input.Encounter_Id). + Where("\"Id\" = ?", input.Id). Updates(map[string]interface{}{ - "Responsible_Doctor_Code": input.Doctor_Code, - "Unit_Code": input.Unit_Code, - "Specialist_Code": input.Doctor.Specialist_Code, - "Subspecialist_Code": input.Doctor.Subspecialist_Code, + "Responsible_Doctor_Code": input.Dst_Doctor_Code, + "Responsible_Nurse_Code": input.Nurse_Code, }).Error; err != nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ diff --git a/internal/use-case/main-use-case/encounter/middleware-runner.go b/internal/use-case/main-use-case/encounter/middleware-runner.go index 1448a7af..da62fdb6 100644 --- a/internal/use-case/main-use-case/encounter/middleware-runner.go +++ b/internal/use-case/main-use-case/encounter/middleware-runner.go @@ -1,35 +1,67 @@ package encounter import ( - e "simrs-vx/internal/domain/main-entities/encounter" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/encounter" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event, syncFromOldSource bool) *middlewareRunner { + activateSync := sync.O.Enable + if syncFromOldSource { + activateSync = false + } + return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: activateSync, } } -// ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Encounter) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.Encounter) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +71,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Encounter) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +90,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Encounter) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +108,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Encounter) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.Encounter) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +127,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Encounter) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -98,6 +146,116 @@ func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, inpu return nil } +func (me *middlewareRunner) RunCheckinMiddleware(middleware checkinMw, input *e.Encounter) error { + if !me.SyncOn { + return nil + } + + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + + return nil +} + +func (me *middlewareRunner) RunCheckoutMiddleware(middleware checkoutMw, input *e.Encounter) error { + if !me.SyncOn { + return nil + } + + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + + return nil +} + +func (me *middlewareRunner) RunUpdateStatusMiddleware(middlewares []updateStatusMw, input *e.Encounter) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + } + + pl.SetLogInfo(me.Event, nil, "complete") + + return nil +} + +func (me *middlewareRunner) RunRequestSwitchUnitMiddleware(middleware requestSwitchUnitMw, input *e.Encounter) error { + if !me.SyncOn { + return nil + } + + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + + return nil +} + +func (me *middlewareRunner) RunApproveSwitchUnitMiddleware(middleware approveSwitchUnitMw, input *e.ApproveCancelUnitDto) error { + if !me.SyncOn { + return nil + } + + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + + return nil +} + +func (me *middlewareRunner) RunCancelSwitchUnitMiddleware(middleware cancelSwitchUnitMw, input *e.ApproveCancelUnitDto) error { + if !me.SyncOn { + return nil + } + + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != 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/encounter/middleware.go b/internal/use-case/main-use-case/encounter/middleware.go index 8a047d33..306e4bca 100644 --- a/internal/use-case/main-use-case/encounter/middleware.go +++ b/internal/use-case/main-use-case/encounter/middleware.go @@ -1,9 +1,29 @@ package encounter -// example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +import ( + plugin "simrs-vx/internal/use-case/simgos-sync-plugin/new/encounter" +) + +func init() { + createPreMw = append(createPreMw, + createMw{Name: "sync-update-encounter", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-sync-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "sync-update-encounter", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "sync-delete-encounter", Func: plugin.Delete}) + + checkinEncounterMw = checkinMw{Name: "sync-checkin-encounter", Func: plugin.Checkin} + checkoutEncounter = checkoutMw{Name: "sync-checkout-encounter", Func: plugin.Checkout} + + updatestatusEncounter = append(updatestatusEncounter, + updateStatusMw{Name: "sync-update-status-encounter", Func: plugin.UpdateStatus}) + + requestSwitchEncounter = requestSwitchUnitMw{Name: "sync-request-switch-unit-encounter", Func: plugin.RequestSwitchUnit} + approveSwitchEncounter = approveSwitchUnitMw{Name: "sync-approve-switch-unit-encounter", Func: plugin.ApproveSwitchUnit} + cancelSwitchEncounter = cancelSwitchUnitMw{Name: "sync-cancel-switch-unit-encounter", Func: plugin.CancelSwitchUnit} +} diff --git a/internal/use-case/main-use-case/encounter/tycovar.go b/internal/use-case/main-use-case/encounter/tycovar.go index 17890a1b..2b268378 100644 --- a/internal/use-case/main-use-case/encounter/tycovar.go +++ b/internal/use-case/main-use-case/encounter/tycovar.go @@ -12,13 +12,28 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/encounter" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Encounter, tx *gorm.DB) error + Func func(input *e.Encounter) error } +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.Encounter) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error +} type readListMw struct { Name string Func func(input *e.ReadListDto, data *e.Encounter, tx *gorm.DB) error @@ -29,16 +44,53 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Encounter, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type checkinMw struct { + Name string + Func func(input *e.Encounter) error +} -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +type checkoutMw struct { + Name string + Func func(input *e.Encounter) error +} + +type updateStatusMw struct { + Name string + Func func(input *e.Encounter) error +} + +type requestSwitchUnitMw struct { + Name string + Func func(input *e.Encounter) error +} + +type approveSwitchUnitMw struct { + Name string + Func func(input *e.ApproveCancelUnitDto) error +} + +type cancelSwitchUnitMw struct { + Name string + Func func(input *e.ApproveCancelUnitDto) error +} + +type UpdateMw = updateMw +type DeleteMw = deleteMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw +var checkinEncounterMw checkinMw +var checkoutEncounter checkoutMw +var updatestatusEncounter []updateStatusMw +var requestSwitchEncounter requestSwitchUnitMw +var approveSwitchEncounter approveSwitchUnitMw +var cancelSwitchEncounter cancelSwitchUnitMw diff --git a/internal/use-case/main-use-case/general-consent/case.go b/internal/use-case/main-use-case/general-consent/case.go new file mode 100644 index 00000000..e6dd2a61 --- /dev/null +++ b/internal/use-case/main-use-case/general-consent/case.go @@ -0,0 +1,295 @@ +package generalconsent + +import ( + "errors" + "strconv" + + // main entities + e "simrs-vx/internal/domain/main-entities/general-consent" + + ue "simrs-vx/internal/use-case/main-use-case/encounter" + + 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" +) + +const source = "general-consent" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.GeneralConsent{} + + 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 + } + + // check if encounter is done + if ue.IsDone(*input.Encounter_Id, &event, tx) { + return errors.New("encounter is already done") + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + 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.GeneralConsent + var dataList []e.GeneralConsent + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.GeneralConsent + 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.GeneralConsent + 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 + } + + // check if encounter is done + if ue.IsDone(*input.Encounter_Id, &event, tx) { + return errors.New("encounter is already done") + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + // Get Updated Data + if data, err = ReadDetailData(rdDto, &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: uint(input.Id)} + var data *e.GeneralConsent + 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/general-consent/helper.go b/internal/use-case/main-use-case/general-consent/helper.go new file mode 100644 index 00000000..015d4716 --- /dev/null +++ b/internal/use-case/main-use-case/general-consent/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package generalconsent + +import ( + e "simrs-vx/internal/domain/main-entities/general-consent" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.GeneralConsent) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Value = inputSrc.Value +} diff --git a/internal/use-case/main-use-case/general-consent/lib.go b/internal/use-case/main-use-case/general-consent/lib.go new file mode 100644 index 00000000..e365523d --- /dev/null +++ b/internal/use-case/main-use-case/general-consent/lib.go @@ -0,0 +1,140 @@ +package generalconsent + +import ( + "errors" + e "simrs-vx/internal/domain/main-entities/general-consent" + plh "simrs-vx/pkg/lib-helper" + 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.GeneralConsent, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.GeneralConsent{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.GeneralConsent, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.GeneralConsent{} + 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.GeneralConsent{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.GeneralConsent, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.GeneralConsent{} + + 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.GeneralConsent, 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.GeneralConsent, 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/general-consent/middleware-runner.go b/internal/use-case/main-use-case/general-consent/middleware-runner.go new file mode 100644 index 00000000..4dfc739a --- /dev/null +++ b/internal/use-case/main-use-case/general-consent/middleware-runner.go @@ -0,0 +1,103 @@ +package generalconsent + +import ( + e "simrs-vx/internal/domain/main-entities/general-consent" + 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.GeneralConsent) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.GeneralConsent) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.GeneralConsent) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.GeneralConsent) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.GeneralConsent) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/general-consent/middleware.go b/internal/use-case/main-use-case/general-consent/middleware.go new file mode 100644 index 00000000..69311dfc --- /dev/null +++ b/internal/use-case/main-use-case/general-consent/middleware.go @@ -0,0 +1,9 @@ +package generalconsent + +// 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/general-consent/tycovar.go b/internal/use-case/main-use-case/general-consent/tycovar.go new file mode 100644 index 00000000..b91396b9 --- /dev/null +++ b/internal/use-case/main-use-case/general-consent/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 generalconsent + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/general-consent" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.GeneralConsent, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.GeneralConsent, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.GeneralConsent, 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/generate-file/case.go b/internal/use-case/main-use-case/generate-file/case.go new file mode 100644 index 00000000..b5103746 --- /dev/null +++ b/internal/use-case/main-use-case/generate-file/case.go @@ -0,0 +1,79 @@ +package generatefile + +import ( + "errors" + + pl "simrs-vx/pkg/logger" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + "gorm.io/gorm" + + ere "simrs-vx/internal/domain/references/encounter" +) + +const source = "generate-file" + +func Generate(input GenerateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Generate", + Source: source, + } + + var ( + response *ResponseDto + err error + ) + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + switch input.Type_Code { + // general-consent + case ere.DTCGC: + response, err = generateGC(input, event, tx) + if err != nil { + return err + } + + // control-letter + case ere.DTCVSCL: + response, err = generateCL(input, event, tx) + if err != nil { + return err + } + + // resume + case ere.DTCResume: + response, err = generateResume(input, event, tx) + if err != nil { + return err + } + + // screening + case ere.DTCScreening: + response, err = generateScreening(input, event, tx) + if err != nil { + return err + } + default: + return errors.New("invalid type code") + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: response, + }, nil +} diff --git a/internal/use-case/main-use-case/generate-file/helper.go b/internal/use-case/main-use-case/generate-file/helper.go new file mode 100644 index 00000000..a0e7c1e2 --- /dev/null +++ b/internal/use-case/main-use-case/generate-file/helper.go @@ -0,0 +1,472 @@ +package generatefile + +import ( + "encoding/json" + "errors" + "fmt" + "mime" + "path/filepath" + "time" + + evs "simrs-vx/internal/domain/bpjs-entities/vclaim-sep" + evscl "simrs-vx/internal/domain/bpjs-entities/vclaim-sep-control-letter" + ee "simrs-vx/internal/domain/main-entities/encounter" + egc "simrs-vx/internal/domain/main-entities/general-consent" + er "simrs-vx/internal/domain/main-entities/resume" + es "simrs-vx/internal/domain/main-entities/screening" + + uvs "simrs-vx/internal/use-case/bpjs-use-case/vclaim-sep" + uvscl "simrs-vx/internal/use-case/bpjs-use-case/vclaim-sep-control-letter" + ue "simrs-vx/internal/use-case/main-use-case/encounter" + ugc "simrs-vx/internal/use-case/main-use-case/general-consent" + ur "simrs-vx/internal/use-case/main-use-case/resume" + us "simrs-vx/internal/use-case/main-use-case/screening" + + ercl "simrs-vx/internal/domain/references/clinical" + erc "simrs-vx/internal/domain/references/common" + docscfg "simrs-vx/internal/infra/docs-cfg" + + pc "simrs-vx/pkg/conv-helper" + pf "simrs-vx/pkg/file-helper" + pl "simrs-vx/pkg/logger" + pm "simrs-vx/pkg/minio-helper" + pp "simrs-vx/pkg/pdf-helper" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" +) + +// generate temporary file, upload to minio, generate public url, delete temporary file +func generateFile(input GenerateDto, templateData any) (string, error) { + newPath, err := pf.PathToSaveFile(fmt.Sprintf("./temporary/%s", input.EntityType_Code)) + if err != nil { + return "", err + } + + fPath := fmt.Sprintf("%s/%s-%s.%s", newPath, input.Type_Code, time.Now().Format("20060102150405"), input.FormatType) + + templatePath := docscfg.O.GetPath() + string(input.TemplateName) + + switch input.FormatType { + case erc.DFTCPDF: + if err := generatePDF(GeneratePDFdto{ + TemplatePath: templatePath, + TemplateData: templateData, + PdfPath: fPath, + UseA5Lanscape: input.UseA5Lanscape, + }); err != nil { + return "", err + } + case erc.DFTCTXLSX: + // TODO: generate xlsx + case erc.DFTCTCSV: + // TODO: generate csv + default: + return "", errors.New("invalid format type") + } + + bucketName := input.EntityType_Code + + objectName := fmt.Sprintf("%s/%s-%d.%s", *pc.UintToString(input.Encounter_Id), input.Type_Code, time.Now().UnixNano(), input.FormatType) + pdfUpload := pm.UploadPathInput{ + BucketName: string(bucketName), + Name: objectName, + Path: fPath, + ContentType: mime.TypeByExtension(filepath.Ext(fPath)), + } + + // create bucket if not exist, create object in bucket + info, err := pm.I.FPutObject(pdfUpload) + if err != nil { + return "", err + } + + // generate public url + urlPub := pm.I.GenerateUrl(info.Bucket, info.Key) + if err := pf.DeleteFolder(fPath); err != nil { + return "", err + } + + return urlPub, nil +} + +func generatePDF(input GeneratePDFdto) error { + // parse template data into html template + r := pp.NewRequestPdf("") + if err := r.ParseTemplate(input.TemplatePath, input.TemplateData); err == nil { + _, err := r.GenerateByCommand(input.PdfPath, input.TemplatePath, input.UseA5Lanscape) + if err != nil { + return errors.New("generate pdf by command error : " + err.Error()) + } + } else { + return errors.New("parse template error : " + err.Error()) + } + + return nil +} + +func removeFile(bucket, fileUrl string) error { + fPath := pu.GetLastTwoPathSegments(fileUrl) + err := pm.I.RemoveObject(bucket, fPath) + if err != nil { + return err + } + return nil +} + +// generate general consent +func generateGC(input GenerateDto, event pl.Event, tx *gorm.DB) (*ResponseDto, error) { + // get value from general consent by ref_id + gc, err := ugc.ReadDetailData(egc.ReadDetailDto{Id: uint(*pc.StringToUint64(*input.Ref_Id))}, &event) + if err != nil { + return nil, err + } + + if gc.FileUrl != nil { + if err := removeFile(string(input.EntityType_Code), *gc.FileUrl); err != nil { + return nil, err + } + } + + // map template data + templateData := GeneralConsentPDF{} + if gc.Value != nil { + err := json.Unmarshal([]byte(*gc.Value), &templateData) + if err != nil { + event.ErrInfo = pl.ErrorInfo{ + Code: "data-unmarshal-fail", + Detail: err.Error(), + Raw: err, + } + return nil, err + } + } else { + return nil, errors.New("no value in this general consent") + } + + input.FormatType = erc.DFTCPDF + input.TemplateName = TDNGC + input.Encounter_Id = gc.Encounter_Id + templateData.Date = pu.FormatIndonesianDate(gc.CreatedAt) + + // generate file + urlPub, err := generateFile(input, templateData) + if err != nil { + return nil, err + } + + gc.FileUrl = &urlPub + if err := tx.Save(&gc).Error; err != nil { + return nil, err + } + + response := ResponseDto{ + FileUrl: urlPub, + } + + return &response, nil +} + +func generateCL(input GenerateDto, event pl.Event, tx *gorm.DB) (*ResponseDto, error) { + // get value from control letter by ref_id + cl, err := uvscl.ReadDetailData(evscl.ReadDetailDto{Number: input.Ref_Id}, &event) + if err != nil { + if !pu.IsDataNotFoundError(err) { + return nil, err + } + } + + if cl != nil && cl.FileUrl != nil { + if err := removeFile(string(input.EntityType_Code), *cl.FileUrl); err != nil { + return nil, err + } + } + + // map template data + clData := VclaimControlLetter{} + if input.Data != nil { + err := json.Unmarshal([]byte(*input.Data), &clData) + if err != nil { + event.ErrInfo = pl.ErrorInfo{ + Code: "data-unmarshal-fail", + Detail: err.Error(), + Raw: err, + } + return nil, err + } + } else { + return nil, errors.New("there is no data to be used") + } + + if cl == nil { + createCL := evscl.CreateDto{ + VclaimSep_Number: &clData.VclaimSep.Number, + Number: &clData.Number, + Value: input.Data, + } + if cl, err = uvscl.CreateData(createCL, &event, tx); err != nil { + return nil, err + } + + } + // get encounter id by vclaim sep number + vs, err := uvs.ReadDetailData(evs.ReadDetailDto{Number: &clData.VclaimSep.Number}, &event) + if err != nil { + return nil, err + } + + input.FormatType = erc.DFTCPDF + input.TemplateName = TDNCL + input.Encounter_Id = vs.Encounter_Id + input.UseA5Lanscape = true + + templateData := clData.generateTemplateData() + // generate file + urlPub, err := generateFile(input, templateData) + if err != nil { + return nil, err + } + + cl.FileUrl = &urlPub + if err := tx.Save(&cl).Error; err != nil { + return nil, err + } + + response := ResponseDto{ + FileUrl: urlPub, + } + + return &response, nil +} + +func generateResume(input GenerateDto, event pl.Event, tx *gorm.DB) (*ResponseDto, error) { + // get value from resume by ref_id + includes := "Doctor.Employee.Person" + r, err := ur.ReadDetailData(er.ReadDetailDto{Id: uint(*pc.StringToUint64(*input.Ref_Id)), Includes: includes}, &event) + if err != nil { + return nil, err + } + + if !r.IsValidated() { + return nil, errors.New("resume is not validated") + } + + if r.FileUrl != nil { + if err := removeFile(string(input.EntityType_Code), *r.FileUrl); err != nil { + return nil, err + } + } + + templateData, err := generateResumeTemplateData(*r, event, tx) + if err != nil { + return nil, err + } + + input.FormatType = erc.DFTCPDF + input.TemplateName = TDNR + input.Encounter_Id = r.Encounter_Id + + // generate file + urlPub, err := generateFile(input, templateData) + if err != nil { + return nil, err + } + + r.FileUrl = &urlPub + if err := tx.Save(&r).Error; err != nil { + return nil, err + } + + response := ResponseDto{ + FileUrl: urlPub, + } + + return &response, nil +} + +func generateResumeTemplateData(resume er.Resume, event pl.Event, tx *gorm.DB) (*ResumePDF, error) { + // get encounter + includes := "Patient,Patient.Person,Patient.Person.BirthRegency,Patient.Person.Contacts" + encounter, err := ue.ReadDetailData(ee.ReadDetailDto{Id: *resume.Encounter_Id, Includes: includes}, &event) + if err != nil { + return nil, err + } + + // map template data + rData := er.ValueDto{} + if resume.Value != nil { + err := json.Unmarshal([]byte(*resume.Value), &rData) + if err != nil { + event.ErrInfo = pl.ErrorInfo{ + Code: "data-unmarshal-fail", + Detail: err.Error(), + Raw: err, + } + return nil, err + } + } else { + return nil, errors.New("there is no data to be used") + } + templateData := ResumePDF{} + templateData.MedicalRecord = *encounter.Patient.Number + templateData.NIK = *encounter.Patient.Person.ResidentIdentityNumber + templateData.Name = encounter.Patient.Person.Name + templateData.BirthPlaceDate = pu.FormatPlaceAndDate(encounter.Patient.Person.BirthRegency.Name, *encounter.Patient.Person.BirthDate) + templateData.Gender = encounter.Patient.Person.GenderString() + templateData.Phone = encounter.Patient.Person.GetPhoneNumber() + // templateData.Class = get from vclaim sep eg. III + // templateData.Unit = get from vclaim sep eg. R.KERINCI - KLS 3 + templateData.Doctor_Name = resume.Doctor.Employee.Person.FullName() + templateData.StartedAt = *pc.TimeToStringWithFormat(encounter.StartedAt, "") + templateData.FinishedAt = *pc.TimeToStringWithFormat(encounter.FinishedAt, "") + templateData.DiagnosisIn = rData.Assessment.DiagnosisIn + templateData.Diagnosis = rData.Diagnosis.SecondaryDiagnosis + templateData.MainComplaint = rData.Assessment.MainComplaint + templateData.MedicalHistory = rData.Assessment.MedicalHistory + templateData.PhysicalExamination = rData.Assessment.PhysicalExamination + templateData.SupportingExamination = rData.Supporting.Notes + templateData.MedicalActions = rData.Action.AdditionalActions + templateData.MedicalAction = rData.Action.MedicalActions + templateData.Consultations = rData.Consultation.Consultations + templateData.Allergy = rData.Pharmacy.AllergySpecialConditions + templateData.ConsciousnessLevel = rData.Discharge.ConsciousnessLevel + templateData.BloodPressure = fmt.Sprintf("%.0f/%.0f", rData.Discharge.BloodPressureSystolic, rData.Discharge.BloodPressureDiastolic) + templateData.BodyTemperature = rData.Discharge.BodyTemperature + templateData.RespirationRate = rData.Discharge.RespirationRate + templateData.HeartRate = rData.Discharge.HeartRate + templateData.PainScale = rData.Discharge.PainScale + templateData.ConditionOnDischarge = rData.Management.ConditionOnDischarge + templateData.DischargeMethod = rData.Management.DischargeMethod + templateData.Medications = rData.Medication.Medications + templateData.Date = pu.GetTimeNow().Format("02-01-2006") + + return &templateData, nil +} + +func generateScreeningTemplateData(screenings []es.Screening, event pl.Event, tx *gorm.DB) (*ScreeningPDF, error) { + // get encounter + includes := "Patient,Patient.Person" + encounter, err := ue.ReadDetailData(ee.ReadDetailDto{Id: *screenings[0].Encounter_Id, Includes: includes}, &event) + if err != nil { + return nil, err + } + + switch screenings[0].Type { + case ercl.SFTCA: + // map template data + sData := es.FormA{} + if screenings[0].Value != nil { + err := json.Unmarshal([]byte(*screenings[0].Value), &sData) + if err != nil { + event.ErrInfo = pl.ErrorInfo{ + Code: "data-unmarshal-fail", + Detail: err.Error(), + Raw: err, + } + return nil, err + } + } else { + return nil, errors.New("there is no data to be used") + } + + templateData := ScreeningPDF{} + templateData.IssuedDate = pu.GetTimeNow().Format("2006-01-02 15:04:05") + templateData.MedicalRecord = *encounter.Patient.Number + templateData.Name = encounter.Patient.Person.FullName() + templateData.BirthDate = encounter.Patient.Person.BirthDate.Format("2006-01-02 15:04:05") + templateData.Employee_Name = screenings[0].Employee.Person.FullName() + templateData.EarlyMedic = sData.Screening.SelectedScreeningLabels() + templateData.Assessment = sData.AssessmentDetail + templateData.ProblemIdentification = sData.ProblemIdentification.SelectedProblemLabels() + templateData.Planning = sData.PlanningDetail + templateData.Date = screenings[0].CreatedAt.Format("2006-01-02 15:04:05") + + return &templateData, nil + case ercl.SFTCB: + // map template data + templateData := ScreeningPDF{} + templateData.IssuedDate = pu.GetTimeNow().Format("2006-01-02 15:04:05") + templateData.MedicalRecord = *encounter.Patient.Number + templateData.Name = encounter.Patient.Person.FullName() + templateData.BirthDate = encounter.Patient.Person.BirthDate.Format("2006-01-02 15:04:05") + for k, v := range screenings { + templateData.FormB = append(templateData.FormB, ScreeningFormBPDF{ + Number: k + 1, + Date: v.CreatedAt.Format("2006-01-02 15:04:05"), + Employee_Name: v.Employee.Person.FullName(), + Value: *v.Value, + }) + } + + return &templateData, nil + } + return nil, errors.New("invalid screening type") +} + +func generateScreening(input GenerateDto, event pl.Event, tx *gorm.DB) (*ResponseDto, error) { + // get value from resume by ref_id + includes := "Employee.Person" + s, err := us.ReadDetailData(es.ReadDetailDto{Id: uint(*pc.StringToUint64(*input.Ref_Id)), Includes: includes}, &event) + if err != nil { + return nil, err + } + + var screenings []es.Screening + var templateData *ScreeningPDF + if s.IsFormA() { + if s.FileUrl != nil { + if err := removeFile(string(input.EntityType_Code), *s.FileUrl); err != nil { + return nil, err + } + } + screenings = append(screenings, *s) + input.FormatType = erc.DFTCPDF + input.TemplateName = TDNSA + input.Encounter_Id = s.Encounter_Id + templateData, err = generateScreeningTemplateData(screenings, event, tx) + if err != nil { + return nil, err + } + } else { + includes := "Employee.Person" + sort := "CreatedAt:ASC" + ss, _, err := us.ReadListData(es.ReadListDto{FilterDto: es.FilterDto{Encounter_Id: s.Encounter_Id, Type: ercl.SFTCB}, Includes: includes, Sort: sort}, &event, tx) + if err != nil { + return nil, err + } + screenings = append(screenings, ss...) + input.FormatType = erc.DFTCPDF + input.TemplateName = TDNSB + input.Encounter_Id = s.Encounter_Id + templateData, err = generateScreeningTemplateData(screenings, event, tx) + if err != nil { + return nil, err + } + } + + // generate file + urlPub, err := generateFile(input, templateData) + if err != nil { + return nil, err + } + + if len(screenings) > 1 { + for i := range screenings { + screenings[i].FileUrl = &urlPub + } + if err := tx.Save(&screenings).Error; err != nil { + return nil, err + } + } else { + s.FileUrl = &urlPub + if err := tx.Save(&s).Error; err != nil { + return nil, err + } + } + + response := ResponseDto{ + FileUrl: urlPub, + } + + return &response, nil +} diff --git a/internal/use-case/main-use-case/generate-file/tycovar.go b/internal/use-case/main-use-case/generate-file/tycovar.go new file mode 100644 index 00000000..a8fd5ef5 --- /dev/null +++ b/internal/use-case/main-use-case/generate-file/tycovar.go @@ -0,0 +1,185 @@ +package generatefile + +import ( + "fmt" + "time" + + erc "simrs-vx/internal/domain/references/common" + ere "simrs-vx/internal/domain/references/encounter" + + er "simrs-vx/internal/domain/main-entities/resume" + + pu "simrs-vx/pkg/use-case-helper" +) + +type GeneralConsentPDF struct { + Relatives []string `json:"relatives"` + Responsible string `json:"responsible"` + Informant string `json:"informant"` + Witness1 string `json:"witness1"` + Witness2 string `json:"witness2"` + Date string `json:"date"` +} + +type ControlLetterPDF struct { + Number string + Doctor_Name string + DstUnit_Name string + CardNumber string + Name string + BirthDate string + Diagnose string + PlanDate string + ResponsibleDoctor_Name string + PrintDate string +} + +type ResumePDF struct { + MedicalRecord string + NIK string + Name string + BirthPlaceDate string + Gender string + Phone string + Class string + Unit string + Doctor_Name string + StartedAt string + FinishedAt string + DiagnosisIn string + DiagnosisOut string + Diagnosis []er.DiagnosisEntry + MainComplaint string + MedicalHistory string + PhysicalExamination string + SupportingExamination string + MedicalActions []er.ActionEntry + MedicalAction string + Consultations []er.ConsultationEntry + Allergy string + ConsciousnessLevel string + BloodPressure string + BodyTemperature float64 + RespirationRate float64 + HeartRate float64 + PainScale int + ConditionOnDischarge string + DischargeMethod string + Medications []er.MedicationEntry + // fasyankes + // date + // klinik + Date string +} + +type ScreeningPDF struct { + IssuedDate string + Date string + MedicalRecord string + Name string + BirthDate string + Employee_Name string + EarlyMedic []string + Assessment string + ProblemIdentification []string + Planning string + FormB []ScreeningFormBPDF +} + +type ScreeningFormBPDF struct { + Number int + Date string + Employee_Name string + Value string +} + +type GenerateDto struct { + EntityType_Code ere.EntityTypeCode `json:"entityType_code" validate:"required"` + Ref_Id *string `json:"ref_id" validate:"required"` + Type_Code ere.DocTypeCode `json:"type_code" validate:"required"` + FormatType erc.DocFormatTypeCode `json:"formatType"` + TemplateName TemplateDocsName `json:"-"` + Encounter_Id *uint `json:"-"` + UseA5Lanscape bool `json:"-"` + + Data *string `json:"data"` +} + +type VclaimControlLetter struct { + Number string `json:"noSuratKontrol"` + PlannedControlDate string `json:"tglRencanaKontrol"` + Doctor_Name string `json:"namaDokter"` + DstUnit_Name string `json:"namaPoliTujuan"` + ResponsibleDoctor_Name string `json:"namaDokterPembuat"` + VclaimSep VclaimSep `json:"sep"` +} + +type VclaimSep struct { + VclaimMember VclaimMember `json:"peserta"` + Diagnose string `json:"diagnosa"` + Number string `json:"noSep"` +} + +type VclaimMember struct { + CardNumber string `json:"noKartu"` + Name string `json:"nama"` + BirthDate string `json:"tglLahir"` + Gender string `json:"kelamin"` +} + +type GeneratePDFdto struct { + TemplatePath string + TemplateData any + PdfPath string + UseA5Lanscape bool +} + +type ResponseDto struct { + FileUrl string `json:"fileUrl"` +} + +type TemplateDocsName string + +// TemplateDocsName is the name of the template file in the assets/docs folder +const ( + TDNGC TemplateDocsName = "general-consent.html" + TDNCL TemplateDocsName = "control-letter.html" + TDNR TemplateDocsName = "resume.html" + TDNSA TemplateDocsName = "screening-form-a.html" + TDNSB TemplateDocsName = "screening-form-b.html" +) + +func (v VclaimControlLetter) generateTemplateData() ControlLetterPDF { + + return ControlLetterPDF{ + Number: v.Number, + Doctor_Name: v.Doctor_Name, + DstUnit_Name: v.DstUnit_Name, + CardNumber: v.VclaimSep.VclaimMember.CardNumber, + Name: v.generateNameWithGender(), + BirthDate: v.generateBirthDate(), + Diagnose: v.VclaimSep.Diagnose, + PlanDate: v.PlannedControlDate, + ResponsibleDoctor_Name: v.ResponsibleDoctor_Name, + PrintDate: generatePrintDate(), + } +} + +func (v VclaimControlLetter) generateNameWithGender() string { + gender := "Perempuan" + if v.VclaimSep.VclaimMember.Gender == "L" { + gender = "Laki-Laki" + } + + return fmt.Sprintf("%s (%s)", v.VclaimSep.VclaimMember.Name, gender) +} + +func (v VclaimControlLetter) generateBirthDate() string { + t, _ := time.Parse("2006-01-02", v.VclaimSep.VclaimMember.BirthDate) + return pu.FormatIndonesianDate(t) +} + +func generatePrintDate() string { + now := time.Now() + return now.Format("2006/01/02") +} diff --git a/internal/use-case/main-use-case/infra/case.go b/internal/use-case/main-use-case/infra/case.go index 4771f3cb..f3ba3854 100644 --- a/internal/use-case/main-use-case/infra/case.go +++ b/internal/use-case/main-use-case/infra/case.go @@ -37,7 +37,7 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } - if input.InfraGroup_Code == ero.IFGCRoom { + if input.InfraGroup_Code == ero.IFGCProcedureRoom { if input.Parent_Code == nil { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ @@ -58,9 +58,9 @@ func Create(input e.CreateDto) (*d.Data, error) { data = *resData } - if input.InfraGroup_Code == ero.IFGCRoom { + if input.InfraGroup_Code == ero.IFGCProcedureRoom { input.Infra_Code = &data.Code - if err := createRoom(&input, &event, tx); err != nil { + if err := createProcedureRoom(&input, &event, tx); err != nil { return err } } diff --git a/internal/use-case/main-use-case/infra/helper.go b/internal/use-case/main-use-case/infra/helper.go index 81de5389..27c5442c 100644 --- a/internal/use-case/main-use-case/infra/helper.go +++ b/internal/use-case/main-use-case/infra/helper.go @@ -7,10 +7,10 @@ package infra import ( e "simrs-vx/internal/domain/main-entities/infra" ei "simrs-vx/internal/domain/main-entities/item" - er "simrs-vx/internal/domain/main-entities/room" + er "simrs-vx/internal/domain/main-entities/procedure-room" ero "simrs-vx/internal/domain/references/organization" ui "simrs-vx/internal/use-case/main-use-case/item" - ur "simrs-vx/internal/use-case/main-use-case/room" + ur "simrs-vx/internal/use-case/main-use-case/procedure-room" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" @@ -53,8 +53,9 @@ func createItem(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { return nil } -func createRoom(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { +func createProcedureRoom(input *e.CreateDto, event *pl.Event, tx *gorm.DB) error { roomCreate := er.CreateDto{ + Code: input.Infra_Code, Infra_Code: input.Infra_Code, Unit_Code: input.Unit_Code, Specialist_Code: input.Specialist_Code, diff --git a/internal/use-case/main-use-case/infra/lib.go b/internal/use-case/main-use-case/infra/lib.go index 5e0592c3..cd97d735 100644 --- a/internal/use-case/main-use-case/infra/lib.go +++ b/internal/use-case/main-use-case/infra/lib.go @@ -129,7 +129,7 @@ func UpdateData(input e.UpdateDto, data *e.Infra, event *pl.Event, dbx ...*gorm. // data.Parent = nil data.Childrens = nil data.Item = nil - data.Rooms = nil + data.ProcedureRooms = nil if err := tx.Save(&data).Error; err != nil { event.Status = "failed" diff --git a/internal/use-case/main-use-case/installation/case.go b/internal/use-case/main-use-case/installation/case.go index f66bedaf..b80b6ca5 100644 --- a/internal/use-case/main-use-case/installation/case.go +++ b/internal/use-case/main-use-case/installation/case.go @@ -1,7 +1,7 @@ package installation import ( - e "simrs-vx/internal/domain/main-entities/installation" + erc "simrs-vx/internal/domain/references/common" "strconv" dg "github.com/karincake/apem/db-gorm-pg" @@ -11,6 +11,9 @@ import ( pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/installation" + esync "simrs-vx/internal/domain/sync-entities/log" ) const source = "installation" @@ -25,36 +28,32 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event) 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 + id := uint(data.Id) + input.Id = &id } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -66,7 +65,6 @@ func Create(input e.CreateDto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Installation var dataList []e.Installation var metaList *e.MetaDto var err error @@ -80,23 +78,11 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -131,23 +117,11 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -177,6 +151,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -184,32 +159,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -233,6 +202,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -240,30 +210,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -274,3 +240,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/installation/middleware-runner.go b/internal/use-case/main-use-case/installation/middleware-runner.go index fce572bb..b2ff8cb4 100644 --- a/internal/use-case/main-use-case/installation/middleware-runner.go +++ b/internal/use-case/main-use-case/installation/middleware-runner.go @@ -1,35 +1,64 @@ 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" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/installation" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Installation) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +68,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Installation) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +87,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Installation) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +105,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Installation) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []UpdateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +124,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Installation) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []DeleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/installation/middleware.go b/internal/use-case/main-use-case/installation/middleware.go index 3d414c9b..363c2526 100644 --- a/internal/use-case/main-use-case/installation/middleware.go +++ b/internal/use-case/main-use-case/installation/middleware.go @@ -1,9 +1,20 @@ package installation +import ( + plugin "simrs-vx/internal/use-case/simgos-sync-plugin/new/installation" +) + // example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +func init() { + createPreMw = append(createPreMw, + createMw{Name: "sync-create-installation", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-sync-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "sync-update-installation", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "sync-delete-installation", Func: plugin.Delete}) +} diff --git a/internal/use-case/main-use-case/installation/tycovar.go b/internal/use-case/main-use-case/installation/tycovar.go index de8e9c9e..262bba8c 100644 --- a/internal/use-case/main-use-case/installation/tycovar.go +++ b/internal/use-case/main-use-case/installation/tycovar.go @@ -12,11 +12,27 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/installation" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Installation, tx *gorm.DB) error + Func func(input *e.CreateDto) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,16 +45,17 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/internal-reference/helper.go b/internal/use-case/main-use-case/internal-reference/helper.go index 234eb770..26b8903f 100644 --- a/internal/use-case/main-use-case/internal-reference/helper.go +++ b/internal/use-case/main-use-case/internal-reference/helper.go @@ -5,35 +5,41 @@ Any functions that are used internally by the use-case package internal_reference import ( + e "simrs-vx/internal/domain/main-entities/encounter" ir "simrs-vx/internal/domain/main-entities/internal-reference" erc "simrs-vx/internal/domain/references/common" ) -func setData[T *ir.CreateDto | *ir.UpdateDto](input T, data *ir.InternalReference) { - var inputSrc *ir.CreateDto - if inputT, ok := any(input).(*ir.CreateDto); ok { - inputSrc = inputT - } else { - inputTemp := any(input).(*ir.UpdateDto) - inputSrc = &inputTemp.CreateDto - } +func setDataCreate(input *ir.CreateDto, data *ir.InternalReference) { + data.Encounter_Id = input.Encounter_Id + data.Unit_Code = input.Unit_Code - data.Encounter_Id = inputSrc.Encounter_Id - data.Unit_Code = inputSrc.Unit_Code - data.Doctor_Code = inputSrc.Doctor_Code - data.Status_Code = &inputSrc.Status_Code + data.Doctor_Code = input.Doctor_Code + data.SrcDoctor_Code = input.SrcDoctor_Code + + data.Nurse_Code = input.Nurse_Code + data.SrcNurse_Code = input.SrcNurse_Code + data.Status_Code = &input.Status_Code } -func setBulkData(input []ir.CreateDto, encounterId uint) []ir.InternalReference { +func setDataUpdate(input *ir.UpdateDto, data *ir.InternalReference) { + data.Doctor_Code = input.Doctor_Code + data.Nurse_Code = input.Nurse_Code + data.Status_Code = &input.Status_Code +} + +func setBulkData(input *e.SwitchUnitDto) []ir.InternalReference { var data []ir.InternalReference - for _, v := range input { + for _, v := range *input.InternalReferences { statusCode := erc.DACNew data = append(data, ir.InternalReference{ - Encounter_Id: &encounterId, - Unit_Code: v.Unit_Code, - Doctor_Code: v.Doctor_Code, - Status_Code: &statusCode, + Encounter_Id: &input.Id, + Unit_Code: v.Unit_Code, + Doctor_Code: v.Doctor_Code, + Status_Code: &statusCode, + SrcDoctor_Code: input.Src_Doctor_Code, + SrcNurse_Code: input.Src_Nurse_Code, }) } diff --git a/internal/use-case/main-use-case/internal-reference/lib.go b/internal/use-case/main-use-case/internal-reference/lib.go index bf852dc6..0aa54b4b 100644 --- a/internal/use-case/main-use-case/internal-reference/lib.go +++ b/internal/use-case/main-use-case/internal-reference/lib.go @@ -2,6 +2,7 @@ package internal_reference import ( "errors" + e "simrs-vx/internal/domain/main-entities/encounter" eir "simrs-vx/internal/domain/main-entities/internal-reference" plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" @@ -16,7 +17,7 @@ func CreateData(input eir.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*eir.Int pl.SetLogInfo(event, nil, "started", "DBCreate") data := eir.InternalReference{} - setData(&input, &data) + setDataCreate(&input, &data) var tx *gorm.DB if len(dbx) > 0 { @@ -97,7 +98,7 @@ func ReadDetailData(input eir.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) ( func UpdateData(input eir.UpdateDto, data *eir.InternalReference, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, data, "started", "DBUpdate") - setData(&input, data) + setDataUpdate(&input, data) var tx *gorm.DB if len(dbx) > 0 { @@ -143,10 +144,10 @@ func DeleteData(data *eir.InternalReference, event *pl.Event, dbx ...*gorm.DB) e return nil } -func CreateBulkData(input []eir.CreateDto, encounterId uint, event *pl.Event, dbx ...*gorm.DB) error { +func CreateBulkData(input *e.SwitchUnitDto, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, nil, "started", "DBCreate") - data := setBulkData(input, encounterId) + data := setBulkData(input) var tx *gorm.DB if len(dbx) > 0 { diff --git a/internal/use-case/main-use-case/item/helper.go b/internal/use-case/main-use-case/item/helper.go index 6f7e0c57..2de4c1bd 100644 --- a/internal/use-case/main-use-case/item/helper.go +++ b/internal/use-case/main-use-case/item/helper.go @@ -23,4 +23,6 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Item) { data.Uom_Code = inputSrc.Uom_Code data.Infra_Code = inputSrc.Infra_Code data.Stock = inputSrc.Stock + data.BuyingPrice = inputSrc.BuyingPrice + data.SellingPrice = inputSrc.SellingPrice } diff --git a/internal/use-case/main-use-case/item/lib.go b/internal/use-case/main-use-case/item/lib.go index 56c4c915..a58a956b 100644 --- a/internal/use-case/main-use-case/item/lib.go +++ b/internal/use-case/main-use-case/item/lib.go @@ -81,7 +81,15 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e tx = dg.I } - if err := tx.First(&data, input.Id).Error; err != nil { + if input.Code != nil { + tx = tx.Where("\"Code\" = ?", *input.Code) + } + + if input.Id != nil { + tx = tx.Where("\"Id\" = ?", input.Id) + } + + if err := tx.First(&data).Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { return nil, processedErr } diff --git a/internal/use-case/main-use-case/material-package-item/case.go b/internal/use-case/main-use-case/material-package-item/case.go new file mode 100644 index 00000000..ecd891a6 --- /dev/null +++ b/internal/use-case/main-use-case/material-package-item/case.go @@ -0,0 +1,276 @@ +package materialpackageorder + +import ( + e "simrs-vx/internal/domain/main-entities/material-package-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 = "material" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.MaterialPackageItem{} + + 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.MaterialPackageItem + var dataList []e.MaterialPackageItem + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.MaterialPackageItem + 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.MaterialPackageItem + 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.MaterialPackageItem + 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-package-item/helper.go b/internal/use-case/main-use-case/material-package-item/helper.go new file mode 100644 index 00000000..c175f776 --- /dev/null +++ b/internal/use-case/main-use-case/material-package-item/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package materialpackageorder + +import ( + e "simrs-vx/internal/domain/main-entities/material-package-item" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MaterialPackageItem) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.MaterialPackage_Code = inputSrc.MaterialPackage_Code + data.Material_Code = inputSrc.Material_Code +} diff --git a/internal/use-case/main-use-case/material-package-item/lib.go b/internal/use-case/main-use-case/material-package-item/lib.go new file mode 100644 index 00000000..fc469249 --- /dev/null +++ b/internal/use-case/main-use-case/material-package-item/lib.go @@ -0,0 +1,140 @@ +package materialpackageorder + +import ( + e "simrs-vx/internal/domain/main-entities/material-package-item" + + plh "simrs-vx/pkg/lib-helper" + 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.MaterialPackageItem, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.MaterialPackageItem{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.MaterialPackageItem, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.MaterialPackageItem{} + 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.MaterialPackageItem{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.MaterialPackageItem, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.MaterialPackageItem{} + + 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.MaterialPackageItem, 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.MaterialPackageItem, 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-package-item/middleware-runner.go b/internal/use-case/main-use-case/material-package-item/middleware-runner.go new file mode 100644 index 00000000..09dfb39b --- /dev/null +++ b/internal/use-case/main-use-case/material-package-item/middleware-runner.go @@ -0,0 +1,103 @@ +package materialpackageorder + +import ( + e "simrs-vx/internal/domain/main-entities/material-package-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.MaterialPackageItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MaterialPackageItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MaterialPackageItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MaterialPackageItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MaterialPackageItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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-package-item/middleware.go b/internal/use-case/main-use-case/material-package-item/middleware.go new file mode 100644 index 00000000..1d1186af --- /dev/null +++ b/internal/use-case/main-use-case/material-package-item/middleware.go @@ -0,0 +1,9 @@ +package materialpackageorder + +// 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-package-item/tycovar.go b/internal/use-case/main-use-case/material-package-item/tycovar.go new file mode 100644 index 00000000..a7e239f1 --- /dev/null +++ b/internal/use-case/main-use-case/material-package-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 materialpackageorder + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/material-package-item" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.MaterialPackageItem, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.MaterialPackageItem, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.MaterialPackageItem, 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/material-package/case.go b/internal/use-case/main-use-case/material-package/case.go new file mode 100644 index 00000000..5e56517b --- /dev/null +++ b/internal/use-case/main-use-case/material-package/case.go @@ -0,0 +1,276 @@ +package materialpackage + +import ( + e "simrs-vx/internal/domain/main-entities/material-package" + "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.MaterialPackage{} + + 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.MaterialPackage + var dataList []e.MaterialPackage + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.MaterialPackage + 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{Code: &input.Code} + var data *e.MaterialPackage + 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{Code: input.Code} + var data *e.MaterialPackage + 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-package/helper.go b/internal/use-case/main-use-case/material-package/helper.go new file mode 100644 index 00000000..7d8e7a9a --- /dev/null +++ b/internal/use-case/main-use-case/material-package/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package materialpackage + +import ( + e "simrs-vx/internal/domain/main-entities/material-package" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MaterialPackage) { + 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/material-package/lib.go b/internal/use-case/main-use-case/material-package/lib.go new file mode 100644 index 00000000..d4d6ac50 --- /dev/null +++ b/internal/use-case/main-use-case/material-package/lib.go @@ -0,0 +1,146 @@ +package materialpackage + +import ( + e "simrs-vx/internal/domain/main-entities/material-package" + + plh "simrs-vx/pkg/lib-helper" + 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.MaterialPackage, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.MaterialPackage{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.MaterialPackage, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.MaterialPackage{} + 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.MaterialPackage{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.MaterialPackage, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.MaterialPackage{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if input.Code != nil { + tx = tx.Where("\"Code\" = ?", *input.Code) + } else { + tx = tx.Where("\"Id\" = ?", *input.Id) + } + + if err := tx.First(&data).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.MaterialPackage, 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.MaterialPackage, 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-package/middleware-runner.go b/internal/use-case/main-use-case/material-package/middleware-runner.go new file mode 100644 index 00000000..b1ea182c --- /dev/null +++ b/internal/use-case/main-use-case/material-package/middleware-runner.go @@ -0,0 +1,103 @@ +package materialpackage + +import ( + e "simrs-vx/internal/domain/main-entities/material-package" + 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.MaterialPackage) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MaterialPackage) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MaterialPackage) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MaterialPackage) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MaterialPackage) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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-package/middleware.go b/internal/use-case/main-use-case/material-package/middleware.go new file mode 100644 index 00000000..85020e68 --- /dev/null +++ b/internal/use-case/main-use-case/material-package/middleware.go @@ -0,0 +1,9 @@ +package materialpackage + +// 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-package/tycovar.go b/internal/use-case/main-use-case/material-package/tycovar.go new file mode 100644 index 00000000..67aa3174 --- /dev/null +++ b/internal/use-case/main-use-case/material-package/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 materialpackage + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/material-package" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.MaterialPackage, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.MaterialPackage, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.MaterialPackage, 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-order-item/case.go b/internal/use-case/main-use-case/mcu-order-item/case.go index 9037b771..e04feded 100644 --- a/internal/use-case/main-use-case/mcu-order-item/case.go +++ b/internal/use-case/main-use-case/mcu-order-item/case.go @@ -4,11 +4,7 @@ import ( "errors" "strconv" - e "simrs-vx/internal/domain/main-entities/mcu-order-item" - - umo "simrs-vx/internal/use-case/main-use-case/mcu-order" - - erc "simrs-vx/internal/domain/references/common" + "gorm.io/gorm" dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" @@ -16,7 +12,10 @@ import ( pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" - "gorm.io/gorm" + e "simrs-vx/internal/domain/main-entities/mcu-order-item" + erc "simrs-vx/internal/domain/references/common" + + umo "simrs-vx/internal/use-case/main-use-case/mcu-order" ) const source = "mcu-order-item" diff --git a/internal/use-case/main-use-case/mcu-order/case.go b/internal/use-case/main-use-case/mcu-order/case.go index 38f13088..6d7c4fed 100644 --- a/internal/use-case/main-use-case/mcu-order/case.go +++ b/internal/use-case/main-use-case/mcu-order/case.go @@ -324,6 +324,65 @@ func Delete(input e.DeleteDto) (*d.Data, error) { } +func Submit(input e.ReadDetailDto) (*d.Data, error) { + var data *e.McuOrder + var err error + + event := pl.Event{ + Feature: "Process", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "process") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + data, err = ReadDetailData(input, &event, tx) + if err != nil { + return err + } + + if data.IsNotNew() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "prescription is not in new state", + Raw: errors.New("prescription is not in new state"), + } + return pl.SetLogError(&event, input) + } + + data.Status_Code = erc.DSCSubmited + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(&event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "submited", + }, + Data: data.ToResponse(), + }, nil + +} + func Complete(input e.ReadDetailDto) (*d.Data, error) { var data *e.McuOrder var err error diff --git a/internal/use-case/main-use-case/medicine-form/case.go b/internal/use-case/main-use-case/medicine-form/case.go new file mode 100644 index 00000000..6eb0fb75 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-form/case.go @@ -0,0 +1,276 @@ +package medicineform + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-form" + "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-form" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.MedicineForm{} + + 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.MedicineForm + var dataList []e.MedicineForm + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.MedicineForm + 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{Code: input.Code} + var data *e.MedicineForm + 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{Code: input.Code} + var data *e.MedicineForm + 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-form/helper.go b/internal/use-case/main-use-case/medicine-form/helper.go new file mode 100644 index 00000000..8e80369c --- /dev/null +++ b/internal/use-case/main-use-case/medicine-form/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package medicineform + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-form" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.MedicineForm) { + 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-form/lib.go b/internal/use-case/main-use-case/medicine-form/lib.go new file mode 100644 index 00000000..01d570a2 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-form/lib.go @@ -0,0 +1,147 @@ +package medicineform + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-form" + + plh "simrs-vx/pkg/lib-helper" + 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.MedicineForm, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.MedicineForm{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.MedicineForm, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.MedicineForm{} + 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.MedicineForm{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.MedicineForm, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.MedicineForm{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if input.Code != nil { + tx = tx.Where("\"Code\" = ?", *input.Code) + } + if input.Id != nil { + tx = tx.Where("\"Id\" = ?", input.Id) + } + + if err := tx.First(&data).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.MedicineForm, 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.MedicineForm, 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-form/middleware-runner.go b/internal/use-case/main-use-case/medicine-form/middleware-runner.go new file mode 100644 index 00000000..9b22189b --- /dev/null +++ b/internal/use-case/main-use-case/medicine-form/middleware-runner.go @@ -0,0 +1,103 @@ +package medicineform + +import ( + e "simrs-vx/internal/domain/main-entities/medicine-form" + 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.MedicineForm) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MedicineForm) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MedicineForm) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MedicineForm) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.MedicineForm) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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-form/middleware.go b/internal/use-case/main-use-case/medicine-form/middleware.go new file mode 100644 index 00000000..b4388010 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-form/middleware.go @@ -0,0 +1,9 @@ +package medicineform + +// 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-form/tycovar.go b/internal/use-case/main-use-case/medicine-form/tycovar.go new file mode 100644 index 00000000..8dbd3509 --- /dev/null +++ b/internal/use-case/main-use-case/medicine-form/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 medicineform + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/medicine-form" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.MedicineForm, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.MedicineForm, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.MedicineForm, 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/lib.go b/internal/use-case/main-use-case/medicine/lib.go index f9fccb2e..8dfc4457 100644 --- a/internal/use-case/main-use-case/medicine/lib.go +++ b/internal/use-case/main-use-case/medicine/lib.go @@ -1,6 +1,7 @@ package medicine import ( + "fmt" e "simrs-vx/internal/domain/main-entities/medicine" plh "simrs-vx/pkg/lib-helper" @@ -47,6 +48,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Me tx = dg.I } + fmt.Println(input.Includes) tx = tx. Model(&e.Medicine{}). Scopes(gh.Preload(input.Includes)). diff --git a/internal/use-case/main-use-case/patient/case.go b/internal/use-case/main-use-case/patient/case.go index a0766d12..5180137b 100644 --- a/internal/use-case/main-use-case/patient/case.go +++ b/internal/use-case/main-use-case/patient/case.go @@ -1,24 +1,28 @@ package patient import ( + "errors" "strconv" - evm "simrs-vx/internal/domain/bpjs-entities/vclaim-member" - e "simrs-vx/internal/domain/main-entities/patient" - - uvm "simrs-vx/internal/use-case/bpjs-use-case/vclaim-member" - upe "simrs-vx/internal/use-case/main-use-case/person" - upa "simrs-vx/internal/use-case/main-use-case/person-address" - upc "simrs-vx/internal/use-case/main-use-case/person-contact" - upi "simrs-vx/internal/use-case/main-use-case/person-insurance" - upr "simrs-vx/internal/use-case/main-use-case/person-relative" - 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" + + erc "simrs-vx/internal/domain/references/common" + + evm "simrs-vx/internal/domain/bpjs-entities/vclaim-member" + e "simrs-vx/internal/domain/main-entities/patient" + esync "simrs-vx/internal/domain/sync-entities/log" + + uvm "simrs-vx/internal/use-case/bpjs-use-case/vclaim-member" + upe "simrs-vx/internal/use-case/main-use-case/person" + upa "simrs-vx/internal/use-case/main-use-case/person-address" + upc "simrs-vx/internal/use-case/main-use-case/person-contact" + upi "simrs-vx/internal/use-case/main-use-case/person-insurance" + upr "simrs-vx/internal/use-case/main-use-case/person-relative" ) const source = "patient" @@ -33,15 +37,34 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event, input.Sync) + + if !input.AuthInfo.IsReg() && !input.AuthInfo.IsSys() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: "user role is not allowed to create patient, only 'reg' position is allowed", + Raw: errors.New("authentication failed"), + } + return nil, pl.SetLogError(&event, input) + } + + input.RegisteredBy_User_Name = &input.AuthInfo.User_Name 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 } + // Run pre-middleware -> Generate number + nomr, err := mwRunner.RunGenerateNumberMiddleware(generatePatientNumber) + if err != nil { + return err + } + input.Number = nomr + if person_id, err := upe.CreateOrUpdatePerson(input.Person, &event, tx); err != nil { return err } else { @@ -88,21 +111,26 @@ func Create(input e.CreateDto) (*d.Data, error) { data = *resData } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + dataPatient, err := ReadDetailData(e.ReadDetailDto{Id: uint16(data.Id)}, &event, tx) + if err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPost) + // Run post-middleware + if err := mwRunner.RunCreateSyncMiddleware(createSimxSyncMw, dataPatient); err != nil { + return err + } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -114,7 +142,6 @@ func Create(input e.CreateDto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Patient var dataList []e.Patient var metaList *e.MetaDto var err error @@ -128,23 +155,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -179,23 +192,9 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -225,6 +224,17 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event, input.Sync) + + if !input.AuthInfo.IsReg() && !input.AuthInfo.IsSys() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: "user role is not allowed to create patient, only 'reg' position is allowed", + Raw: errors.New("authentication failed"), + } + return nil, pl.SetLogError(&event, input) + } err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -232,13 +242,6 @@ func Update(input e.UpdateDto) (*d.Data, error) { 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 person_id, err := upe.CreateOrUpdatePerson(input.Person, &event, tx); err != nil { return err } else { @@ -277,21 +280,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - pl.SetLogInfo(&event, nil, "complete") + dataPatient, err := ReadDetailData(e.ReadDetailDto{Id: uint16(data.Id)}, &event, tx) + if err != nil { + return err + } - mwRunner.setMwType(pu.MWTPost) + mwRunner.setMwType(pu.MWTPre) // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + if err := mwRunner.RunUpdateMiddleware(updatePreMw, dataPatient); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -315,6 +323,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event, input.Sync) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -322,30 +331,66 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + // Delete Patient if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) + // Delete PersonInsurance + if insurance := data.Person.Insurances; insurance != nil && len(*insurance) > 0 { + if err = upi.DeleteMultipleData(data.Person_Id, &event, tx); err != nil { + return err + } + } + + // Delete PersonRelative + if relative := data.Person.Relatives; relative != nil && len(*relative) > 0 { + if err = upr.DeleteMultipleData(data.Person_Id, &event, tx); err != nil { + return err + } + } + + // Delete PersonContacts + if contact := data.Person.Contacts; contact != nil && len(*contact) > 0 { + if err = upc.DeleteMultipleData(data.Person_Id, &event, tx); err != nil { + return err + } + } + + // Delete PersonAddress + if address := data.Person.Addresses; address != nil && len(*address) > 0 { + if err = upa.DeleteMultipleData(data.Person_Id, &event, tx); err != nil { + return err + } + } + + // Delete VclaimMember + if vclaim := data.Person.VclaimMember; vclaim != nil { + if err = uvm.DeleteData(vclaim, &event, tx); err != nil { + return err + } + } + + // Delete Person + if err = upe.DeleteData(data.Person, &event, tx); err != nil { + return err + } + + mwRunner.setMwType(pu.MWTPre) // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -421,3 +466,32 @@ func Search(input e.SearchDto) (*d.Data, error) { Data: e.ToResponseList(dataList), }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/patient/helper.go b/internal/use-case/main-use-case/patient/helper.go index c53ebca3..fa3f1815 100644 --- a/internal/use-case/main-use-case/patient/helper.go +++ b/internal/use-case/main-use-case/patient/helper.go @@ -19,17 +19,21 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Patient) error { var inputSrc *e.CreateDto if inputT, ok := any(input).(*e.CreateDto); ok { inputSrc = inputT + data.RegisteredBy_User_Name = inputSrc.RegisteredBy_User_Name } else { inputTemp := any(input).(*e.UpdateDto) inputSrc = &inputTemp.CreateDto } - if data.Id == 0 { + switch { + case inputSrc.Number == nil && data.Number == nil: medRecNum, err := GenerateNextMedicalRecordNumber() if err != nil { return err } data.Number = &medRecNum + case inputSrc.Number != nil: + data.Number = inputSrc.Number } data.Person_Id = inputSrc.Person_Id @@ -52,38 +56,57 @@ func GenerateNextMedicalRecordNumber() (string, error) { return "", err } - var nextInt int64 - var format string + //var nextInt int64 + //var format string + //if last == "" { + // // No existing records, start with 10 digits + // nextInt = 1 + // format = "%08d" + //} else { + // n, err := strconv.ParseInt(last, 10, 64) + // if err != nil { + // return "", err + // } + // nextInt = n + 1 + // + // // Dynamically determine format based on existing number + // digitCount := len(last) + // + // // If the incremented number needs more digits, expand format + // nextStr := strconv.FormatInt(nextInt, 10) + // if len(nextStr) > digitCount { + // digitCount = len(nextStr) + // } + // + // // Ensure minimum 10 digits as per requirement + // if digitCount < 10 { + // digitCount = 10 + // } + // + // format = fmt.Sprintf("%%0%dd", digitCount) + //} + + const prefix = "12" // fixed starting prefix (same as $awal_rm) in simgos + const maxSuffix = 999999 + + // No existing NOMR → start fresh if last == "" { - // No existing records, start with 10 digits - nextInt = 1 - format = "%010d" - } else { - n, err := strconv.ParseInt(last, 10, 64) - if err != nil { - return "", err - } - nextInt = n + 1 - - // Dynamically determine format based on existing number - digitCount := len(last) - - // If the incremented number needs more digits, expand format - nextStr := strconv.FormatInt(nextInt, 10) - if len(nextStr) > digitCount { - digitCount = len(nextStr) - } - - // Ensure minimum 10 digits as per requirement - if digitCount < 10 { - digitCount = 10 - } - - format = fmt.Sprintf("%%0%dd", digitCount) + return prefix + "000001", nil } - return fmt.Sprintf(format, nextInt), nil + suffix := last[len(prefix):] // extract numeric part + num, _ := strconv.Atoi(suffix) + + // 3. If suffix reaches 999999 → increment the prefix + if num == maxSuffix { + p, _ := strconv.Atoi(prefix) + p++ + return fmt.Sprintf("%d000001", p), nil + } + + // 4. Normal increment + return prefix + fmt.Sprintf("%06d", num+1), nil } func endpointMapper(noBpjs string) string { diff --git a/internal/use-case/main-use-case/patient/lib.go b/internal/use-case/main-use-case/patient/lib.go index 36c9d416..e615c854 100644 --- a/internal/use-case/main-use-case/patient/lib.go +++ b/internal/use-case/main-use-case/patient/lib.go @@ -92,7 +92,8 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e Preload("Person.Relatives.Village.District.Regency.Province"). Preload("Person.Addresses.Village.District.Regency.Province"). Preload("Person.Addresses.PostalRegion.Village.District.Regency.Province"). - Preload("Person.Insurances.InsuranceCompany") + Preload("Person.Insurances.InsuranceCompany"). + Preload("Person.VclaimMember") if err := tx.First(&data, input.Id).Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { diff --git a/internal/use-case/main-use-case/patient/middleware-runner.go b/internal/use-case/main-use-case/patient/middleware-runner.go index 2e9ea66a..0cc10e27 100644 --- a/internal/use-case/main-use-case/patient/middleware-runner.go +++ b/internal/use-case/main-use-case/patient/middleware-runner.go @@ -1,24 +1,34 @@ package patient import ( - e "simrs-vx/internal/domain/main-entities/patient" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/patient" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event, syncFromOldSource bool) *middlewareRunner { + activateSync := sync.O.Enable + if syncFromOldSource { + activateSync = false + } + return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: activateSync, } } @@ -38,7 +48,51 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e return nil } +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateSyncMiddleware(middlewares []createSyncMw, input *e.Patient) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != 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.Patient) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +108,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Patient) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +126,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Patient) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.Patient) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +145,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Patient) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -98,6 +164,25 @@ func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, inpu return nil } +func (me *middlewareRunner) RunGenerateNumberMiddleware(middlewares generateNumberMw) (generateNorm *string, err error) { + if !me.SyncOn { + return nil, nil + } + + logData := pu.GetLogData(nil, nil) + + pl.SetLogInfo(me.Event, logData, "started", middlewares.Name) + + generateNorm, err = middlewares.Func() + if err != nil { + return nil, pu.HandleMiddlewareError(me.Event, string(me.MwType), middlewares.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + + return +} + func (me *middlewareRunner) setMwType(mwType pu.MWType) { me.MwType = mwType } diff --git a/internal/use-case/main-use-case/patient/middleware.go b/internal/use-case/main-use-case/patient/middleware.go index 6b0175dc..bd3e955b 100644 --- a/internal/use-case/main-use-case/patient/middleware.go +++ b/internal/use-case/main-use-case/patient/middleware.go @@ -5,17 +5,31 @@ import ( "fmt" "io" "net/http" - - e "simrs-vx/internal/domain/main-entities/patient" + plugin "simrs-vx/internal/use-case/simgos-sync-plugin/new/patient" "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/patient" ) // example of middleware func init() { createPreMw = append(createPreMw, - createMw{Name: "check-vclaim-member", Func: checkVclaimMember}, - ) + createMw{Name: "check-vclaim-member", Func: checkVclaimMember}) + + createSimxSyncMw = append(createSimxSyncMw, + createSyncMw{Name: "sync-create-patient", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-sync-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "sync-update-patient", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "sync-delete-patient", Func: plugin.Delete}) + + generatePatientNumber = generateNumberMw{Name: "generate-nomr-patient", Func: plugin.GenerateNomrPatient} } func checkVclaimMember(input *e.CreateDto, data *e.Patient, tx *gorm.DB) error { diff --git a/internal/use-case/main-use-case/patient/tycovar.go b/internal/use-case/main-use-case/patient/tycovar.go index 29e5c368..d2370122 100644 --- a/internal/use-case/main-use-case/patient/tycovar.go +++ b/internal/use-case/main-use-case/patient/tycovar.go @@ -12,6 +12,7 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/patient" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { @@ -19,6 +20,26 @@ type createMw struct { Func func(input *e.CreateDto, data *e.Patient, tx *gorm.DB) error } +type createSyncMw struct { + Name string + Func func(input *e.Patient) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.Patient) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error +} + type readListMw struct { Name string Func func(input *e.ReadListDto, data *e.Patient, tx *gorm.DB) error @@ -29,19 +50,27 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Patient, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type generateNumberMw struct { + Name string + Func func() (*string, error) +} -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +type UpdateMw = updateMw +type DeleteMw = deleteMw + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxSyncMw []createSyncMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw +var generatePatientNumber generateNumberMw type BPJSResponse struct { MetaData struct { diff --git a/internal/use-case/main-use-case/person-address/lib.go b/internal/use-case/main-use-case/person-address/lib.go index d0a581bd..8a07aba6 100644 --- a/internal/use-case/main-use-case/person-address/lib.go +++ b/internal/use-case/main-use-case/person-address/lib.go @@ -2,6 +2,8 @@ package personaddress import ( e "simrs-vx/internal/domain/main-entities/person-address" + "strconv" + "strings" plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" @@ -179,10 +181,19 @@ func CreateOrUpdateBatch(input []e.UpdateDto, event *pl.Event, tx ...*gorm.DB) e } setData(&input[idx], &data[idx]) if err := dbx.Create(&data[idx]).Error; err != nil { + errMsg := err.Error() + additionalMessage := "" + // FK error + if strings.Contains(errMsg, "violates foreign key") { + pos := strings.Index(errMsg, "violates foreign key") + additionalMessage = ", " + errMsg[pos:] + } + // Got another errot, put it down below + // .... event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-create-fail", - Detail: "Database insert failed", + Detail: "data insert failed at PersonAddres[" + strconv.Itoa(idx) + "]" + additionalMessage, Raw: err, } return pl.SetLogError(event, input) @@ -191,3 +202,28 @@ func CreateOrUpdateBatch(input []e.UpdateDto, event *pl.Event, tx ...*gorm.DB) e return nil } + +func DeleteMultipleData(personId *uint, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, personId, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx. + Where("\"Person_Id\" = ?", *personId). + Delete(&e.PersonAddress{}).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, personId) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/person-contact/lib.go b/internal/use-case/main-use-case/person-contact/lib.go index 034800a4..2c0028bf 100644 --- a/internal/use-case/main-use-case/person-contact/lib.go +++ b/internal/use-case/main-use-case/person-contact/lib.go @@ -191,3 +191,28 @@ func CreateOrUpdateBatch(input []e.UpdateDto, event *pl.Event, tx ...*gorm.DB) e return nil } + +func DeleteMultipleData(personId *uint, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, personId, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx. + Where("\"Person_Id\" = ?", *personId). + Delete(&e.PersonContact{}).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, personId) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/person-insurance/lib.go b/internal/use-case/main-use-case/person-insurance/lib.go index 86c6dc83..835694ff 100644 --- a/internal/use-case/main-use-case/person-insurance/lib.go +++ b/internal/use-case/main-use-case/person-insurance/lib.go @@ -191,3 +191,28 @@ func CreateOrUpdateBatch(input []e.UpdateDto, event *pl.Event, tx ...*gorm.DB) e return nil } + +func DeleteMultipleData(personId *uint, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, personId, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx. + Where("\"Person_Id\" = ?", *personId). + Delete(&e.PersonInsurance{}).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, personId) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/person-relative/lib.go b/internal/use-case/main-use-case/person-relative/lib.go index 28e12e2b..4531f736 100644 --- a/internal/use-case/main-use-case/person-relative/lib.go +++ b/internal/use-case/main-use-case/person-relative/lib.go @@ -191,3 +191,28 @@ func CreateOrUpdateBatch(input []e.UpdateDto, event *pl.Event, tx ...*gorm.DB) e return nil } + +func DeleteMultipleData(personId *uint, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, personId, "started", "DBDelete") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx. + Where("\"Person_Id\" = ?", *personId). + Delete(&e.PersonRelative{}).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, personId) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/prescription-item/lib.go b/internal/use-case/main-use-case/prescription-item/lib.go index aa6f97bf..aa5c9e2b 100644 --- a/internal/use-case/main-use-case/prescription-item/lib.go +++ b/internal/use-case/main-use-case/prescription-item/lib.go @@ -47,13 +47,13 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Pr tx = dg.I } - tx = tx. + tx = tx.Debug(). Model(&e.PrescriptionItem{}). Scopes(gh.Preload(input.Includes)). Scopes(gh.Filter(input.FilterDto)). Count(&count). Scopes(gh.Paginate(input, &pagination)). - Order("\"CreatedAt\" DESC") + Scopes(gh.Sort(input.Sort)) if err := tx.Find(&data).Error; err != nil { if err == gorm.ErrRecordNotFound { diff --git a/internal/use-case/main-use-case/prescription/case.go b/internal/use-case/main-use-case/prescription/case.go index fa68ec44..e67ec03d 100644 --- a/internal/use-case/main-use-case/prescription/case.go +++ b/internal/use-case/main-use-case/prescription/case.go @@ -279,6 +279,69 @@ func Delete(input e.DeleteDto) (*d.Data, error) { } +func Submit(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Prescription + var err error + + event := pl.Event{ + Feature: "Process", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "process") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + data, err = ReadDetailData(input, &event, tx) + if err != nil { + return err + } + + if data.IsNotNew() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "prescription is not in new state", + Raw: errors.New("prescription is not in new state"), + } + return pl.SetLogError(&event, input) + } + + data.Status_Code = erc.DSCSubmited + 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) + } + + if err := createMedication(input.Id, &event, tx); 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": "submited", + }, + Data: data.ToResponse(), + }, nil + +} + func Approve(input e.ReadDetailDto) (*d.Data, error) { var data *e.Prescription var err error diff --git a/internal/use-case/main-use-case/procedure-report/case.go b/internal/use-case/main-use-case/procedure-report/case.go new file mode 100644 index 00000000..e44cfaee --- /dev/null +++ b/internal/use-case/main-use-case/procedure-report/case.go @@ -0,0 +1,295 @@ +package procedurereport + +import ( + "errors" + "strconv" + + e "simrs-vx/internal/domain/main-entities/procedure-report" + + 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-report" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.ProcedureReport{} + + 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 !input.AuthInfo.IsDoctor() && !input.AuthInfo.IsNurse() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: "user position is not allowed", + Raw: errors.New("authentication failed"), + } + return pl.SetLogError(&event, input) + } + + if input.AuthInfo.Employee_Id != nil { + v := uint(*input.AuthInfo.Employee_Id) + input.Employee_Id = &v + } else { + input.Employee_Id = nil + } + + 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.ProcedureReport + var dataList []e.ProcedureReport + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ProcedureReport + 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.ProcedureReport + 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.ProcedureReport + 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-report/helper.go b/internal/use-case/main-use-case/procedure-report/helper.go new file mode 100644 index 00000000..e16711e5 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-report/helper.go @@ -0,0 +1,39 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package procedurereport + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-report" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ProcedureReport) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Date = inputSrc.Date + data.Doctor_Code = inputSrc.Doctor_Code + data.Operator_Name = inputSrc.Operator_Name + data.Assistant_Name = inputSrc.Assistant_Name + data.Instrumentor_Name = inputSrc.Instrumentor_Name + data.Anesthesia_Doctor_Code = inputSrc.Anesthesia_Doctor_Code + data.Anesthesia_Nurse_Name = inputSrc.Anesthesia_Nurse_Name + data.Diagnose = inputSrc.Diagnose + data.Nurse_Name = inputSrc.Nurse_Name + data.ProcedureValue = inputSrc.ProcedureValue + data.ExecutionValue = inputSrc.ExecutionValue + data.Type_Code = inputSrc.Type_Code + + //PROPER + // data.Operator_Employe_Id = inputSrc.Operator_Employe_Id + // data.Assistant_Employe_Id = inputSrc.Assistant_Employe_Id + // data.Instrumentor_Employe_Id = inputSrc.Instrumentor_Employe_Id + // data.Nurse_Code = inputSrc.Nurse_Code +} diff --git a/internal/use-case/main-use-case/procedure-report/lib.go b/internal/use-case/main-use-case/procedure-report/lib.go new file mode 100644 index 00000000..0588a944 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-report/lib.go @@ -0,0 +1,140 @@ +package procedurereport + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-report" + + plh "simrs-vx/pkg/lib-helper" + 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.ProcedureReport, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.ProcedureReport{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ProcedureReport, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ProcedureReport{} + 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.ProcedureReport{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + 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, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.ProcedureReport, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ProcedureReport{} + + 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.ProcedureReport, 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.ProcedureReport, 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-report/middleware-runner.go b/internal/use-case/main-use-case/procedure-report/middleware-runner.go new file mode 100644 index 00000000..c849ef28 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-report/middleware-runner.go @@ -0,0 +1,103 @@ +package procedurereport + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-report" + 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.ProcedureReport) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureReport) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureReport) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureReport) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureReport) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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-report/middleware.go b/internal/use-case/main-use-case/procedure-report/middleware.go new file mode 100644 index 00000000..157d4e2e --- /dev/null +++ b/internal/use-case/main-use-case/procedure-report/middleware.go @@ -0,0 +1,9 @@ +package procedurereport + +// 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-report/tycovar.go b/internal/use-case/main-use-case/procedure-report/tycovar.go new file mode 100644 index 00000000..3fb449c3 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-report/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 procedurereport + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/procedure-report" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ProcedureReport, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ProcedureReport, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ProcedureReport, 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-room-order-item/case.go b/internal/use-case/main-use-case/procedure-room-order-item/case.go new file mode 100644 index 00000000..3351c737 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order-item/case.go @@ -0,0 +1,276 @@ +package procedureroomorderitem + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-room-order-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 = "procedure-room-order-item" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.ProcedureRoomOrderItem{} + + 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.ProcedureRoomOrderItem + var dataList []e.ProcedureRoomOrderItem + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ProcedureRoomOrderItem + 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.ProcedureRoomOrderItem + 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.ProcedureRoomOrderItem + 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-room-order-item/helper.go b/internal/use-case/main-use-case/procedure-room-order-item/helper.go new file mode 100644 index 00000000..b7ca1a4f --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order-item/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package procedureroomorderitem + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-room-order-item" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ProcedureRoomOrderItem) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.ProcedureRoomOrder_Id = inputSrc.ProcedureRoomOrder_Id + data.ProcedureRoom_Code = inputSrc.ProcedureRoom_Code + data.Note = inputSrc.Note +} diff --git a/internal/use-case/main-use-case/procedure-room-order-item/lib.go b/internal/use-case/main-use-case/procedure-room-order-item/lib.go new file mode 100644 index 00000000..d5dd8b05 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order-item/lib.go @@ -0,0 +1,151 @@ +package procedureroomorderitem + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-room-order-item" + + plh "simrs-vx/pkg/lib-helper" + 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.ProcedureRoomOrderItem, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + deletedData := e.ProcedureRoomOrderItem{} + tx.Unscoped(). + Where("\"ProcedureRoomOrder_Id\" = ? AND \"ProcedureRoom_Code\" = ?", input.ProcedureRoomOrder_Id, input.ProcedureRoom_Code). + First(&deletedData) + if deletedData.Id != 0 { + if err := tx.Unscoped().Model(e.ProcedureRoomOrderItem{}).Where("\"Id\" = ?", deletedData.Id).Update("\"DeletedAt\"", nil).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + return &deletedData, nil + } + + data := e.ProcedureRoomOrderItem{} + setData(&input, &data) + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ProcedureRoomOrderItem, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ProcedureRoomOrderItem{} + 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.ProcedureRoomOrderItem{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + 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, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.ProcedureRoomOrderItem, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ProcedureRoomOrderItem{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Scopes(gh.Preload(input.Includes)).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.ProcedureRoomOrderItem, 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.ProcedureRoomOrderItem, 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-room-order-item/middleware-runner.go b/internal/use-case/main-use-case/procedure-room-order-item/middleware-runner.go new file mode 100644 index 00000000..f0edfe87 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order-item/middleware-runner.go @@ -0,0 +1,103 @@ +package procedureroomorderitem + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-room-order-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.ProcedureRoomOrderItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoomOrderItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoomOrderItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoomOrderItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoomOrderItem) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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-room-order-item/middleware.go b/internal/use-case/main-use-case/procedure-room-order-item/middleware.go new file mode 100644 index 00000000..0d6c70f7 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order-item/middleware.go @@ -0,0 +1,9 @@ +package procedureroomorderitem + +// 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-room-order-item/tycovar.go b/internal/use-case/main-use-case/procedure-room-order-item/tycovar.go new file mode 100644 index 00000000..bcc4bf17 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order-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 procedureroomorderitem + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/procedure-room-order-item" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ProcedureRoomOrderItem, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ProcedureRoomOrderItem, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ProcedureRoomOrderItem, 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-room-order/case.go b/internal/use-case/main-use-case/procedure-room-order/case.go new file mode 100644 index 00000000..7e9e1952 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order/case.go @@ -0,0 +1,338 @@ +package procedureroomorder + +import ( + "errors" + "strconv" + + "gorm.io/gorm" + + 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" + + e "simrs-vx/internal/domain/main-entities/procedure-room-order" + erc "simrs-vx/internal/domain/references/common" +) + +const source = "procedure-room-order" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.ProcedureRoomOrder{} + + 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.ProcedureRoomOrder + var dataList []e.ProcedureRoomOrder + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ProcedureRoomOrder + 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.ProcedureRoomOrder + 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.ProcedureRoomOrder + 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 + +} + +func Submit(input e.ReadDetailDto) (*d.Data, error) { + var data *e.ProcedureRoomOrder + var err error + + event := pl.Event{ + Feature: "Process", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "process") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + data, err = ReadDetailData(input, &event, tx) + if err != nil { + return err + } + + if data.IsNotNew() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: source + " is not in new state", + Raw: errors.New(source + " is not in new state"), + } + return pl.SetLogError(&event, input) + } + + data.Status_Code = erc.DSCSubmited + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(&event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "submited", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/procedure-room-order/helper.go b/internal/use-case/main-use-case/procedure-room-order/helper.go new file mode 100644 index 00000000..9f47d54d --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order/helper.go @@ -0,0 +1,24 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package procedureroomorder + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-room-order" + erc "simrs-vx/internal/domain/references/common" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ProcedureRoomOrder) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.MaterialPackage_Code = inputSrc.MaterialPackage_Code + data.Status_Code = erc.DSCNew +} diff --git a/internal/use-case/main-use-case/procedure-room-order/lib.go b/internal/use-case/main-use-case/procedure-room-order/lib.go new file mode 100644 index 00000000..50775d7c --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order/lib.go @@ -0,0 +1,140 @@ +package procedureroomorder + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-room-order" + + plh "simrs-vx/pkg/lib-helper" + 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.ProcedureRoomOrder, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.ProcedureRoomOrder{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ProcedureRoomOrder, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.ProcedureRoomOrder{} + 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.ProcedureRoomOrder{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + 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, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.ProcedureRoomOrder, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.ProcedureRoomOrder{} + + 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.ProcedureRoomOrder, 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.ProcedureRoomOrder, 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-room-order/middleware-runner.go b/internal/use-case/main-use-case/procedure-room-order/middleware-runner.go new file mode 100644 index 00000000..0fb20eaf --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order/middleware-runner.go @@ -0,0 +1,103 @@ +package procedureroomorder + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-room-order" + 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.ProcedureRoomOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoomOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoomOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoomOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoomOrder) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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-room-order/middleware.go b/internal/use-case/main-use-case/procedure-room-order/middleware.go new file mode 100644 index 00000000..cd9a687d --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order/middleware.go @@ -0,0 +1,9 @@ +package procedureroomorder + +// 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-room-order/tycovar.go b/internal/use-case/main-use-case/procedure-room-order/tycovar.go new file mode 100644 index 00000000..5113ce03 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room-order/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 procedureroomorder + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/procedure-room-order" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ProcedureRoomOrder, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ProcedureRoomOrder, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ProcedureRoomOrder, 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/room/case.go b/internal/use-case/main-use-case/procedure-room/case.go similarity index 95% rename from internal/use-case/main-use-case/room/case.go rename to internal/use-case/main-use-case/procedure-room/case.go index eeb1cce1..0378b759 100644 --- a/internal/use-case/main-use-case/room/case.go +++ b/internal/use-case/main-use-case/procedure-room/case.go @@ -1,7 +1,7 @@ -package room +package procedureroom import ( - e "simrs-vx/internal/domain/main-entities/room" + e "simrs-vx/internal/domain/main-entities/procedure-room" "strconv" dg "github.com/karincake/apem/db-gorm-pg" @@ -16,7 +16,7 @@ import ( const source = "specialist" func Create(input e.CreateDto) (*d.Data, error) { - data := e.Room{} + data := e.ProcedureRoom{} event := pl.Event{ Feature: "Create", @@ -66,8 +66,8 @@ func Create(input e.CreateDto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Room - var dataList []e.Room + var data *e.ProcedureRoom + var dataList []e.ProcedureRoom var metaList *e.MetaDto var err error @@ -119,7 +119,7 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { } func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { - var data *e.Room + var data *e.ProcedureRoom var err error event := pl.Event{ @@ -167,7 +167,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { func Update(input e.UpdateDto) (*d.Data, error) { rdDto := e.ReadDetailDto{Id: uint16(input.Id)} - var data *e.Room + var data *e.ProcedureRoom var err error event := pl.Event{ @@ -223,7 +223,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { func Delete(input e.DeleteDto) (*d.Data, error) { rdDto := e.ReadDetailDto{Id: uint16(input.Id)} - var data *e.Room + var data *e.ProcedureRoom var err error event := pl.Event{ diff --git a/internal/use-case/main-use-case/room/helper.go b/internal/use-case/main-use-case/procedure-room/helper.go similarity index 70% rename from internal/use-case/main-use-case/room/helper.go rename to internal/use-case/main-use-case/procedure-room/helper.go index 5e97a653..0101efef 100644 --- a/internal/use-case/main-use-case/room/helper.go +++ b/internal/use-case/main-use-case/procedure-room/helper.go @@ -2,13 +2,13 @@ DESCRIPTION: Any functions that are used internally by the use-case */ -package room +package procedureroom import ( - e "simrs-vx/internal/domain/main-entities/room" + e "simrs-vx/internal/domain/main-entities/procedure-room" ) -func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Room) { +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.ProcedureRoom) { var inputSrc *e.CreateDto if inputT, ok := any(input).(*e.CreateDto); ok { inputSrc = inputT @@ -17,6 +17,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Room) { inputSrc = &inputTemp.CreateDto } + data.Code = *inputSrc.Infra_Code data.Infra_Code = inputSrc.Infra_Code data.Unit_Code = inputSrc.Unit_Code data.Specialist_Code = inputSrc.Specialist_Code diff --git a/internal/use-case/main-use-case/room/lib.go b/internal/use-case/main-use-case/procedure-room/lib.go similarity index 84% rename from internal/use-case/main-use-case/room/lib.go rename to internal/use-case/main-use-case/procedure-room/lib.go index 5e586248..f9e46d17 100644 --- a/internal/use-case/main-use-case/room/lib.go +++ b/internal/use-case/main-use-case/procedure-room/lib.go @@ -1,7 +1,7 @@ -package room +package procedureroom import ( - e "simrs-vx/internal/domain/main-entities/room" + e "simrs-vx/internal/domain/main-entities/procedure-room" plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" @@ -12,10 +12,10 @@ import ( "gorm.io/gorm" ) -func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Room, error) { +func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.ProcedureRoom, error) { pl.SetLogInfo(event, nil, "started", "DBCreate") - data := e.Room{} + data := e.ProcedureRoom{} setData(&input, &data) var tx *gorm.DB @@ -33,9 +33,9 @@ func CreateData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*e.Room, e return &data, nil } -func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Room, *e.MetaDto, error) { +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.ProcedureRoom, *e.MetaDto, error) { pl.SetLogInfo(event, input, "started", "DBReadList") - data := []e.Room{} + data := []e.ProcedureRoom{} pagination := gh.Pagination{} count := int64(0) meta := e.MetaDto{} @@ -48,7 +48,7 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ro } tx = tx. - Model(&e.Room{}). + Model(&e.ProcedureRoom{}). Scopes(gh.Preload(input.Includes)). Scopes(gh.Filter(input.FilterDto)). Count(&count). @@ -70,9 +70,9 @@ func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Ro return data, &meta, nil } -func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Room, error) { +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.ProcedureRoom, error) { pl.SetLogInfo(event, input, "started", "DBReadDetail") - data := e.Room{} + data := e.ProcedureRoom{} var tx *gorm.DB if len(dbx) > 0 { @@ -91,7 +91,7 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e return &data, nil } -func UpdateData(input e.UpdateDto, data *e.Room, event *pl.Event, dbx ...*gorm.DB) error { +func UpdateData(input e.UpdateDto, data *e.ProcedureRoom, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, data, "started", "DBUpdate") setData(&input, data) @@ -116,7 +116,7 @@ func UpdateData(input e.UpdateDto, data *e.Room, event *pl.Event, dbx ...*gorm.D return nil } -func DeleteData(data *e.Room, event *pl.Event, dbx ...*gorm.DB) error { +func DeleteData(data *e.ProcedureRoom, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB if len(dbx) > 0 { diff --git a/internal/use-case/main-use-case/procedure-room/middleware-runner.go b/internal/use-case/main-use-case/procedure-room/middleware-runner.go new file mode 100644 index 00000000..bc96f5c6 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room/middleware-runner.go @@ -0,0 +1,103 @@ +package procedureroom + +import ( + e "simrs-vx/internal/domain/main-entities/procedure-room" + 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.ProcedureRoom) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoom) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoom) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoom) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.ProcedureRoom) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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-room/middleware.go b/internal/use-case/main-use-case/procedure-room/middleware.go new file mode 100644 index 00000000..c30fa7b1 --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room/middleware.go @@ -0,0 +1,9 @@ +package procedureroom + +// 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-room/tycovar.go b/internal/use-case/main-use-case/procedure-room/tycovar.go new file mode 100644 index 00000000..ab9f660b --- /dev/null +++ b/internal/use-case/main-use-case/procedure-room/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 procedureroom + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/procedure-room" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.ProcedureRoom, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.ProcedureRoom, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.ProcedureRoom, 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/registrator/case.go b/internal/use-case/main-use-case/registrator/case.go new file mode 100644 index 00000000..64313b97 --- /dev/null +++ b/internal/use-case/main-use-case/registrator/case.go @@ -0,0 +1,276 @@ +package registrator + +import ( + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/registrator" + + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" +) + +const source = "registrator" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Registrator{} + + 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.Registrator + var dataList []e.Registrator + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Registrator + 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.Registrator + 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.Registrator + 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/registrator/helper.go b/internal/use-case/main-use-case/registrator/helper.go new file mode 100644 index 00000000..68482b0b --- /dev/null +++ b/internal/use-case/main-use-case/registrator/helper.go @@ -0,0 +1,22 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package registrator + +import ( + e "simrs-vx/internal/domain/main-entities/registrator" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Registrator) { + 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.Installation_Code = inputSrc.Installation_Code +} diff --git a/internal/use-case/main-use-case/registrator/lib.go b/internal/use-case/main-use-case/registrator/lib.go new file mode 100644 index 00000000..694f9441 --- /dev/null +++ b/internal/use-case/main-use-case/registrator/lib.go @@ -0,0 +1,179 @@ +package registrator + +import ( + "fmt" + e "simrs-vx/internal/domain/main-entities/registrator" + + plh "simrs-vx/pkg/lib-helper" + 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.Registrator, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Registrator{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Registrator, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Registrator{} + 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.Registrator{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + 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, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Registrator, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Registrator{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if input.Employee_Id != nil { + tx = tx.Where("\"Employee_Id\" = ?", *input.Employee_Id) + } + if input.Id != nil { + tx = tx.Where("\"Id\" = ?", input.Id) + } + fmt.Println(input.Includes) + if err := tx.Scopes(gh.Preload(input.Includes)).First(&data).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.Registrator, 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.Registrator, 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 +} + +func GetIdByUserId(user_id *uint, event *pl.Event, dbx ...*gorm.DB) (*uint, error) { + pl.SetLogInfo(event, nil, "started", "DBGetIdByUserId") + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + var registrator_id uint + + err := tx.Model(&e.Registrator{}). + Select("\"Doctor\".\"Id\" as registrator_id"). + Joins("JOIN \"Employee\" as e ON e.\"Id\" = \"Doctor\".\"Employee_Id\""). + Where("e.\"User_Id\" = ?", user_id). + Scan(®istrator_id).Error + + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-get-fail", + Detail: "Database get failed", + Raw: err, + } + return nil, pl.SetLogError(event, user_id) + } + + pl.SetLogInfo(event, nil, "complete") + return ®istrator_id, nil +} diff --git a/internal/use-case/main-use-case/registrator/middleware-runner.go b/internal/use-case/main-use-case/registrator/middleware-runner.go new file mode 100644 index 00000000..e0488ca7 --- /dev/null +++ b/internal/use-case/main-use-case/registrator/middleware-runner.go @@ -0,0 +1,103 @@ +package registrator + +import ( + e "simrs-vx/internal/domain/main-entities/registrator" + 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.Registrator) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Registrator) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Registrator) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Registrator) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Registrator) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/registrator/middleware.go b/internal/use-case/main-use-case/registrator/middleware.go new file mode 100644 index 00000000..c47ed8e0 --- /dev/null +++ b/internal/use-case/main-use-case/registrator/middleware.go @@ -0,0 +1,9 @@ +package registrator + +// 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/registrator/tycovar.go b/internal/use-case/main-use-case/registrator/tycovar.go new file mode 100644 index 00000000..565e186f --- /dev/null +++ b/internal/use-case/main-use-case/registrator/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 registrator + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/registrator" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Registrator, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Registrator, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Registrator, 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/resume/case.go b/internal/use-case/main-use-case/resume/case.go new file mode 100644 index 00000000..8f771794 --- /dev/null +++ b/internal/use-case/main-use-case/resume/case.go @@ -0,0 +1,391 @@ +package resume + +import ( + "errors" + "strconv" + + erc "simrs-vx/internal/domain/references/common" + + // main entities + ee "simrs-vx/internal/domain/main-entities/encounter" + e "simrs-vx/internal/domain/main-entities/resume" + + ue "simrs-vx/internal/use-case/main-use-case/encounter" + + 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" +) + +const source = "resume" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Resume{} + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + if !input.AuthInfo.IsDoctor() { + return errors.New("user is not a doctor") + } + + mwRunner := newMiddlewareRunner(&event, tx) + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { + return err + } + + // check if encounter is done + if ue.IsDone(*input.Encounter_Id, &event, tx) { + return errors.New("encounter is already done") + } + + if resData, err := CreateData(input, &event, tx); err != nil { + return err + } else { + 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.Resume + var dataList []e.Resume + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Resume + 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.Resume + 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 { + if !input.AuthInfo.IsDoctor() { + return errors.New("user is not a doctor") + } + + 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 + } + + // check if encounter is done + if ue.IsDone(*input.Encounter_Id, &event, tx) { + return errors.New("encounter is already done") + } + + if err := UpdateData(input, data, &event, tx); err != nil { + return err + } + + // Get Updated Data + if data, err = ReadDetailData(rdDto, &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: uint(input.Id)} + var data *e.Resume + 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 { + if !input.AuthInfo.IsDoctor() { + return errors.New("user is not a doctor") + } + + 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 + +} + +func UpdateStatusCode(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Resume + var err error + + event := pl.Event{ + Feature: "UpdateStatusCode", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "updateStatusCode") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + if !input.AuthInfo.IsDoctor() { + return errors.New("user is not a doctor") + } + + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + if data, err = ReadDetailData(rdDto, &event, tx); err != nil { + return err + } + + enc, err := ue.ReadDetailData(ee.ReadDetailDto{Id: *data.Encounter_Id}, &event, tx) + if err != nil { + return err + } + + // check if encounter is done + if enc.IsDone() { + return errors.New("encounter is already done") + } + + switch input.Status_Code { + case erc.DVCValidated: + if data.IsNew() { + return errors.New("resume need to be verified first") + } + if data.IsValidated() { + return errors.New("resume already validated") + } + if !enc.IsSameResponsibleDoctor(input.AuthInfo.Doctor_Code) { + return errors.New("validation doctor is not the same as encounter responsible doctor") + } + + data.Status_Code = erc.DVCValidated + err = tx.Save(&data).Error + if err != nil { + return err + } + case erc.DVCVerified: + if data.IsValidated() { + return errors.New("resume already validated") + } + if data.IsVerified() { + return errors.New("resume already verified") + } + data.Status_Code = erc.DVCVerified + err = tx.Save(&data).Error + if 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 +} diff --git a/internal/use-case/main-use-case/resume/helper.go b/internal/use-case/main-use-case/resume/helper.go new file mode 100644 index 00000000..794ae214 --- /dev/null +++ b/internal/use-case/main-use-case/resume/helper.go @@ -0,0 +1,26 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package resume + +import ( + e "simrs-vx/internal/domain/main-entities/resume" + + erc "simrs-vx/internal/domain/references/common" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Resume) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + data.Status_Code = erc.DVCNew + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Doctor_Code = inputSrc.AuthInfo.Doctor_Code + data.Value = inputSrc.Value +} diff --git a/internal/use-case/main-use-case/resume/lib.go b/internal/use-case/main-use-case/resume/lib.go new file mode 100644 index 00000000..02a2e27a --- /dev/null +++ b/internal/use-case/main-use-case/resume/lib.go @@ -0,0 +1,140 @@ +package resume + +import ( + "errors" + e "simrs-vx/internal/domain/main-entities/resume" + plh "simrs-vx/pkg/lib-helper" + 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.Resume, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Resume{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Resume, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Resume{} + 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.Resume{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Find(&data).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Resume, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Resume{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Scopes(gh.Preload(input.Includes)).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.Resume, 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.Resume, 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/resume/middleware-runner.go b/internal/use-case/main-use-case/resume/middleware-runner.go new file mode 100644 index 00000000..e7f4cade --- /dev/null +++ b/internal/use-case/main-use-case/resume/middleware-runner.go @@ -0,0 +1,103 @@ +package resume + +import ( + e "simrs-vx/internal/domain/main-entities/resume" + 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.Resume) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Resume) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Resume) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Resume) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Resume) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/upload/middleware.go b/internal/use-case/main-use-case/resume/middleware.go similarity index 93% rename from internal/use-case/main-use-case/upload/middleware.go rename to internal/use-case/main-use-case/resume/middleware.go index 63beb606..dc0aa8c9 100644 --- a/internal/use-case/main-use-case/upload/middleware.go +++ b/internal/use-case/main-use-case/resume/middleware.go @@ -1,4 +1,4 @@ -package upload +package resume // example of middleware // func init() { diff --git a/internal/use-case/main-use-case/resume/tycovar.go b/internal/use-case/main-use-case/resume/tycovar.go new file mode 100644 index 00000000..13f36d2a --- /dev/null +++ b/internal/use-case/main-use-case/resume/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 resume + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/resume" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Resume, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Resume, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Resume, 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/screening/case.go b/internal/use-case/main-use-case/screening/case.go new file mode 100644 index 00000000..f6673450 --- /dev/null +++ b/internal/use-case/main-use-case/screening/case.go @@ -0,0 +1,320 @@ +package screening + +import ( + "errors" + "strconv" + + e "simrs-vx/internal/domain/main-entities/screening" + + erc "simrs-vx/internal/domain/references/clinical" + + 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 = "screening" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Screening{} + + 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 !pu.Contains([]erc.ScreeningFormTypeCode{erc.SFTCB, erc.SFTCA}, input.Type) { + return errors.New("invalid screening form type") + } + + if !input.AuthInfo.IsScreener() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: "user position is not allowed", + Raw: errors.New("authentication failed"), + } + return pl.SetLogError(&event, input) + } + + if input.AuthInfo.Employee_Id != nil { + v := uint(*input.AuthInfo.Employee_Id) + input.Employee_Id = &v + } else { + input.Employee_Id = nil + } + + switch input.Type { + case erc.SFTCA: + s, _, err := ReadListData(e.ReadListDto{FilterDto: e.FilterDto{Type: erc.SFTCA}}, &event, tx) + if err != nil { + return err + } + if len(s) > 0 { + return errors.New("screening form type A is already created for this encounter") + } + case erc.SFTCB: + s, _, err := ReadListData(e.ReadListDto{FilterDto: e.FilterDto{Type: erc.SFTCA}}, &event, tx) + if err != nil { + return err + } + if len(s) < 1 { + return errors.New("screening form type A is not created yet, please create it first") + } + } + + 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.Screening + var dataList []e.Screening + 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), + "record_currentCount": strconv.Itoa(len(dataList)), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Screening + 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.Screening + 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.Screening + 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/screening/helper.go b/internal/use-case/main-use-case/screening/helper.go new file mode 100644 index 00000000..94692281 --- /dev/null +++ b/internal/use-case/main-use-case/screening/helper.go @@ -0,0 +1,26 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package screening + +import ( + e "simrs-vx/internal/domain/main-entities/screening" + erc "simrs-vx/internal/domain/references/common" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Screening) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + data.Status = erc.DVCValidated + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Encounter_Id = inputSrc.Encounter_Id + data.Employee_Id = inputSrc.Employee_Id + data.Type = inputSrc.Type + data.Value = inputSrc.Value +} diff --git a/internal/use-case/main-use-case/screening/lib.go b/internal/use-case/main-use-case/screening/lib.go new file mode 100644 index 00000000..31ed6ee1 --- /dev/null +++ b/internal/use-case/main-use-case/screening/lib.go @@ -0,0 +1,140 @@ +package screening + +import ( + e "simrs-vx/internal/domain/main-entities/screening" + + plh "simrs-vx/pkg/lib-helper" + 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.Screening, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := e.Screening{} + 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 { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListData(input e.ReadListDto, event *pl.Event, dbx ...*gorm.DB) ([]e.Screening, *e.MetaDto, error) { + pl.SetLogInfo(event, input, "started", "DBReadList") + data := []e.Screening{} + 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.Screening{}). + Scopes(gh.Preload(input.Includes)). + Scopes(gh.Filter(input.FilterDto)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Scopes(gh.Sort(input.Sort)) + + if err := tx.Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, plh.HandleListError(input, event, err) + } + + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + + pl.SetLogInfo(event, nil, "complete") + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e.Screening, error) { + pl.SetLogInfo(event, input, "started", "DBReadDetail") + data := e.Screening{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Scopes(gh.Preload(input.Includes)).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.Screening, 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.Screening, 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/screening/middleware-runner.go b/internal/use-case/main-use-case/screening/middleware-runner.go new file mode 100644 index 00000000..9eb1b4a2 --- /dev/null +++ b/internal/use-case/main-use-case/screening/middleware-runner.go @@ -0,0 +1,103 @@ +package screening + +import ( + e "simrs-vx/internal/domain/main-entities/screening" + 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.Screening) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Screening) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Screening) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Screening) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Screening) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/screening/middleware.go b/internal/use-case/main-use-case/screening/middleware.go new file mode 100644 index 00000000..6ec8140c --- /dev/null +++ b/internal/use-case/main-use-case/screening/middleware.go @@ -0,0 +1,9 @@ +package screening + +// 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/screening/tycovar.go b/internal/use-case/main-use-case/screening/tycovar.go new file mode 100644 index 00000000..481f3d3e --- /dev/null +++ b/internal/use-case/main-use-case/screening/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 screening + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/screening" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Screening, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Screening, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Screening, 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/soapi/case.go b/internal/use-case/main-use-case/soapi/case.go index 3dc8e195..ebf1c7d8 100644 --- a/internal/use-case/main-use-case/soapi/case.go +++ b/internal/use-case/main-use-case/soapi/case.go @@ -2,6 +2,8 @@ package soapi import ( "errors" + erc "simrs-vx/internal/domain/references/common" + esync "simrs-vx/internal/domain/sync-entities/log" "strconv" e "simrs-vx/internal/domain/main-entities/soapi" @@ -27,53 +29,50 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event, input.Sync) + + if !input.AuthInfo.IsDoctor() && !input.AuthInfo.IsNurse() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "auth-forbidden", + Detail: "user position is not allowed", + Raw: errors.New("authentication failed"), + } + return nil, pl.SetLogError(&event, input) + } 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 !input.AuthInfo.IsDoctor() && !input.AuthInfo.IsNurse() { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "auth-forbidden", - Detail: "user position is not allowed", - Raw: errors.New("authentication failed"), - } - return pl.SetLogError(&event, input) - } - - if input.AuthInfo.Employee_Id != nil { - v := uint(*input.AuthInfo.Employee_Id) - input.Employee_Id = &v - } else { - input.Employee_Id = nil - } - 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 { + // get detail for sync + soapiData, err := ReadDetailData(e.ReadDetailDto{ + Id: data.Id, + Includes: "Encounter,Employee.User"}, &event, tx) + if err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err = mwRunner.ExecuteIfSyncOn(func() error { + return mwRunner.RunCreateMiddleware(createPreMw, soapiData) + }); err != nil { + return err + } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, erc.CCCreate, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -85,7 +84,6 @@ func Create(input e.CreateDto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Soapi var dataList []e.Soapi var metaList *e.MetaDto var err error @@ -99,23 +97,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -150,23 +134,9 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -196,6 +166,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event, input.Sync) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -203,32 +174,35 @@ func Update(input e.UpdateDto) (*d.Data, error) { 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") + // get detail for sync + soapiData, err := ReadDetailData(e.ReadDetailDto{ + Id: data.Id, + Includes: "Encounter,Employee"}, &event) + if err != nil { + return err + } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err = mwRunner.ExecuteIfSyncOn(func() error { + return mwRunner.RunUpdateMiddleware(updatePreMw, soapiData) + }); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, erc.CCUpdate, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -252,6 +226,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event, input.Sync) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -259,30 +234,27 @@ func Delete(input e.DeleteDto) (*d.Data, error) { 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 { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err = mwRunner.ExecuteIfSyncOn(func() error { + return mwRunner.RunDeleteMiddleware(deletePreMw, &input) + }); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, erc.CCDelete, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -293,3 +265,39 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, method erc.CrudCode, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: method, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.ExecuteIfSyncOn(func() error { + return mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog) + }); errMiddleware != nil { + return errMiddleware + } + + return err + } + + // create log success + inputLog.IsSuccess = true + err = mwRunner.ExecuteIfSyncOn(func() error { + return mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog) + }) + + if err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/soapi/helper.go b/internal/use-case/main-use-case/soapi/helper.go index ae396270..c42b95d0 100644 --- a/internal/use-case/main-use-case/soapi/helper.go +++ b/internal/use-case/main-use-case/soapi/helper.go @@ -18,7 +18,7 @@ func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Soapi) { } data.Encounter_Id = inputSrc.Encounter_Id - data.Employee_Id = inputSrc.Employee_Id + data.Employee_Id = inputSrc.AuthInfo.Employee_Id data.Time = inputSrc.Time data.TypeCode = inputSrc.TypeCode data.Value = inputSrc.Value diff --git a/internal/use-case/main-use-case/soapi/lib.go b/internal/use-case/main-use-case/soapi/lib.go index 57bb5d23..85e94800 100644 --- a/internal/use-case/main-use-case/soapi/lib.go +++ b/internal/use-case/main-use-case/soapi/lib.go @@ -81,7 +81,9 @@ func ReadDetailData(input e.ReadDetailDto, event *pl.Event, dbx ...*gorm.DB) (*e tx = dg.I } - if err := tx.First(&data, input.Id).Error; err != nil { + if err := tx. + Scopes(gh.Preload(input.Includes)). + First(&data, input.Id).Error; err != nil { if processedErr := pu.HandleReadError(err, event, source, input.Id, data); processedErr != nil { return nil, processedErr } diff --git a/internal/use-case/main-use-case/soapi/middleware-runner.go b/internal/use-case/main-use-case/soapi/middleware-runner.go index a840a33a..fbe18503 100644 --- a/internal/use-case/main-use-case/soapi/middleware-runner.go +++ b/internal/use-case/main-use-case/soapi/middleware-runner.go @@ -2,6 +2,8 @@ package soapi import ( e "simrs-vx/internal/domain/main-entities/soapi" + esync "simrs-vx/internal/domain/sync-entities/log" + sync "simrs-vx/internal/infra/sync-consumer-cfg" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" @@ -12,24 +14,45 @@ type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event, syncFromOldSource bool) *middlewareRunner { + activateSync := sync.O.Enable + if syncFromOldSource { + activateSync = false + } + return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: activateSync, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Soapi) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.Soapi) error { for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -68,13 +91,13 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Soapi) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.Soapi) error { for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +106,13 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Soapi) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -101,3 +124,10 @@ func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, inpu func (me *middlewareRunner) setMwType(mwType pu.MWType) { me.MwType = mwType } + +func (me *middlewareRunner) ExecuteIfSyncOn(fn func() error) error { + if !me.SyncOn { + return nil + } + return fn() +} diff --git a/internal/use-case/main-use-case/soapi/middleware.go b/internal/use-case/main-use-case/soapi/middleware.go index f2fecda5..548d27fd 100644 --- a/internal/use-case/main-use-case/soapi/middleware.go +++ b/internal/use-case/main-use-case/soapi/middleware.go @@ -1,9 +1,17 @@ package soapi -// example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +import plugin "simrs-vx/internal/use-case/simgos-sync-plugin/new/soapi" + +func init() { + createPreMw = append(createPreMw, + createMw{Name: "sync-create-soapi", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-sync-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "sync-update-soapi", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "sync-delete-soapi", Func: plugin.Delete}) +} diff --git a/internal/use-case/main-use-case/soapi/tycovar.go b/internal/use-case/main-use-case/soapi/tycovar.go index 956193a4..aece45a5 100644 --- a/internal/use-case/main-use-case/soapi/tycovar.go +++ b/internal/use-case/main-use-case/soapi/tycovar.go @@ -12,11 +12,27 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/soapi" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Soapi, tx *gorm.DB) error + Func func(input *e.Soapi) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.Soapi) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,8 +45,8 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Soapi, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw var createPreMw []createMw // preprocess middleware var createPostMw []createMw // postprocess middleware @@ -38,7 +54,8 @@ var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw +var createSimxLogMw []createLogMw diff --git a/internal/use-case/main-use-case/specialist/case.go b/internal/use-case/main-use-case/specialist/case.go index c51a0002..f9f5442b 100644 --- a/internal/use-case/main-use-case/specialist/case.go +++ b/internal/use-case/main-use-case/specialist/case.go @@ -1,7 +1,6 @@ package specialist import ( - e "simrs-vx/internal/domain/main-entities/specialist" "strconv" dg "github.com/karincake/apem/db-gorm-pg" @@ -11,6 +10,11 @@ import ( pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/specialist" + esync "simrs-vx/internal/domain/sync-entities/log" ) const source = "specialist" @@ -25,36 +29,32 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event) 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 + id := uint(data.Id) + input.Id = &id } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -80,7 +80,7 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { @@ -131,7 +131,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { @@ -177,6 +177,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -184,32 +185,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -233,6 +228,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -240,30 +236,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -274,3 +266,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/specialist/middleware-runner.go b/internal/use-case/main-use-case/specialist/middleware-runner.go index 4aa6cdd4..e2799b61 100644 --- a/internal/use-case/main-use-case/specialist/middleware-runner.go +++ b/internal/use-case/main-use-case/specialist/middleware-runner.go @@ -1,35 +1,64 @@ package specialist import ( - e "simrs-vx/internal/domain/main-entities/specialist" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/specialist" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Specialist) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +// ExecuteCreateMiddleware executes createlog middleware +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +68,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Specialist) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +87,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Specialist) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +105,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Specialist) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +124,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Specialist) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/specialist/middleware.go b/internal/use-case/main-use-case/specialist/middleware.go index 298e51a8..74ba8e78 100644 --- a/internal/use-case/main-use-case/specialist/middleware.go +++ b/internal/use-case/main-use-case/specialist/middleware.go @@ -1,9 +1,20 @@ package specialist +import ( + plugin "simrs-vx/internal/use-case/simgos-sync-plugin/new/specialist" +) + // example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +func init() { + createPreMw = append(createPreMw, + createMw{Name: "sync-create-specialist", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-sync-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "sync-update-specialiast", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "sync-delete-specialist", Func: plugin.Delete}) +} diff --git a/internal/use-case/main-use-case/specialist/tycovar.go b/internal/use-case/main-use-case/specialist/tycovar.go index 16fa50b0..d0755799 100644 --- a/internal/use-case/main-use-case/specialist/tycovar.go +++ b/internal/use-case/main-use-case/specialist/tycovar.go @@ -12,11 +12,27 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/specialist" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Specialist, tx *gorm.DB) error + Func func(input *e.CreateDto) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,16 +45,17 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Specialist, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/subspecialist/case.go b/internal/use-case/main-use-case/subspecialist/case.go index 51509c47..ca99750d 100644 --- a/internal/use-case/main-use-case/subspecialist/case.go +++ b/internal/use-case/main-use-case/subspecialist/case.go @@ -2,6 +2,8 @@ package subspecialist import ( e "simrs-vx/internal/domain/main-entities/subspecialist" + erc "simrs-vx/internal/domain/references/common" + esync "simrs-vx/internal/domain/sync-entities/log" "strconv" dg "github.com/karincake/apem/db-gorm-pg" @@ -25,36 +27,32 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event) 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 + id := uint(data.Id) + input.Id = &id } - mwRunner.setMwType(pu.MWTPost) + mwRunner.setMwType(pu.MWTPre) // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -80,7 +78,7 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { @@ -131,7 +129,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { @@ -177,6 +175,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -184,32 +183,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) + mwRunner.setMwType(pu.MWTPre) // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -233,6 +226,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -240,30 +234,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) + mwRunner.setMwType(pu.MWTPre) // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -274,3 +264,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/subspecialist/middleware-runner.go b/internal/use-case/main-use-case/subspecialist/middleware-runner.go index c7e5f285..3e5c0dce 100644 --- a/internal/use-case/main-use-case/subspecialist/middleware-runner.go +++ b/internal/use-case/main-use-case/subspecialist/middleware-runner.go @@ -1,35 +1,63 @@ package subspecialist import ( - e "simrs-vx/internal/domain/main-entities/subspecialist" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/subspecialist" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Subspecialist) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +67,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Subspecialist) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +86,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Subspecialist) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +104,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Subspecialist) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +123,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Subspecialist) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/subspecialist/tycovar.go b/internal/use-case/main-use-case/subspecialist/tycovar.go index ed4540b8..cd26e517 100644 --- a/internal/use-case/main-use-case/subspecialist/tycovar.go +++ b/internal/use-case/main-use-case/subspecialist/tycovar.go @@ -9,6 +9,8 @@ functionality. The purpose of this is to make the code more maintainable. package subspecialist import ( + elog "simrs-vx/internal/domain/sync-entities/log" + "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/subspecialist" @@ -16,7 +18,22 @@ import ( type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Subspecialist, tx *gorm.DB) error + Func func(input *e.CreateDto) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,16 +46,17 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Subspecialist, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/therapy-protocol/case.go b/internal/use-case/main-use-case/therapy-protocol/case.go index bc65325f..a332d675 100644 --- a/internal/use-case/main-use-case/therapy-protocol/case.go +++ b/internal/use-case/main-use-case/therapy-protocol/case.go @@ -1,6 +1,7 @@ package therapy_protocol import ( + "errors" "strconv" "gorm.io/gorm" @@ -15,6 +16,8 @@ import ( ee "simrs-vx/internal/domain/main-entities/encounter" e "simrs-vx/internal/domain/main-entities/therapy-protocol" + erc "simrs-vx/internal/domain/references/common" + ud "simrs-vx/internal/use-case/main-use-case/doctor" ue "simrs-vx/internal/use-case/main-use-case/encounter" ) @@ -45,6 +48,8 @@ func Create(input e.CreateDto) (*d.Data, error) { return err } + statusNew := erc.DVCNew + input.Status_Code = &statusNew if resData, err := CreateData(input, &event, tx); err != nil { return err } else { @@ -291,10 +296,70 @@ func Delete(input e.DeleteDto) (*d.Data, error) { } +func Verify(input e.VerifyDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.TherapyProtocol + var err error + + event := pl.Event{ + Feature: "Verify", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "verify") + + 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.IsNew() { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-state-mismatch", + Detail: "data is not new", + Raw: errors.New("data is not new"), + } + return pl.SetLogError(&event, input) + } + + data.Status_Code = &input.Status_Code + err = tx.Save(&data).Error + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(&event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "verify", + }, + Data: data.ToResponse(), + }, nil +} + func validateForeignKey(input e.CreateDto) error { // validate encounter if input.Encounter_Id != nil { - if _, err := ue.ReadDetail(ee.ReadDetailDto{Id: uint16(*input.Encounter_Id)}); err != nil { + if _, err := ue.ReadDetail(ee.ReadDetailDto{Id: *input.Encounter_Id}); err != nil { return err } } diff --git a/internal/use-case/main-use-case/unit-position/case.go b/internal/use-case/main-use-case/unit-position/case.go index 47ea67cd..c472e90c 100644 --- a/internal/use-case/main-use-case/unit-position/case.go +++ b/internal/use-case/main-use-case/unit-position/case.go @@ -290,7 +290,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { func validateForeignKey(input e.CreateDto) error { // validate installation_id - if _, err := uu.ReadDetail(eu.ReadDetailDto{Code: &input.Code}); err != nil { + if _, err := uu.ReadDetail(eu.ReadDetailDto{Code: input.Unit_Code}); err != nil { return err } diff --git a/internal/use-case/main-use-case/unit/case.go b/internal/use-case/main-use-case/unit/case.go index 650c4511..c73c2c1d 100644 --- a/internal/use-case/main-use-case/unit/case.go +++ b/internal/use-case/main-use-case/unit/case.go @@ -1,7 +1,10 @@ package unit import ( + "errors" e "simrs-vx/internal/domain/main-entities/unit" + erc "simrs-vx/internal/domain/references/common" + esync "simrs-vx/internal/domain/sync-entities/log" "strconv" dg "github.com/karincake/apem/db-gorm-pg" @@ -26,35 +29,44 @@ func Create(input e.CreateDto) (*d.Data, error) { // 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 + // validate unit_code + _, err := strconv.Atoi(input.Code) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "invalid_code_format", + Detail: "unit_code must be a valid integer", + Raw: errors.New("invalid unit_code format"), } + return nil, pl.SetLogError(&event, input) + } + mwRunner := newMiddlewareRunner(&event) + + err = dg.I.Transaction(func(tx *gorm.DB) error { if resData, err := CreateData(input, &event, tx); err != nil { return err } else { data = *resData + id := uint(data.Id) + input.Id = &id } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -66,7 +78,6 @@ func Create(input e.CreateDto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Unit var dataList []e.Unit var metaList *e.MetaDto var err error @@ -80,23 +91,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -131,23 +128,9 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, 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 }) @@ -177,6 +160,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -184,32 +168,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -233,6 +211,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -240,30 +219,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -274,3 +249,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/unit/middleware-runner.go b/internal/use-case/main-use-case/unit/middleware-runner.go index fdce9d02..a02bb9cf 100644 --- a/internal/use-case/main-use-case/unit/middleware-runner.go +++ b/internal/use-case/main-use-case/unit/middleware-runner.go @@ -1,35 +1,64 @@ 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" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/unit" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Unit) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +68,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Unit) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +87,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +105,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +124,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/unit/middleware.go b/internal/use-case/main-use-case/unit/middleware.go index bac48f4d..03ef2c19 100644 --- a/internal/use-case/main-use-case/unit/middleware.go +++ b/internal/use-case/main-use-case/unit/middleware.go @@ -1,9 +1,20 @@ package unit +import ( + plugin "simrs-vx/internal/use-case/simgos-sync-plugin/new/unit" +) + // example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +func init() { + createPreMw = append(createPreMw, + createMw{Name: "sync-create-unit", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-sync-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "sync-update-unit", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "sync-delete-unit", Func: plugin.Delete}) +} diff --git a/internal/use-case/main-use-case/unit/tycovar.go b/internal/use-case/main-use-case/unit/tycovar.go index e1a7c69f..bf717333 100644 --- a/internal/use-case/main-use-case/unit/tycovar.go +++ b/internal/use-case/main-use-case/unit/tycovar.go @@ -12,11 +12,27 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/unit" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Unit, tx *gorm.DB) error + Func func(input *e.CreateDto) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,16 +45,17 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/upload-file/case.go b/internal/use-case/main-use-case/upload-file/case.go new file mode 100644 index 00000000..20d000dc --- /dev/null +++ b/internal/use-case/main-use-case/upload-file/case.go @@ -0,0 +1,76 @@ +package uploadfile + +import ( + "errors" + pl "simrs-vx/pkg/logger" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + "gorm.io/gorm" + + ere "simrs-vx/internal/domain/references/encounter" +) + +const source = "upload-file" + +func Upload(input CreateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Upload", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + var ( + err error + ) + err = dg.I.Transaction(func(tx *gorm.DB) error { + // validate entityType_Code and Type_Code + valid, msg := ere.IsValidUploadCode(input.EntityType_Code, input.Type_Code) + if !valid { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "invalid-code", + Detail: msg, + Raw: errors.New(msg), + } + return pl.SetLogError(&event, input) + } + + // upload file + input.FilePath, err = uploadAndGenerateFileUrl(input, &event) + if err != nil { + return err + } + + if input.EntityType_Code == ere.ETCEncounter { + _, err = setEncounterDocument(input, &event, tx) + if err != nil { + return err + } + + } else if input.EntityType_Code == ere.ETCPerson { + _, err = setPersonAttachment(input, &event, tx) + } + + 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: d.IS{ + "fileUrl": input.FilePath, + }, + }, nil +} diff --git a/internal/use-case/main-use-case/upload/helper.go b/internal/use-case/main-use-case/upload-file/helper.go similarity index 78% rename from internal/use-case/main-use-case/upload/helper.go rename to internal/use-case/main-use-case/upload-file/helper.go index 652d80fa..176de93f 100644 --- a/internal/use-case/main-use-case/upload/helper.go +++ b/internal/use-case/main-use-case/upload-file/helper.go @@ -2,13 +2,13 @@ DESCRIPTION: Any functions that are used internally by the use-case */ -package upload +package uploadfile import ( "fmt" "path/filepath" ecore "simrs-vx/internal/domain/base-entities/core" - eru "simrs-vx/internal/domain/references/upload" + ere "simrs-vx/internal/domain/references/encounter" "strings" "time" @@ -21,13 +21,12 @@ import ( ee "simrs-vx/internal/domain/main-entities/encounter-document" ep "simrs-vx/internal/domain/main-entities/person" - e "simrs-vx/internal/domain/main-entities/upload" ue "simrs-vx/internal/use-case/main-use-case/encounter-document" up "simrs-vx/internal/use-case/main-use-case/person" ) -func uploadAndGenerateFileUrl(input e.CreateDto, event *pl.Event) (string, error) { +func uploadAndGenerateFileUrl(input CreateDto, event *pl.Event) (string, error) { pl.SetLogInfo(event, input, "started", "uploadAndGenerateFileUrl") bucket := string(input.EntityType_Code) ext := strings.ToLower(filepath.Ext(input.Filename)) @@ -97,7 +96,7 @@ func updatePersonAttachment(dataPerson *ep.Person, event *pl.Event, dbx ...*gorm return nil } -func setPersonAttachment(input e.CreateDto, event *pl.Event, tx *gorm.DB) (*ep.Person, error) { +func setPersonAttachment(input CreateDto, event *pl.Event, tx *gorm.DB) (*ep.Person, error) { // get person dataPerson, err := up.ReadDetailData(ep.ReadDetailDto{Id: *input.Ref_Id}, event, tx) if err != nil { @@ -106,22 +105,22 @@ func setPersonAttachment(input e.CreateDto, event *pl.Event, tx *gorm.DB) (*ep.P var removeUrl string switch input.Type_Code { - case eru.UCPRN: + case ere.DTCPRN: if dataPerson.ResidentIdentityFileUrl != nil { removeUrl = *dataPerson.ResidentIdentityFileUrl } dataPerson.ResidentIdentityFileUrl = &input.FilePath - case eru.UCPDL: + case ere.DTCPDL: if dataPerson.DrivingLicenseFileUrl != nil { removeUrl = *dataPerson.DrivingLicenseFileUrl } dataPerson.DrivingLicenseFileUrl = &input.FilePath - case eru.UCPP: + case ere.DTCPP: if dataPerson.PassportFileUrl != nil { removeUrl = *dataPerson.PassportFileUrl } dataPerson.PassportFileUrl = &input.FilePath - case eru.UCPFC: + case ere.DTCPFC: if dataPerson.FamilyIdentityFileUrl != nil { removeUrl = *dataPerson.FamilyIdentityFileUrl } @@ -141,7 +140,7 @@ func setPersonAttachment(input e.CreateDto, event *pl.Event, tx *gorm.DB) (*ep.P return dataPerson, nil } -func setEncounterDocument(input e.CreateDto, event *pl.Event, tx *gorm.DB) (*ee.EncounterDocument, error) { +func setEncounterDocument(input CreateDto, event *pl.Event, tx *gorm.DB) (*ee.EncounterDocument, error) { data := ee.EncounterDocument{} // get EncounterDocument @@ -164,29 +163,35 @@ func setEncounterDocument(input e.CreateDto, event *pl.Event, tx *gorm.DB) (*ee. Upload_Employee_Id: input.Upload_Employee_Id, } - if len(dataUpload) > 0 { - if err := removeUploadedFile(string(input.EntityType_Code), *dataUpload[0].FilePath, *dataUpload[0].Encounter_Id, event); err != nil { - return nil, err - } + if input.Type_Code == ere.DTCSEP || input.Type_Code == ere.DTCSIPP { + if len(dataUpload) > 0 { + data = dataUpload[0] - // update data - err = ue.UpdateData(ee.UpdateDto{ - Id: uint16(dataUpload[0].Id), - CreateDto: createDto}, &dataUpload[0], event, tx) - if err != nil { - return nil, err - } + // remove file + if err := removeUploadedFile(string(input.EntityType_Code), *data.FilePath, *data.Encounter_Id, event); err != nil { + return nil, err + } - data = dataUpload[0] - data.FilePath = &input.FilePath - } else { - // insert data - resData, err := ue.CreateData(createDto, event, tx) - if err != nil { - return nil, err + // update data + err = ue.UpdateData(ee.UpdateDto{ + Id: uint16(data.Id), + CreateDto: createDto}, &data, event, tx) + if err != nil { + return nil, err + } + + data.FilePath = &input.FilePath + + return &data, nil } - data = *resData } + // insert data + resData, err := ue.CreateData(createDto, event, tx) + if err != nil { + return nil, err + } + data = *resData + return &data, nil } diff --git a/internal/domain/main-entities/upload/dto.go b/internal/use-case/main-use-case/upload-file/tycovar.go similarity index 53% rename from internal/domain/main-entities/upload/dto.go rename to internal/use-case/main-use-case/upload-file/tycovar.go index ca8e101b..a5d63454 100644 --- a/internal/domain/main-entities/upload/dto.go +++ b/internal/use-case/main-use-case/upload-file/tycovar.go @@ -1,16 +1,22 @@ -package upload +/* +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 uploadfile import ( "mime/multipart" - eru "simrs-vx/internal/domain/references/upload" - // internal - domain - base-entities - ecore "simrs-vx/internal/domain/base-entities/core" + ere "simrs-vx/internal/domain/references/encounter" ) type CreateDto struct { - EntityType_Code eru.EntityTypeCode `form:"entityType_code"` + EntityType_Code ere.EntityTypeCode `form:"entityType_code"` Ref_Id *uint `form:"ref_id"` - Type_Code eru.UploadCode `form:"type_code"` + Type_Code ere.DocTypeCode `form:"type_code"` Name string `form:"name"` Upload_Employee_Id *uint `form:"upload_employee_id"` FilePath string `json:"-"` @@ -22,46 +28,10 @@ type CreateDto struct { MimeType string `json:"-"` } -type ReadListDto struct { - FilterDto - Includes string `json:"includes"` - Pagination ecore.Pagination -} - -type FilterDto struct { - EntityType_Code eru.EntityTypeCode `json:"entityType-code"` - Ref_Id *uint `json:"ref-id"` - Type_Code eru.UploadCode `json:"type-code"` - Name string `json:"name"` - FilePath *string `json:"filePath"` - FileName *string `json:"fileName"` - Upload_Employee_Id *string `json:"encounter-document-employee-id"` -} - -type ReadDetailDto struct { - Id uint16 `json:"id"` - Includes string `json:"includes"` -} - -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 { - EntityType_Code eru.EntityTypeCode `json:"entityType_code"` + EntityType_Code ere.EntityTypeCode `json:"entityType_code"` Ref_Id *uint `json:"ref_id"` - Type_Code eru.UploadCode `json:"type_code"` + Type_Code ere.DocTypeCode `json:"type_code"` Name string `json:"name"` Upload_Employee_Id *uint `json:"upload_employee_id"` FilePath string `json:"filePath"` diff --git a/internal/use-case/main-use-case/upload/case.go b/internal/use-case/main-use-case/upload/case.go deleted file mode 100644 index 40ff74f6..00000000 --- a/internal/use-case/main-use-case/upload/case.go +++ /dev/null @@ -1,90 +0,0 @@ -package upload - -import ( - "errors" - 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" - - eru "simrs-vx/internal/domain/references/upload" - - e "simrs-vx/internal/domain/main-entities/upload" -) - -const source = "upload" - -func Upload(input e.CreateDto) (*d.Data, error) { - event := pl.Event{ - Feature: "Upload", - Source: source, - } - - // Start log - pl.SetLogInfo(&event, input, "started", "create") - - var data interface{} - err := dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - - // Run pre-middleware - err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data) - if err != nil { - return err - } - - // validate entityType_Code and Type_Code - valid, msg := eru.IsValidUploadCode(input.EntityType_Code, input.Type_Code) - if !valid { - event.Status = "failed" - event.ErrInfo = pl.ErrorInfo{ - Code: "invalid-code", - Detail: msg, - Raw: errors.New(msg), - } - return pl.SetLogError(&event, input) - } - - // upload file - input.FilePath, err = uploadAndGenerateFileUrl(input, &event) - if err != nil { - return err - } - - if input.EntityType_Code == eru.ETCEncounter { - data, err = setEncounterDocument(input, &event, tx) - if err != nil { - return err - } - - } else if input.EntityType_Code == eru.ETCPerson { - data, err = setPersonAttachment(input, &event, tx) - } - - 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: input.ToResponse(), - }, nil -} diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index 7c66b153..1ea8c6ea 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -13,6 +13,7 @@ import ( en "simrs-vx/internal/domain/main-entities/nurse" et "simrs-vx/internal/domain/main-entities/nutritionist" ep "simrs-vx/internal/domain/main-entities/pharmacist" + er "simrs-vx/internal/domain/main-entities/registrator" esi "simrs-vx/internal/domain/main-entities/specialist-intern" e "simrs-vx/internal/domain/main-entities/user" @@ -26,6 +27,7 @@ import ( upa "simrs-vx/internal/use-case/main-use-case/person-address" upc "simrs-vx/internal/use-case/main-use-case/person-contact" up "simrs-vx/internal/use-case/main-use-case/pharmacist" + ur "simrs-vx/internal/use-case/main-use-case/registrator" usi "simrs-vx/internal/use-case/main-use-case/specialist-intern" erc "simrs-vx/internal/domain/references/common" @@ -166,6 +168,14 @@ func Create(input e.CreateDto) (*d.Data, error) { if _, err := umw.CreateData(createMidWife, &event, tx); err != nil { return err } + case ero.EPCReg, ero.EPCScr: + createSub := er.CreateDto{ + Employee_Id: employeeData.Id, + Installation_Code: *input.Installation_Code, + } + if _, err := ur.CreateData(createSub, &event, tx); err != nil { + return err + } default: return errors.New("invalid employee position") } @@ -521,6 +531,8 @@ func Update(input e.UpdateDto) (*d.Data, error) { if _, err := umw.CreateData(createMidWife, &event, tx); err != nil { return err } + case ero.EPCReg, ero.EPCScr: + // do nothing default: return errors.New("invalid employee position") } diff --git a/internal/use-case/main-use-case/user/helper.go b/internal/use-case/main-use-case/user/helper.go index acb32331..ed500bac 100644 --- a/internal/use-case/main-use-case/user/helper.go +++ b/internal/use-case/main-use-case/user/helper.go @@ -18,6 +18,7 @@ import ( ee "simrs-vx/internal/domain/main-entities/employee" esi "simrs-vx/internal/domain/main-entities/specialist-intern" e "simrs-vx/internal/domain/main-entities/user" + erc "simrs-vx/internal/domain/references/common" erg "simrs-vx/internal/domain/references/organization" ) @@ -29,7 +30,7 @@ func setCreate(src e.CreateDto, dst *e.User) error { dst.Name = src.Name dst.Password = pass - dst.Status_Code = src.Status_Code + dst.Status_Code = erc.USCActive dst.ContractPosition_Code = src.ContractPosition_Code return nil diff --git a/internal/use-case/simgos-sync-plugin/new/division/plugin.go b/internal/use-case/simgos-sync-plugin/new/division/plugin.go new file mode 100644 index 00000000..f4d6a34b --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/new/division/plugin.go @@ -0,0 +1,37 @@ +package division + +import ( + "fmt" + helper "simrs-vx/internal/use-case/simgos-sync-plugin/new" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/division" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +func Create(input *e.CreateDto) error { + return helper.DoJsonRequest(input, "POST", getPrefixEndpoint()) +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + return helper.DoJsonRequest(input, "POST", endpoint) +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "DELETE", endpoint) +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/division", sync.O.TargetHost, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/new/encounter/plugin.go b/internal/use-case/simgos-sync-plugin/new/encounter/plugin.go new file mode 100644 index 00000000..2f5e2515 --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/new/encounter/plugin.go @@ -0,0 +1,72 @@ +package encounter + +import ( + "fmt" + sync "simrs-vx/internal/infra/sync-consumer-cfg" + helper "simrs-vx/internal/use-case/simgos-sync-plugin/new" + + e "simrs-vx/internal/domain/main-entities/encounter" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +func Create(input *e.Encounter) error { + return helper.DoJsonRequest(input, "POST", getPrefixEndpoint()) +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + return helper.DoJsonRequest(input, "POST", endpoint) +} + +func Update(input *e.Encounter) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "DELETE", endpoint) +} + +func Checkin(input *e.Encounter) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v/checkin", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func Checkout(input *e.Encounter) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v/checkout", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func UpdateStatus(input *e.Encounter) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v/update-status", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func RequestSwitchUnit(input *e.Encounter) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v/req-switch-unit", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func ApproveSwitchUnit(input *e.ApproveCancelUnitDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v/approve-switch-unit", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func CancelSwitchUnit(input *e.ApproveCancelUnitDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v/cancel-switch-unit", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/encounter", sync.O.TargetHost, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/new/helper.go b/internal/use-case/simgos-sync-plugin/new/helper.go new file mode 100644 index 00000000..75f63d49 --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/new/helper.go @@ -0,0 +1,45 @@ +package new + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + d "github.com/karincake/dodol" +) + +func DoJsonRequest(input any, method, endpoint string) error { + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest(method, endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} diff --git a/internal/use-case/simgos-sync-plugin/new/installation/plugin.go b/internal/use-case/simgos-sync-plugin/new/installation/plugin.go new file mode 100644 index 00000000..40f0c153 --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/new/installation/plugin.go @@ -0,0 +1,37 @@ +package installation + +import ( + "fmt" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + helper "simrs-vx/internal/use-case/simgos-sync-plugin/new" + + e "simrs-vx/internal/domain/main-entities/installation" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +func Create(input *e.CreateDto) error { + return helper.DoJsonRequest(input, "POST", getPrefixEndpoint()) +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + return helper.DoJsonRequest(input, "POST", endpoint) +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "DELETE", endpoint) +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/installation", sync.O.TargetHost, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/new/patient/plugin.go b/internal/use-case/simgos-sync-plugin/new/patient/plugin.go new file mode 100644 index 00000000..7678da47 --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/new/patient/plugin.go @@ -0,0 +1,82 @@ +package patient + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + helper "simrs-vx/internal/use-case/simgos-sync-plugin/new" + + d "github.com/karincake/dodol" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/patient" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +func Create(input *e.Patient) error { + return helper.DoJsonRequest(input, "POST", getPrefixEndpoint()) +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + return helper.DoJsonRequest(input, "POST", endpoint) +} + +func Update(input *e.Patient) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "DELETE", endpoint) +} + +func GenerateNomrPatient() (*string, error) { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/nomr", prefixEndpoint) + + req, err := http.NewRequest("POST", endpoint, nil) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return nil, fmt.Errorf(errors.Message) + } + + var result map[string]any + if err = json.Unmarshal(bodyBytes, &result); err != nil { + return nil, err + } + + dataMap := result["data"].(map[string]any) + nomr := dataMap["nomr"].(string) + + return &nomr, nil +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/patient", sync.O.TargetHost, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/new/soapi/plugin.go b/internal/use-case/simgos-sync-plugin/new/soapi/plugin.go new file mode 100644 index 00000000..20fabfac --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/new/soapi/plugin.go @@ -0,0 +1,36 @@ +package soapi + +import ( + "fmt" + sync "simrs-vx/internal/infra/sync-consumer-cfg" + helper "simrs-vx/internal/use-case/simgos-sync-plugin/new" + + e "simrs-vx/internal/domain/main-entities/soapi" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +func Create(input *e.Soapi) error { + return helper.DoJsonRequest(input, "POST", getPrefixEndpoint()) +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + return helper.DoJsonRequest(input, "POST", endpoint) +} + +func Update(input *e.Soapi) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, input.Id) + return helper.DoJsonRequest(input, "DELETE", endpoint) +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/soapi", sync.O.TargetHost, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/new/specialist/plugin.go b/internal/use-case/simgos-sync-plugin/new/specialist/plugin.go new file mode 100644 index 00000000..29da9d0a --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/new/specialist/plugin.go @@ -0,0 +1,37 @@ +package specialist + +import ( + "fmt" + helper "simrs-vx/internal/use-case/simgos-sync-plugin/new" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/specialist" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +func Create(input *e.CreateDto) error { + return helper.DoJsonRequest(input, "POST", getPrefixEndpoint()) +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + return helper.DoJsonRequest(input, "POST", endpoint) +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "DELETE", endpoint) +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/specialist", sync.O.TargetHost, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/new/subspecialist/plugin.go b/internal/use-case/simgos-sync-plugin/new/subspecialist/plugin.go new file mode 100644 index 00000000..0167936c --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/new/subspecialist/plugin.go @@ -0,0 +1,37 @@ +package subspecialist + +import ( + "fmt" + helper "simrs-vx/internal/use-case/simgos-sync-plugin/new" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/subspecialist" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +func Create(input *e.CreateDto) error { + return helper.DoJsonRequest(input, "POST", getPrefixEndpoint()) +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + return helper.DoJsonRequest(input, "POST", endpoint) +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "DELETE", endpoint) +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/subspecialist", sync.O.TargetHost, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/new/unit/plugin.go b/internal/use-case/simgos-sync-plugin/new/unit/plugin.go new file mode 100644 index 00000000..f646f450 --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/new/unit/plugin.go @@ -0,0 +1,37 @@ +package unit + +import ( + "fmt" + helper "simrs-vx/internal/use-case/simgos-sync-plugin/new" + + sync "simrs-vx/internal/infra/sync-consumer-cfg" + + e "simrs-vx/internal/domain/main-entities/unit" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +func Create(input *e.CreateDto) error { + return helper.DoJsonRequest(input, "POST", getPrefixEndpoint()) +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + return helper.DoJsonRequest(input, "POST", endpoint) +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "PATCH", endpoint) +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + return helper.DoJsonRequest(input, "DELETE", endpoint) +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/unit", sync.O.TargetHost, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-use-case/new/division/case.go b/internal/use-case/simgos-sync-use-case/new/division/case.go new file mode 100644 index 00000000..458118d6 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/division/case.go @@ -0,0 +1,197 @@ +package division + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/division" + esimgos "simrs-vx/internal/domain/simgos-entities/m-unit" + esync "simrs-vx/internal/domain/sync-entities/division" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +const source = "division" + +func Create(input e.CreateDto) (*d.Data, error) { + var ( + sgData *esimgos.MUnit + syncLink *esync.DivisionLink + err error + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to simgos + sgData, err = CreateSimgosData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to Link + syncLink, err = CreateLinkData(*input.Id, sgData.KodeUnit, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // Step 2: Update Simgos + if err = UpdateSimgosData(input, syncLink, &event, tx); err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete Simgos + err = HardDeleteSimgosData(sgData, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Delete Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(uint(*input.Id), sgData.KodeUnit, &event) + }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/new/division/helper.go b/internal/use-case/simgos-sync-use-case/new/division/helper.go new file mode 100644 index 00000000..dbf69fa6 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/division/helper.go @@ -0,0 +1,56 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package division + +import ( + "encoding/json" + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/division" + esimgos "simrs-vx/internal/domain/simgos-entities/m-unit" + esync "simrs-vx/internal/domain/sync-entities/division" + esyncLog "simrs-vx/internal/domain/sync-entities/log" +) + +func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MUnit) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.NamaUnit = inputSrc.Name + return +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.DivisionSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.DivisionLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/new/division/lib.go b/internal/use-case/simgos-sync-use-case/new/division/lib.go new file mode 100644 index 00000000..5f4697a5 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/division/lib.go @@ -0,0 +1,188 @@ +package division + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/division" + esimgos "simrs-vx/internal/domain/simgos-entities/m-unit" + esync "simrs-vx/internal/domain/sync-entities/division" + esynclog "simrs-vx/internal/domain/sync-entities/log" +) + +var now = time.Now() + +func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MUnit, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setDataSimgos(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MUnit, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := esimgos.MUnit{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"kode_unit\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.DivisionLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + data := setDataSimgos(&input) + data.KodeUnit = dataSimgos.Simgos_Id + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 HardDeleteSimgosData(data *esimgos.MUnit, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.DivisionLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.DivisionLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.DivisionLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.DivisionLink, 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 +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/division/middleware-runner.go b/internal/use-case/simgos-sync-use-case/new/division/middleware-runner.go new file mode 100644 index 00000000..dad68114 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/division/middleware-runner.go @@ -0,0 +1,104 @@ +package division + +import ( + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/division" +) + +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/simgos-sync-use-case/new/division/middleware.go b/internal/use-case/simgos-sync-use-case/new/division/middleware.go new file mode 100644 index 00000000..f066ffb8 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/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/upload/tycovar.go b/internal/use-case/simgos-sync-use-case/new/division/tycovar.go similarity index 78% rename from internal/use-case/main-use-case/upload/tycovar.go rename to internal/use-case/simgos-sync-use-case/new/division/tycovar.go index 4849e215..c7733117 100644 --- a/internal/use-case/main-use-case/upload/tycovar.go +++ b/internal/use-case/simgos-sync-use-case/new/division/tycovar.go @@ -6,27 +6,27 @@ 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 upload +package division import ( "gorm.io/gorm" - e "simrs-vx/internal/domain/main-entities/upload" + e "simrs-vx/internal/domain/main-entities/division" ) type createMw struct { Name string - Func func(input *e.CreateDto, data interface{}, tx *gorm.DB) error + Func func(input *e.CreateDto, data *e.Division, tx *gorm.DB) error } type readListMw struct { Name string - Func func(input *e.ReadListDto, data interface{}, tx *gorm.DB) error + Func func(input *e.ReadListDto, data *e.Division, tx *gorm.DB) error } type readDetailMw struct { Name string - Func func(input *e.ReadDetailDto, data interface{}, tx *gorm.DB) error + Func func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error } type UpdateMw = readDetailMw diff --git a/internal/use-case/simgos-sync-use-case/new/encounter/case.go b/internal/use-case/simgos-sync-use-case/new/encounter/case.go new file mode 100644 index 00000000..05c77915 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/encounter/case.go @@ -0,0 +1,526 @@ +package encounter + +import ( + erc "simrs-vx/internal/domain/references/common" + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/encounter" + synce "simrs-vx/internal/domain/sync-entities/encounter" + syncir "simrs-vx/internal/domain/sync-entities/internal-reference" + elog "simrs-vx/internal/domain/sync-entities/log" + + utph "simrs-vx/internal/use-case/simgos-sync-use-case/new/internal-reference" +) + +const source = "encounter" + +func Create(input e.Encounter) (*d.Data, error) { + var ( + syncLink *synce.EncounterLink + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert TPendaftaran + tPendaftaran, err := CreateTPendaftaranData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert TRekammedik + err = CreateTRekammedik(input, tPendaftaran, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 3: Update MPasien + err = updatePatientCaraBayar(*tPendaftaran, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Insert to Link + syncLink, err = CreateLinkData(input.Id, tPendaftaran.Idxdaftar, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.Encounter) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + simgos, err := ReadTPendaftaranDetailData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // SET LOCAL + if err = tx.Exec(`SET LOCAL simx.sync_source = 'new'`).Error; err != nil { + return err + } + + // Step 2: Update Simgos + if err = UpdateTPendaftaranData(input, simgos, "update", &event, tx); err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + sgData, err := ReadTPendaftaranDetailData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete Simgos + err = HardDeleteTPendaftaranData(sgData, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Delete Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(uint(input.Id), sgData.Idxdaftar, &event) + }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} + +func CheckIn(input e.Encounter) (*d.Data, error) { + event := pl.Event{ + Feature: "CheckIn", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "check-in") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + simgos, err := ReadTPendaftaranDetailData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // SET LOCAL + if err = tx.Exec(`SET LOCAL simx.sync_source = 'new'`).Error; err != nil { + return err + } + + // Step 2: Update Simgos + if err = UpdateTPendaftaranData(input, simgos, "check-in", &event, tx); err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func CheckOut(input e.Encounter) (*d.Data, error) { + event := pl.Event{ + Feature: "CheckOut", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "check-out") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + simgos, err := ReadTPendaftaranDetailData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // SET LOCAL + if err = tx.Exec(`SET LOCAL simx.sync_source = 'new'`).Error; err != nil { + return err + } + + // Step 2: Update Simgos + if err = UpdateTPendaftaranData(input, simgos, "check-out", &event, tx); err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func UpdateStatus(input e.Encounter) (*d.Data, error) { + event := pl.Event{ + Feature: "Update Status", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update-status") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + simgos, err := ReadTPendaftaranDetailData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // SET LOCAL + if err = tx.Exec(`SET LOCAL simx.sync_source = 'new'`).Error; err != nil { + return err + } + + // Step 2: Update TPendaftaran + if err = UpdateTPendaftaranData(input, simgos, "update-status", &event, tx); err != nil { + return err + } + + // Step 3: Update TDiagnosadanterapi + if input.Status_Code == erc.DSCCancel { + if err = updateCancelTDiagnosaTherapy(simgos.Idxdaftar, input, &event, tx); err != nil { + return err + } + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func RequestSwitchUnit(input e.Encounter) (*d.Data, error) { + var ( + syncLinkInternal *[]syncir.InternalReferenceLink + ) + + event := pl.Event{ + Feature: "RequestSwitchUnit", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "request-switch-unit") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + tpendaftaran, err := ReadTPendaftaranDetailData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // Step 3: Update TPendaftaran + if err = UpdateTPendaftaranData(input, tpendaftaran, "update-status", &event, tx.Simgos); err != nil { + return err + } + + // Step 4: Bulk Insert TPemeriksaanHist + tPemeriksanHistory, err := utph.CreateSimgosData(input, tpendaftaran, &event, tx.Simgos) + if err != nil { + return err + } + + // Step 5: Bulk Insert To Link + if syncLinkInternal, err = utph.CreateBulkLinkData(*input.InternalReferences, *tPemeriksanHistory, &event, tx.Sync); err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLinkInternal != nil { + go func() { _ = utph.DeleteLinkData(syncLinkInternal, &event) }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func ApproveSwitchUnit(input e.ApproveCancelUnitDto) (*d.Data, error) { + event := pl.Event{ + Feature: "ApproveSwitchUnit", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "approve-switch-unit") + + // STEP 1: Get InternalReference Link + syncLink, err := utph.ReadDetailLinkData(input.InternalReferences_Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get TPemeriksaanHist + tPemeriksaanHist, err := utph.ReadDetailSimgosData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // SET LOCAL + if err = tx.Exec(`SET LOCAL simx.sync_source = 'new'`).Error; err != nil { + return err + } + + // Step 3: Update TPemeriksaanHist + if err := utph.UpdateSimgosData(input, tPemeriksaanHist, "approve", &event, tx); err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func CancelSwitchUnit(input e.ApproveCancelUnitDto) (*d.Data, error) { + event := pl.Event{ + Feature: "CancelSwitchUnit", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "cancel-switch-unit") + + // STEP 1: Get InternalReference Link + syncLink, err := utph.ReadDetailLinkData(input.InternalReferences_Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get TPemeriksaanHist + tPemeriksaanHist, err := utph.ReadDetailSimgosData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // SET LOCAL + if err = tx.Exec(`SET LOCAL simx.sync_source = 'new'`).Error; err != nil { + return err + } + + // Step 3: Update TPemeriksaanHist + if err := utph.UpdateSimgosData(input, tPemeriksaanHist, "cancel", &event, tx); err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/encounter/helper.go b/internal/use-case/simgos-sync-use-case/new/encounter/helper.go new file mode 100644 index 00000000..97656afe --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/encounter/helper.go @@ -0,0 +1,441 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package encounter + +import ( + "encoding/json" + pl "simrs-vx/pkg/logger" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + "gorm.io/gorm/clause" + + erc "simrs-vx/internal/domain/references/common" + ere "simrs-vx/internal/domain/references/encounter" + erp "simrs-vx/internal/domain/references/person" + + e "simrs-vx/internal/domain/main-entities/encounter" + epa "simrs-vx/internal/domain/main-entities/person-address" + epc "simrs-vx/internal/domain/main-entities/person-contact" + epr "simrs-vx/internal/domain/main-entities/person-relative" + + ep "simrs-vx/internal/domain/simgos-entities/m-pasien" + etdt "simrs-vx/internal/domain/simgos-entities/t-diagnosadanterapi" + etp "simrs-vx/internal/domain/simgos-entities/t-pendaftaran" + etrm "simrs-vx/internal/domain/simgos-entities/t-rekammedik" + + esync "simrs-vx/internal/domain/sync-entities/encounter" + esyncLog "simrs-vx/internal/domain/sync-entities/log" +) + +func setDataCreateTPendaftaran(input *e.Encounter) (data etp.TPendaftaran, err error) { + data.Nomr = *input.Patient.Number + + // set pasienbaru + if input.NewStatus { + data.Pasienbaru = 1 + } + + // default kelas daftar + data.KelasDaftar = 3 + + // set noAntrian + defaultFromSimx := "rehab" + data.NoAntrian = &defaultFromSimx + + // set no_kunjung + noKunjung, err := generateNoKunjung() + if err != nil { + return etp.TPendaftaran{}, err + } + data.NoKunjung = uint(noKunjung) + + if p := input.Patient.Person; p != nil { + mapRelative(p.Relatives, &data) + + if data.PenanggungjawabNama == "" { + data.PenanggungjawabHubungan = "DIRI SENDIRI" + data.PenanggungjawabNama = p.Name + mapContact(p.Contacts, &data) + mapAddress(p.Addresses, &data) + } + + if bpjs := p.VclaimMember; bpjs != nil { + data.Nokartu = *bpjs.CardNumber + } + } + + setDataTPendaftaran(input, &data) + + return +} + +func setDataTPendaftaran(input *e.Encounter, data *etp.TPendaftaran) { + data.Tglreg = input.RegisteredAt + + // set kdpoly + if p := input.Unit_Code; p != nil { + kdpoly, _ := strconv.Atoi(*input.Unit_Code) + data.Kdpoly = uint(kdpoly) + } + + // set kdrujuk + setKdrujuk(input.RefType_Code, data) + + // set kdcarabayar + setKdcarabayar(input.PaymentMethod_Code, data) + + // TODO: shift + + // set nip + if emp := input.Adm_Employee; emp != nil { + if user := emp.User; user != nil { + data.Nip = user.Name + } + } + + // set data if payment_method bpjs + if input.RefSource_Name != nil { + data.Ketrujuk = *input.RefSource_Name + data.Strujukan = 1 + } else { + data.Ketrujuk = "TR" + data.Strujukan = 0 + } + + if ref := input.VclaimReference; ref != nil { + data.Norujukan = *ref.Number + data.Tglrujukan = ref.Date + } + + data.Jamreg = input.RegisteredAt + + // TODO: st_asal_masuk + + return +} + +func setDataUpdateStatus(input e.Encounter, data *etp.TPendaftaran) { + switch input.Status_Code { + case erc.DSCProcess: + data.Masukpoly = &now + } + + if input.Status_Code == erc.DSCCancel { + data.Status = 11 + return + } + + if input.Discharge_Method_Code != nil { + setStatus(input.Discharge_Method_Code, data) + } +} + +func setDataCheckIn(input e.Encounter, data *etp.TPendaftaran) { + // set kddokter + kddokter, _ := strconv.Atoi(*input.Responsible_Doctor_Code) + data.Kddokter = uint(kddokter) + + // set petugas_klinik + // only update once + if data.PetugasKlinik == "" { + if n := input.Responsible_Nurse; n != nil { + if emp := n.Employee; emp != nil { + if u := emp.User; u != nil { + data.PetugasKlinik = u.Name + } + } + } + } + + data.Masukpoly = input.StartedAt + return +} + +func setDataCheckOut(input e.Encounter, data *etp.TPendaftaran) { + data.Keluarpoly = input.FinishedAt + + // set status + setStatus(input.Discharge_Method_Code, data) + if data.Status == 8 || data.Status == 3 { + if dc := input.DeathCause; dc != nil { + var dcSrc []DeathCauseSrc + _ = json.Unmarshal([]byte(*dc.Value), &dcSrc) + + for i, v := range dcSrc { + switch i { + case 0: + data.SebabMati1 = &v.Name + data.IcdMati1 = &v.Code + case 1: + data.SebabMati2 = &v.Name + data.IcdMati2 = &v.Code + case 2: + data.SebabMati3 = &v.Name + data.IcdMati3 = &v.Code + default: + break + } + } + } + death := uint(1) + data.StMeninggal = &death + data.DtMeninggal = data.Keluarpoly + } + + setPelayanan := uint(1) + data.StPelayanan = &setPelayanan + + return +} + +func setKdrujuk(input *ere.RefTypeCode, data *etp.TPendaftaran) { + switch *input { + case ere.RTCGov: + data.Kdrujuk = 1 + case ere.RTCPrivate: + data.Kdrujuk = 2 + case ere.RTCBpjs: + data.Kdrujuk = 3 + default: + data.Kdrujuk = 0 + } +} + +func setKdcarabayar(input ere.AllPaymentMethodCode, data *etp.TPendaftaran) { + switch input { + case ere.APMCPks: + data.Kdcarabayar = 12 + case ere.APMCJkn: + data.Kdcarabayar = 5 + case ere.APMCJkmm: + data.Kdcarabayar = 9 + case ere.APMCSpm: + data.Kdcarabayar = 10 + default: + data.Kdcarabayar = 1 + } +} + +func setStatus(code *ere.DischargeMethodCode, data *etp.TPendaftaran) { + switch *code { + case ere.DMCHome: + data.Status = 1 + case ere.DMCInpatient: + data.Status = 2 + case ere.DMCDeathOnArrival: + data.Status = 3 + data.StMeninggal = func(u uint) *uint { return &u }(1) + data.DtMeninggal = &now + case ere.DMCDeath: + data.Status = 8 + data.StMeninggal = func(u uint) *uint { return &u }(1) + data.DtMeninggal = &now + case ere.DMCHomeReq: + data.Status = 7 + case ere.DMCConsulPoly: + data.Status = 5 + case ere.DMCExtRef: + data.Status = 6 + case ere.DMCConsulChDay: + data.Status = 12 + case ere.DMCEmergency: + data.Status = 10 + case ere.DMCEmergencyCovid: + data.Status = 13 + case ere.DMCConsulExecutive: + data.Status = 15 + case ere.DMCConsulBack: + data.Status = 100 + default: + data.Status = 0 + } +} + +func mapRelative(relative *[]epr.PersonRelative, data *etp.TPendaftaran) { + if relative == nil || len(*relative) == 0 { + return + } + + for _, r := range *relative { + if r.Responsible { + data.PenanggungjawabNama = *r.Name + + switch r.Relationship_Code { + case erp.RCMother, erp.RCFather: + data.PenanggungjawabHubungan = "ORANG TUA" + case erp.RCChild: + data.PenanggungjawabHubungan = "ANAK" + case erp.RCSibling: + data.PenanggungjawabHubungan = "SAUDARA" + case erp.RCUncle, erp.RCAunt, + erp.RCGdMother, erp.RCGdFather, + erp.RCNephew, erp.RCGdChild: + data.PenanggungjawabHubungan = "KELUARGA LAIN" + case erp.RCFriend: + data.PenanggungjawabHubungan = "TEMAN" + case erp.RCSpouse: + data.PenanggungjawabHubungan = "SUAMI/ISTRI" + case erp.RCSelf: + data.PenanggungjawabHubungan = "DIRI SENDIRI" + default: + data.PenanggungjawabHubungan = "LAINNYA ..." + } + + data.PenanggungjawabAlamat = *r.Address + data.PenanggungjawabPhone = *r.PhoneNumber + + break + } + } +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.EncounterSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.EncounterLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} + +func generateNoKunjung() (int, error) { + var lastNumber int + + // Lock rows for this prefix → prevents race condition + if err := dg.IS["simrs"]. + Table("t_pendaftaran"). + Select("no_kunjung"). + Where("tglreg = CURRENT_DATE"). + Order("no_kunjung DESC"). + Clauses(clause.Locking{Strength: "UPDATE"}). + Limit(1). + Scan(&lastNumber).Error; err != nil { + return 0, err + } + + return lastNumber + 1, nil +} + +func updatePatientCaraBayar(input etp.TPendaftaran, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBUpdate") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Model(&ep.MPasien{}). + Where("\"nomr\" = ?", input.Nomr). + Update("kdcarabayar", input.Kdcarabayar).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "update-fail", + Detail: "Failed to update patient", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, input, "complete") + return nil +} + +func mapContact(contact *[]epc.PersonContact, data *etp.TPendaftaran) { + if contact == nil || len(*contact) == 0 { + return + } + + for _, c := range *contact { + if c.Type_Code == erp.CTPhone || c.Type_Code == erp.CTMPhone { + data.PenanggungjawabPhone = c.Value + break + } + } +} + +func mapAddress(addresses *[]epa.PersonAddress, data *etp.TPendaftaran) { + if addresses == nil || len(*addresses) == 0 { + return + } + a := (*addresses)[0] + data.PenanggungjawabAlamat = a.Address +} + +func setDataTRekammedik(input e.Encounter, tdaftar *etp.TPendaftaran) (data etrm.TRekammedik) { + data.TglKirim = tdaftar.Tglreg + data.Idxdaftar = tdaftar.Idxdaftar + data.Kdpoly = tdaftar.Kdpoly + data.JamKirimRm = tdaftar.Tglreg + + if emp := input.Adm_Employee; emp != nil { + if p := emp.Person; p != nil { + data.Pengirim = p.Name + } + } + + return +} + +func updateCancelTDiagnosaTherapy(idxdaftar uint, enc e.Encounter, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBUpdate") + + var ( + tx *gorm.DB + userBatal string + ) + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if a := enc.Adm_Employee; a != nil { + if u := a.User; u != nil { + userBatal = u.Name + } + } + + if err := tx.Model(&etdt.TDiagnosaDanTerapi{}). + Where("idxdaftar = ?", idxdaftar). + Updates(map[string]interface{}{ + "status": "BATAL", + "user_batal": userBatal, + "tgl_batal": &now, + }).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "update-fail", + Detail: "Failed to update patient", + Raw: err, + } + return pl.SetLogError(event, idxdaftar) + } + + pl.SetLogInfo(event, idxdaftar, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/encounter/lib.go b/internal/use-case/simgos-sync-use-case/new/encounter/lib.go new file mode 100644 index 00000000..95f86ede --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/encounter/lib.go @@ -0,0 +1,218 @@ +package encounter + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/encounter" + etp "simrs-vx/internal/domain/simgos-entities/t-pendaftaran" + esync "simrs-vx/internal/domain/sync-entities/encounter" + esynclog "simrs-vx/internal/domain/sync-entities/log" +) + +var now = time.Now() + +func CreateTPendaftaranData(input e.Encounter, event *pl.Event, dbx ...*gorm.DB) (*etp.TPendaftaran, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data, err := setDataCreateTPendaftaran(&input) + if err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadTPendaftaranDetailData(simgosId uint, event *pl.Event) (*etp.TPendaftaran, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := etp.TPendaftaran{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"idxdaftar\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateTPendaftaranData(input e.Encounter, data *etp.TPendaftaran, method string, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + switch method { + case "update": + setDataTPendaftaran(&input, data) + case "check-in": + setDataCheckIn(input, data) + case "check-out": + setDataCheckOut(input, data) + case "update-status": + setDataUpdateStatus(input, data) + } + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 HardDeleteTPendaftaranData(data *etp.TPendaftaran, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.EncounterLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint, event *pl.Event) (*esync.EncounterLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.EncounterLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.EncounterLink, 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 +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func CreateTRekammedik(input e.Encounter, tpendaftaran *etp.TPendaftaran, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataTRekammedik(input, tpendaftaran) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/encounter/middleware-runner.go b/internal/use-case/simgos-sync-use-case/new/encounter/middleware-runner.go new file mode 100644 index 00000000..83e0252c --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/encounter/middleware-runner.go @@ -0,0 +1,104 @@ +package encounter + +import ( + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/encounter" +) + +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.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Encounter) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/simgos-sync-use-case/new/encounter/middleware.go b/internal/use-case/simgos-sync-use-case/new/encounter/middleware.go new file mode 100644 index 00000000..8a047d33 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/encounter/middleware.go @@ -0,0 +1,9 @@ +package encounter + +// 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/simgos-sync-use-case/new/encounter/tycovar.go b/internal/use-case/simgos-sync-use-case/new/encounter/tycovar.go new file mode 100644 index 00000000..7d3d19db --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/encounter/tycovar.go @@ -0,0 +1,51 @@ +/* +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 encounter + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/encounter" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Encounter, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Encounter, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Encounter, 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 + +type DeathCauseSrc struct { + Id uint `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + IndName string `json:"indName"` +} diff --git a/internal/use-case/simgos-sync-use-case/new/installation/case.go b/internal/use-case/simgos-sync-use-case/new/installation/case.go new file mode 100644 index 00000000..4d89b5ae --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/installation/case.go @@ -0,0 +1,199 @@ +package installation + +import ( + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/installation" + esimgos "simrs-vx/internal/domain/simgos-entities/m-instalasi" + esync "simrs-vx/internal/domain/sync-entities/installation" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +const source = "installation" + +func Create(input e.CreateDto) (*d.Data, error) { + var ( + sgData *esimgos.MInstalasi + syncLink *esync.InstallationLink + err error + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to simgos + sgData, err = CreateSimgosData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to Link + syncLink, err = CreateLinkData(*input.Id, sgData.No_Instalasi, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // Step 2: Update Simgos + if err = UpdateSimgosData(input, syncLink, &event, tx); err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete Simgos + err = SoftDeleteSimgosData(sgData, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Delete Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(uint(*input.Id), sgData.No_Instalasi, &event) + }() + } + + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/new/installation/helper.go b/internal/use-case/simgos-sync-use-case/new/installation/helper.go new file mode 100644 index 00000000..1bb722dd --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/installation/helper.go @@ -0,0 +1,58 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package installation + +import ( + "encoding/json" + e "simrs-vx/internal/domain/main-entities/installation" + erc "simrs-vx/internal/domain/references/common" + esimgos "simrs-vx/internal/domain/simgos-entities/m-instalasi" + esync "simrs-vx/internal/domain/sync-entities/installation" + esyncLog "simrs-vx/internal/domain/sync-entities/log" +) + +func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MInstalasi) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Nama_Instalasi = inputSrc.Name + data.Status_Rawat_Inap = 0 + data.St_Aktif = 1 + + return +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.InstallationSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.InstallationLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/new/installation/lib.go b/internal/use-case/simgos-sync-use-case/new/installation/lib.go new file mode 100644 index 00000000..a8d074fa --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/installation/lib.go @@ -0,0 +1,214 @@ +package installation + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/installation" + esimgos "simrs-vx/internal/domain/simgos-entities/m-instalasi" + esync "simrs-vx/internal/domain/sync-entities/installation" + esynclog "simrs-vx/internal/domain/sync-entities/log" +) + +var now = time.Now() + +func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MInstalasi, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setDataSimgos(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MInstalasi, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := esimgos.MInstalasi{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"no_instalasi\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.InstallationLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + data := setDataSimgos(&input) + data.No_Instalasi = dataSimgos.Simgos_Id + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 HardDeleteSimgosData(data *esimgos.MInstalasi, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 +} + +func SoftDeleteSimgosData(data *esimgos.MInstalasi, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + data.St_Aktif = 0 + + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.InstallationLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.InstallationLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.InstallationLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.InstallationLink, 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 +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/installation/middleware-runner.go b/internal/use-case/simgos-sync-use-case/new/installation/middleware-runner.go new file mode 100644 index 00000000..fce572bb --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/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/simgos-sync-use-case/new/installation/middleware.go b/internal/use-case/simgos-sync-use-case/new/installation/middleware.go new file mode 100644 index 00000000..3d414c9b --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/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/simgos-sync-use-case/new/installation/tycovar.go b/internal/use-case/simgos-sync-use-case/new/installation/tycovar.go new file mode 100644 index 00000000..de8e9c9e --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/installation/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 installation + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/installation" +) + +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 +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/simgos-sync-use-case/new/internal-reference/helper.go b/internal/use-case/simgos-sync-use-case/new/internal-reference/helper.go new file mode 100644 index 00000000..9cb55785 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/internal-reference/helper.go @@ -0,0 +1,103 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package internal_reference + +import ( + "encoding/json" + eir "simrs-vx/internal/domain/main-entities/internal-reference" + erc "simrs-vx/internal/domain/references/common" + "strconv" + + e "simrs-vx/internal/domain/main-entities/encounter" + + etph "simrs-vx/internal/domain/simgos-entities/t-pemeriksaan-hist" + etp "simrs-vx/internal/domain/simgos-entities/t-pendaftaran" + + esync "simrs-vx/internal/domain/sync-entities/internal-reference" + esyncLog "simrs-vx/internal/domain/sync-entities/log" +) + +func setCreateDataSimgos(input e.Encounter, data *etp.TPendaftaran) (hist []etph.TPemeriksaanHist) { + if enc := input.InternalReferences; enc != nil { + for i, ref := range *enc { + hist = append(hist, etph.TPemeriksaanHist{ + Idxdaftar: &data.Idxdaftar, + Kdpoly: stringtouint(*ref.Unit_Code), + DokterPengonsul: stringtouint(*ref.SrcDoctor_Code), + DokterPenerima: stringtouint(*ref.Doctor_Code), + }) + + // set user konsul + if n := input.Responsible_Nurse; n != nil { + if emp := n.Employee; emp != nil { + if u := emp.User; u != nil { + hist[i].UserKonsul = &u.Name + } + } + } + + // setaktif + aktif := uint16(1) + hist[i].StAktif = &aktif + } + } + return +} + +func setUpdateApproveDataSimgos(input e.ApproveCancelUnitDto, data *etph.TPemeriksaanHist) { + data.DokterPenerima = stringtouint(*input.Dst_Doctor_Code) + data.StartKonsul = &now + data.UserPenerima = &input.User_Name + data.MasukPoly = data.StartKonsul + return +} + +func setUpdateCancelDataSimgos(input e.ApproveCancelUnitDto, data *etph.TPemeriksaanHist) { + data.UserBatal = &input.User_Name + data.TglBatal = &now + + aktif := uint16(0) + data.StAktif = &aktif + + return +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.InternalReferenceSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(ir []eir.InternalReference, tph []etph.TPemeriksaanHist) (data []esync.InternalReferenceLink) { + for i := range len(ir) { + data = append(data, esync.InternalReferenceLink{ + Simx_Id: ir[i].Id, + Simgos_Id: tph[i].IdPemeriksaanHist, + }) + } + return +} + +func stringtouint(v string) *uint { + u, _ := strconv.Atoi(v) + point := uint(u) + return &point +} diff --git a/internal/use-case/simgos-sync-use-case/new/internal-reference/lib.go b/internal/use-case/simgos-sync-use-case/new/internal-reference/lib.go new file mode 100644 index 00000000..2263f230 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/internal-reference/lib.go @@ -0,0 +1,173 @@ +package internal_reference + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/encounter" + eir "simrs-vx/internal/domain/main-entities/internal-reference" + + etph "simrs-vx/internal/domain/simgos-entities/t-pemeriksaan-hist" + etp "simrs-vx/internal/domain/simgos-entities/t-pendaftaran" + + esync "simrs-vx/internal/domain/sync-entities/internal-reference" + esynclog "simrs-vx/internal/domain/sync-entities/log" +) + +const source = "internal-reference" + +var now = time.Now() + +func CreateSimgosData(input e.Encounter, dataDaftar *etp.TPendaftaran, event *pl.Event, dbx ...*gorm.DB) (*[]etph.TPemeriksaanHist, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setCreateDataSimgos(input, dataDaftar) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosData(simgosId uint, event *pl.Event) (*etph.TPemeriksaanHist, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := etph.TPemeriksaanHist{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"id_pemeriksaanhist\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.ApproveCancelUnitDto, data *etph.TPemeriksaanHist, method string, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + switch method { + case "approve": + setUpdateApproveDataSimgos(input, data) + case "cancel": + setUpdateCancelDataSimgos(input, data) + } + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 CreateBulkLinkData(ir []eir.InternalReference, tph []etph.TPemeriksaanHist, event *pl.Event, dbx ...*gorm.DB) (*[]esync.InternalReferenceLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(ir, tph) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint, event *pl.Event) (*esync.InternalReferenceLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.InternalReferenceLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *[]esync.InternalReferenceLink, 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 +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/internal-reference/middleware-runner.go b/internal/use-case/simgos-sync-use-case/new/internal-reference/middleware-runner.go new file mode 100644 index 00000000..344bbe93 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/internal-reference/middleware-runner.go @@ -0,0 +1,103 @@ +package internal_reference + +import ( + e "simrs-vx/internal/domain/main-entities/internal-reference" + 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.InternalReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.InternalReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.InternalReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.InternalReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.InternalReference) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/simgos-sync-use-case/new/internal-reference/middleware.go b/internal/use-case/simgos-sync-use-case/new/internal-reference/middleware.go new file mode 100644 index 00000000..2afd1eaf --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/internal-reference/middleware.go @@ -0,0 +1,9 @@ +package internal_reference + +// 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/simgos-sync-use-case/new/internal-reference/tycovar.go b/internal/use-case/simgos-sync-use-case/new/internal-reference/tycovar.go new file mode 100644 index 00000000..4cb6c572 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/internal-reference/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 internal_reference + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/internal-reference" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.InternalReference, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.InternalReference, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.InternalReference, 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/simgos-sync-use-case/new/patient/case.go b/internal/use-case/simgos-sync-use-case/new/patient/case.go new file mode 100644 index 00000000..03497eed --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/patient/case.go @@ -0,0 +1,240 @@ +package patient + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/patient" + esimgos "simrs-vx/internal/domain/simgos-entities/m-pasien" + elog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/patient" +) + +const source = "patient" + +func Create(input e.Patient) (*d.Data, error) { + var ( + sgData *esimgos.MPasien + syncLink *esync.PatientLink + err error + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to simgos + sgData, err = CreateSimgosData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to Link + syncLink, err = CreateLinkData(input.Id, sgData.Id, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.Patient) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + patientData, err := ReadDetailSimgosData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // SET LOCAL + if err = tx.Exec(`SET LOCAL simx.sync_source = 'new'`).Error; err != nil { + return err + } + + // Step 3: Update Simgos + if err = UpdateSimgosData(input, patientData, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + sgData, err := ReadDetailSimgosData(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete Simgos + err = HardDeleteSimgosData(sgData, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Delete Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(input.Id, sgData.Id, &event) + }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} + +func GenerateNomr() (*d.Data, error) { + event := pl.Event{ + Feature: "Generate Nomr", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, nil, "started", "create") + + norm, err := generateNomrPatient("12") + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: d.IS{ + "nomr": norm, + }, + }, nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/patient/helper.go b/internal/use-case/simgos-sync-use-case/new/patient/helper.go new file mode 100644 index 00000000..532574b2 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/patient/helper.go @@ -0,0 +1,352 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package patient + +import ( + "encoding/json" + "fmt" + erc "simrs-vx/internal/domain/references/common" + erp "simrs-vx/internal/domain/references/person" + "strconv" + + e "simrs-vx/internal/domain/main-entities/patient" + ep "simrs-vx/internal/domain/main-entities/person" + epa "simrs-vx/internal/domain/main-entities/person-address" + epc "simrs-vx/internal/domain/main-entities/person-contact" + epr "simrs-vx/internal/domain/main-entities/person-relative" + esimgos "simrs-vx/internal/domain/simgos-entities/m-pasien" + esyncLog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/patient" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm/clause" +) + +func setDataSimgos(input *e.Patient) (data esimgos.MPasien) { + if p := input.Person; p != nil { + mapPerson(p, &data) + } + + if input.Person != nil && input.Person.Addresses != nil { + mapAddress(input.Person.Addresses, &data) + } + + if input.Person != nil && input.Person.Contacts != nil { + mapContact(input.Person.Contacts, &data) + } + + if input.Person != nil { + data.PenanggungjawabHubungan = "DIRI SENDIRI" + data.PenanggungjawabNama = input.Person.Name + data.PenanggungjawabPhone = data.Notelp + data.PenanggungjawabAlamat = data.Alamat + + if input.Person.Relatives != nil { + mapRelative(input.Person.Relatives, &data) + } + } + + data.Nip = input.RegisteredBy_User_Name + data.Tgldaftar = input.RegisteredAt + data.Nomr = *input.Number + + nomrBaru, _ := generateNomrPatient("00") + data.NomrBaru = &nomrBaru + + return +} + +func generateNomrPatient(prefix string) (string, error) { + const maxSuffix = 999999 + + column := "nomr" + if prefix == "00" { + column = "nomr_baru" + } + + type Row struct { + Value string `gorm:"column:value"` + } + + var r Row + + // Lock rows for this prefix → prevents race condition + if err := dg.IS["simrs"]. + Table("m_pasien"). + Select(fmt.Sprintf("%s AS value", column)). + Where(fmt.Sprintf("%s LIKE ?", column), prefix+"%"). + Order(fmt.Sprintf("%s DESC", column)). + Clauses(clause.Locking{Strength: "UPDATE"}). + Limit(1). + Scan(&r).Error; err != nil { + return "", err + } + + // No existing number → start at 000001 + if r.Value == "" || len(r.Value) < len(prefix) { + return prefix + "000001", nil + } + + suffix := r.Value[len(prefix):] + num, err := strconv.Atoi(suffix) + if err != nil { + // data corrupt, reset nomor + return prefix + "000001", nil + } + + // If reached 999999 → increment prefix + if num >= maxSuffix { + p, _ := strconv.Atoi(prefix) + p++ + return fmt.Sprintf("%02d000001", p), nil + } + + // Normal increment + return prefix + fmt.Sprintf("%06d", num+1), nil +} + +func mapPerson(p *ep.Person, data *esimgos.MPasien) { + if p.FrontTitle != nil { + data.Title = *p.FrontTitle + } + + if p.BirthRegency != nil { + data.Tempat = p.BirthRegency.Name + } + + if p.BirthDate != nil { + data.Tgllahir = p.BirthDate + } + + if p.Gender_Code != nil { + if *p.Gender_Code == erp.GCMale { + data.Jeniskelamin = "L" + } else if *p.Gender_Code == erp.GCFemale { + data.Jeniskelamin = "P" + } + } + + data.Nama = p.Name + data.Noktp = *p.ResidentIdentityNumber + data.NoktpBaru = *p.ResidentIdentityNumber + data.Pekerjaan = *p.Ocupation_Name + + data.Status, data.TxtStatus = setMaritalStatus(p.MaritalStatus_Code) + data.Agama, data.TxtAgama = setReligion(p.Religion_Code) + data.Pendidikan, data.TxtPendidikan = setEducation(p.Education_Code) + + if c := p.VclaimMember; c != nil && c.CardNumber != nil { + data.NoKartu = *c.CardNumber + } + + if l := p.Language; l != nil { + data.Bahasa = l.Name + } + + if p.CommunicationIssueStatus { + data.HambatanKomunikasi = "Y" + } else { + data.HambatanKomunikasi = "T" + } + + if p.Nationality != nil { + data.Kebangsaan = *p.Nationality + } + + if p.Ethnic != nil { + data.Suku = p.Ethnic.Name + } +} + +func setMaritalStatus(code *erp.MaritalStatusCode) (uint, string) { + if code != nil { + switch *code { + case erp.MaritalStatusSingle: + return 1, "Belum Menikah" + case erp.MaritalStatusMarried: + return 2, "Menikah" + case erp.MaritalStatusDivorced: + return 4, "Cerai" + case erp.MaritalStatusWidowed: + return 3, "Janda/Duda" + default: + return 0, "Tidak Diketahui" + } + } else { + return 0, "Tidak Diketahui" + } +} + +func setReligion(code *erp.ReligionCode) (uint, string) { + if code != nil { + switch *code { + case erp.RCIslam: + return 1, "Islam" + case erp.RCProtestan: + return 2, "Kristen Protestan" + case erp.RCKatolik: + return 3, "Katholik" + case erp.RCHindu: + return 4, "Hindu" + case erp.RCBudha: + return 5, "Budha" + case erp.RCKonghucu: + return 6, "Konghucu" + default: + return 9, "Lainnya" + } + } else { + return 0, "Tidak Diketahui" + } +} + +func setEducation(code *erp.EducationCode) (uint, string) { + if code != nil { + switch *code { + case erp.ECTS: + return 0, "Tidak Sekolah" + case erp.ECSD: + return 1, string(erp.ECSD) + case erp.ECSLTP: + return 2, string(erp.ECSLTP) + case erp.ECSLTA: + return 3, string(erp.ECSLTA) + case erp.ECD1, erp.ECD2, erp.ECD3, erp.ECD4: + return 4, "D3/Akademik" + case erp.ECS1, erp.ECS2, erp.ECS3: + return 5, "Universitas" + case erp.ECOther: + return 6, "Lainnya" + default: + return 7, "Tidak Diketahui" + } + } else { + return 7, "Tidak Diketahui" + } +} + +func mapAddress(addresses *[]epa.PersonAddress, data *esimgos.MPasien) { + if addresses == nil || len(*addresses) == 0 { + return + } + + a := (*addresses)[0] + data.Alamat = a.Address + data.AlamatKtp = a.Address + + if v := a.Village; v != nil { + villageCode, _ := strconv.Atoi(v.Code) + data.Kelurahan = uint64(villageCode) + data.TxtKelurahan = v.Name + + if d := v.District; d != nil { + districtCode, _ := strconv.Atoi(d.Code) + data.Kdkecamatan = uint(districtCode) + data.TxtKecamatan = d.Name + + if r := d.Regency; r != nil { + regencyCode, _ := strconv.Atoi(r.Code) + data.Kota = uint(regencyCode) + data.TxtKota = r.Name + + if p := r.Province; p != nil { + provinceCode, _ := strconv.Atoi(p.Code) + data.Kdprovinsi = uint(provinceCode) + data.TxtProvinsi = p.Name + } + } + } + } +} + +func mapContact(contact *[]epc.PersonContact, data *esimgos.MPasien) { + if contact == nil || len(*contact) == 0 { + return + } + + for _, c := range *contact { + if c.Type_Code == erp.CTPhone || c.Type_Code == erp.CTMPhone { + data.Notelp = c.Value + break + } + } + +} + +func mapRelative(relative *[]epr.PersonRelative, data *esimgos.MPasien) { + if relative == nil || len(*relative) == 0 { + return + } + + for _, r := range *relative { + if r.Responsible { + data.PenanggungjawabNama = *r.Name + + switch r.Relationship_Code { + case erp.RCMother, erp.RCFather: + data.PenanggungjawabHubungan = "ORANG TUA" + switch { + case r.Relationship_Code == erp.RCMother: + data.NamaIbu = *r.Name + eduCode, _ := setEducation(r.Education_Code) + data.PendidikanIbu = strconv.Itoa(int(eduCode)) + case r.Relationship_Code == erp.RCFather: + data.NamaAyah = *r.Name + eduCode, _ := setEducation(r.Education_Code) + data.PendidikanAyah = strconv.Itoa(int(eduCode)) + } + case erp.RCChild: + data.PenanggungjawabHubungan = "ANAK" + case erp.RCSibling: + data.PenanggungjawabHubungan = "SAUDARA" + case erp.RCUncle, erp.RCAunt, + erp.RCGdMother, erp.RCGdFather, + erp.RCNephew, erp.RCGdChild: + data.PenanggungjawabHubungan = "KELUARGA LAIN" + case erp.RCFriend: + data.PenanggungjawabHubungan = "TEMAN" + case erp.RCSpouse: + data.PenanggungjawabHubungan = "SUAMI/ISTRI" + case erp.RCSelf: + data.PenanggungjawabHubungan = "DIRI SENDIRI" + default: + data.PenanggungjawabHubungan = "LAINNYA ..." + } + + data.PenanggungjawabAlamat = *r.Address + data.PenanggungjawabPhone = *r.PhoneNumber + + break + } + } +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.PatientSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.PatientLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/new/patient/lib.go b/internal/use-case/simgos-sync-use-case/new/patient/lib.go new file mode 100644 index 00000000..edcaf036 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/patient/lib.go @@ -0,0 +1,212 @@ +package patient + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/patient" + esimgos "simrs-vx/internal/domain/simgos-entities/m-pasien" + esynclog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/patient" +) + +var now = time.Now() + +func CreateSimgosData(input e.Patient, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MPasien, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setDataSimgos(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosData(simgosId uint, event *pl.Event) (*esimgos.MPasien, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := esimgos.MPasien{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"id\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosByNomrData(nomr string, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MPasien, error) { + pl.SetLogInfo(event, nomr, "started", "DBReadDetail") + data := esimgos.MPasien{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx. + Where("\"nomr\" = ?", nomr). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, nomr, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.Patient, patientData *esimgos.MPasien, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + data := setDataSimgos(&input) + data.Id = patientData.Id + data.CreatedAt = patientData.CreatedAt + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 HardDeleteSimgosData(data *esimgos.MPasien, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.PatientLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint, event *pl.Event) (*esync.PatientLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.PatientLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.PatientLink, 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 +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/upload/middleware-runner.go b/internal/use-case/simgos-sync-use-case/new/patient/middleware-runner.go similarity index 87% rename from internal/use-case/main-use-case/upload/middleware-runner.go rename to internal/use-case/simgos-sync-use-case/new/patient/middleware-runner.go index 88e3e637..648be8d7 100644 --- a/internal/use-case/main-use-case/upload/middleware-runner.go +++ b/internal/use-case/simgos-sync-use-case/new/patient/middleware-runner.go @@ -1,4 +1,4 @@ -package upload +package patient import ( pl "simrs-vx/pkg/logger" @@ -6,7 +6,7 @@ import ( "gorm.io/gorm" - e "simrs-vx/internal/domain/main-entities/upload" + e "simrs-vx/internal/domain/main-entities/patient" ) type middlewareRunner struct { @@ -24,7 +24,7 @@ func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data interface{}) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Patient) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -39,7 +39,7 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e return nil } -func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data interface{}) error { +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Patient) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,7 +54,7 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu return nil } -func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data interface{}) error { +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Patient) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -69,7 +69,7 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data interface{}) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Patient) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -84,7 +84,7 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data interface{}) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Patient) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) diff --git a/internal/use-case/simgos-sync-use-case/new/patient/middleware.go b/internal/use-case/simgos-sync-use-case/new/patient/middleware.go new file mode 100644 index 00000000..5fe75e0a --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/patient/middleware.go @@ -0,0 +1,9 @@ +package patient + +// 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/simgos-sync-use-case/new/patient/tycovar.go b/internal/use-case/simgos-sync-use-case/new/patient/tycovar.go new file mode 100644 index 00000000..d7e9abfe --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/patient/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 patient + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/patient" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Patient, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Patient, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Patient, 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/simgos-sync-use-case/new/soapi/case.go b/internal/use-case/simgos-sync-use-case/new/soapi/case.go new file mode 100644 index 00000000..d7e9bcc4 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/soapi/case.go @@ -0,0 +1,274 @@ +package soapi + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/soapi" + + elog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/soapi" + + ue "simrs-vx/internal/use-case/simgos-sync-use-case/new/encounter" +) + +const source = "soapi" + +func Create(input e.Soapi) (*d.Data, error) { + var ( + syncLink *esync.SoapiLink + err error + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + // get encounter Link + eLink, err := ue.ReadDetailLinkData(*input.Encounter_Id, &event) + if err != nil { + return nil, err + } + + // get Tpendaftaran + tPendaftaran, err := ue.ReadTPendaftaranDetailData(eLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to TDiagnosaDanTerapi + tDiagTherapy, err := CreateTDiagnosaDanTerapi(input, tPendaftaran, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to TICD + _, err = CreateTIcd(input, tPendaftaran, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 3: Insert to TICD-CM + _, err = CreateTIcdCm(input, tPendaftaran, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Insert to Link + syncLink, err = CreateLinkData(input.Id, tDiagTherapy.Idxterapi, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.Soapi) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // Get Soapi Link + sLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // Get TDiagnosadanTerapi + tDiagTherapy, err := ReadDetailTDiagnosaDanTerapi(sLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + // Get Encounter Link + eLink, err := ue.ReadDetailLinkData(*input.Encounter_Id, &event) + if err != nil { + return nil, err + } + + // Get TPendaftaran + tPendaftaran, err := ue.ReadTPendaftaranDetailData(eLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // SET LOCAL + if err = tx.Exec(`SET LOCAL simx.sync_source = 'new'`).Error; err != nil { + return err + } + + // Step 1: Update TDiagnosaDanTerapi + if err = UpdateTDiagnosaDanTerapi(input, tDiagTherapy, &event, tx); err != nil { + return err + } + + // STEP 2: Delete TIcd + if err = HardDeleteTIcd(tDiagTherapy.Idxdaftar, &event, tx); err != nil { + return err + } + + // STEP 3: Delete TIcdCm + if err = HardDeleteTIcdCm(tDiagTherapy.Idxdaftar, &event, tx); err != nil { + return err + } + + // STEP 4: Insert TIcd + if _, err = CreateTIcd(input, tPendaftaran, &event, tx); err != nil { + return err + } + + // STEP 5: Insert TIcd-cm + if _, err = CreateTIcdCm(input, tPendaftaran, &event, tx); err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // Get Soapi Link + syncLink, err := ReadDetailLinkData(input.Id, &event) + if err != nil { + return nil, err + } + + // Get TDiagnosa&Terapi + tDiagTh, err := ReadDetailTDiagnosaDanTerapi(syncLink.Simgos_Id, &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Delete TDiagnosa&Terapi Simgos + if err = HardDeleteTDiagnosaDanTerapi(tDiagTh, &event, tx.Simgos); err != nil { + return err + } + + // STEP 2: Delete TIcd + if err = HardDeleteTIcd(tDiagTh.Idxdaftar, &event, tx.Simgos); err != nil { + return err + } + + // STEP 3: Delete TIcdCm + if err = HardDeleteTIcdCm(tDiagTh.Idxdaftar, &event, tx.Simgos); err != nil { + return err + } + + // STEP 4: Delete Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(input.Id, tDiagTh.Idxterapi, &event) + }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/new/soapi/helper.go b/internal/use-case/simgos-sync-use-case/new/soapi/helper.go new file mode 100644 index 00000000..b9d761a1 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/soapi/helper.go @@ -0,0 +1,200 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package soapi + +import ( + "encoding/json" + "fmt" + ere "simrs-vx/internal/domain/references/encounter" + "strconv" + "time" + + ercl "simrs-vx/internal/domain/references/clinical" + erc "simrs-vx/internal/domain/references/common" + + es "simrs-vx/internal/domain/main-entities/soapi" + + etdt "simrs-vx/internal/domain/simgos-entities/t-diagnosadanterapi" + eicd "simrs-vx/internal/domain/simgos-entities/t-icd" + eicdcm "simrs-vx/internal/domain/simgos-entities/t-icd-cm" + etp "simrs-vx/internal/domain/simgos-entities/t-pendaftaran" + + esyncLog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/soapi" +) + +func setDataCreateTDiagnosaDanTerapi(input es.Soapi, enc *etp.TPendaftaran) (data etdt.TDiagnosaDanTerapi) { + switch input.TypeCode { + case ercl.STCEEarlyMedic: + data.Idxdaftar = enc.Idxdaftar + data.Nomr = enc.Nomr + data.Kdpoly = enc.Kdpoly + data.Kddokter = enc.Kddokter + + if e := input.Encounter; e != nil { + data.Tanggal = e.VisitDate + if e.Class_Code == ere.ECAmbulatory { + data.Rajal = 1 + } + + } + + if e := input.Employee; e != nil { + if u := e.User; u != nil { + data.Nip = u.Name + } + } + + setEarlyMedicTDT(input, &data) + return + } + + return +} + +func setEarlyMedicTDT(input es.Soapi, data *etdt.TDiagnosaDanTerapi) { + value := ercl.EarlyMedicValue{} + _ = json.Unmarshal([]byte(*input.Value), &value) + + data.TekananDarah = fmt.Sprintf("%v/%v", value.SystolicBloodPressure, value.DiastolicBloodPressure) + data.GolonganDarah = value.BloodType + if value.BloodType == "" { + data.GolonganDarah = "X" + } + + data.TinggiBadan = float64(value.Height) + data.BeratBadan = float64(value.Weight) + data.Diagnosa = &value.EarlyMedicDiagnose + data.Terapi = &value.Therapy + data.Anamnesa = &value.PrimaryComplain + + // TODO : status, tindakan_mdeis (?) + data.KunjunganBl = uint(value.EncounterStatus) + data.KasusBl = uint(value.CaseStatus) + + data.PemeriksaanFisik = &value.PhysicalExamination + data.RiwayatPasien = &value.CurrentDiseaseHistory + + if value.Vaccinated { + data.SudahVaksin = "YA" + } else { + data.SudahVaksin = "TIDAK" + } + + data.DenyutJantung = strconv.Itoa(value.Pulse) + data.Pernapasan = strconv.Itoa(value.RespiratoryRate) + data.Suhu = strconv.Itoa(value.Temperature) + data.Sp02 = strconv.Itoa(value.SpO2) + + if o := value.ExpectedOutcome; len(o) > 0 { + expectedOutput := []string{} + for _, v := range o { + expectedOutput = append(expectedOutput, v.Name) + } + + jsonData, _ := json.Marshal(expectedOutput) + data.TargetCapaian = string(jsonData) + } + return +} + +func setDataIcd(input es.Soapi, enc *etp.TPendaftaran) (data []eicd.TIcd) { + value := ercl.EarlyMedicValue{} + _ = json.Unmarshal([]byte(*input.Value), &value) + + var ( + visitDate time.Time + ambulatory uint16 + ) + + if e := input.Encounter; e != nil { + visitDate = e.VisitDate + if e.Class_Code == ere.ECAmbulatory { + ambulatory = 1 + } + + } + + if d := value.DiagnoseSrc; len(d) > 0 { + for _, v := range d { + data = append(data, eicd.TIcd{ + Nomr: enc.Nomr, + Idxdaftar: enc.Idxdaftar, + Kddokter: enc.Kddokter, + Icd: v.Code, + StatusRajal: ambulatory, + Tanggal: visitDate, + }) + } + } + + return +} + +func setDataIcdCm(input es.Soapi, enc *etp.TPendaftaran) (data []eicdcm.TIcdCm) { + value := ercl.EarlyMedicValue{} + _ = json.Unmarshal([]byte(*input.Value), &value) + + var ( + visitDate time.Time + ambulatory uint16 + ) + + if e := input.Encounter; e != nil { + visitDate = e.VisitDate + if e.Class_Code == ere.ECAmbulatory { + ambulatory = 1 + } + + } + + if p := value.ProcedureSrc; len(p) > 0 { + for _, v := range p { + data = append(data, eicdcm.TIcdCm{ + Nomr: enc.Nomr, + Idxdaftar: enc.Idxdaftar, + Kddokter: enc.Kddokter, + Icd: &v.Code, + StatusRajal: ambulatory, + Tanggal: visitDate, + }) + } + } + + return +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.SoapiSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.SoapiLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} + +func stringtouint(v string) uint { + u, _ := strconv.Atoi(v) + return uint(u) +} diff --git a/internal/use-case/simgos-sync-use-case/new/soapi/lib.go b/internal/use-case/simgos-sync-use-case/new/soapi/lib.go new file mode 100644 index 00000000..af27a791 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/soapi/lib.go @@ -0,0 +1,334 @@ +package soapi + +import ( + "errors" + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/soapi" + + etdt "simrs-vx/internal/domain/simgos-entities/t-diagnosadanterapi" + eicd "simrs-vx/internal/domain/simgos-entities/t-icd" + eicdcm "simrs-vx/internal/domain/simgos-entities/t-icd-cm" + ep "simrs-vx/internal/domain/simgos-entities/t-pendaftaran" + + esynclog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/soapi" +) + +var now = time.Now() + +func CreateTDiagnosaDanTerapi(input e.Soapi, tdaftar *ep.TPendaftaran, event *pl.Event, dbx ...*gorm.DB) (*etdt.TDiagnosaDanTerapi, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataCreateTDiagnosaDanTerapi(input, tdaftar) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailTDiagnosaDanTerapi(simgosId uint, event *pl.Event) (*etdt.TDiagnosaDanTerapi, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := etdt.TDiagnosaDanTerapi{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"idxterapi\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateTDiagnosaDanTerapi(input e.Soapi, data *etdt.TDiagnosaDanTerapi, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + setEarlyMedicTDT(input, data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 HardDeleteTDiagnosaDanTerapi(data *etdt.TDiagnosaDanTerapi, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 +} + +func CreateTIcd(input e.Soapi, tdaftar *ep.TPendaftaran, event *pl.Event, dbx ...*gorm.DB) (*[]eicd.TIcd, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataIcd(input, tdaftar) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListTIcd(idxdaftar string, event *pl.Event, dbx ...*gorm.DB) ([]eicd.TIcd, error) { + pl.SetLogInfo(event, idxdaftar, "started", "DBReadList") + data := []eicd.TIcd{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&eicd.TIcd{}). + Where("idxdaftar = ?", idxdaftar) + + if err := tx.Find(&data).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, nil + } + return nil, plh.HandleListError(idxdaftar, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return data, nil +} + +func HardDeleteTIcd(idxdaftar uint, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, idxdaftar, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx. + Where("idxdaftar = ?", idxdaftar). + Delete(&eicd.TIcd{}).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, idxdaftar) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func CreateTIcdCm(input e.Soapi, tdaftar *ep.TPendaftaran, event *pl.Event, dbx ...*gorm.DB) (*[]eicdcm.TIcdCm, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataIcdCm(input, tdaftar) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadListTIcdCm(idxdaftar string, event *pl.Event, dbx ...*gorm.DB) ([]eicdcm.TIcdCm, error) { + pl.SetLogInfo(event, idxdaftar, "started", "DBReadList") + data := []eicdcm.TIcdCm{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&eicdcm.TIcdCm{}). + Where("idxdaftar = ?", idxdaftar) + + if err := tx.Find(&data).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, nil + } + return nil, plh.HandleListError(idxdaftar, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return data, nil +} + +func HardDeleteTIcdCm(idxdaftar uint, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, idxdaftar, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx. + Where("idxdaftar = ?", idxdaftar). + Delete(&eicdcm.TIcdCm{}).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, idxdaftar) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.SoapiLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint, event *pl.Event) (*esync.SoapiLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.SoapiLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.SoapiLink, 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 +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/soapi/middleware-runner.go b/internal/use-case/simgos-sync-use-case/new/soapi/middleware-runner.go new file mode 100644 index 00000000..74d8b1a8 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/soapi/middleware-runner.go @@ -0,0 +1,104 @@ +package soapi + +import ( + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/soapi" +) + +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.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Soapi) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/simgos-sync-use-case/new/soapi/middleware.go b/internal/use-case/simgos-sync-use-case/new/soapi/middleware.go new file mode 100644 index 00000000..1fa07628 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/soapi/middleware.go @@ -0,0 +1 @@ +package soapi diff --git a/internal/use-case/simgos-sync-use-case/new/soapi/tycovar.go b/internal/use-case/simgos-sync-use-case/new/soapi/tycovar.go new file mode 100644 index 00000000..956193a4 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/soapi/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 soapi + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/soapi" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Soapi, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Soapi, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Soapi, 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/simgos-sync-use-case/new/specialist/case.go b/internal/use-case/simgos-sync-use-case/new/specialist/case.go new file mode 100644 index 00000000..dd88981d --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/specialist/case.go @@ -0,0 +1,197 @@ +package specialist + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/specialist" + esimgos "simrs-vx/internal/domain/simgos-entities/m-polihfis" + elog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +const source = "specialist" + +func Create(input e.CreateDto) (*d.Data, error) { + var ( + sgData *esimgos.MPolihfis + syncLink *esync.SpecialistLink + err error + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to simgos + sgData, err = CreateSimgosData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to Link + syncLink, err = CreateLinkData(*input.Id, sgData.Id, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // STEP 1: Get Installation Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // Step 2: Update Simgos + err = UpdateSimgosData(input, syncLink, &event, tx) + if err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete Simgos + err = HardDeleteSimgosData(sgData, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Delete Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(uint(*input.Id), sgData.Id, &event) + }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/new/specialist/helper.go b/internal/use-case/simgos-sync-use-case/new/specialist/helper.go new file mode 100644 index 00000000..adce079f --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/specialist/helper.go @@ -0,0 +1,60 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package specialist + +import ( + "encoding/json" + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/specialist" + esimgos "simrs-vx/internal/domain/simgos-entities/m-polihfis" + esyncLog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T, data *esimgos.MPolihfis) { + 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.Poliklinik = inputSrc.Name + data.Active = 1 + data.Status = 1 + + return +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.SpecialistSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.SpecialistLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/new/specialist/lib.go b/internal/use-case/simgos-sync-use-case/new/specialist/lib.go new file mode 100644 index 00000000..0aee2ceb --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/specialist/lib.go @@ -0,0 +1,191 @@ +package specialist + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/specialist" + esimgos "simrs-vx/internal/domain/simgos-entities/m-polihfis" + esynclog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +var now = time.Now() + +func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MPolihfis, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := esimgos.MPolihfis{} + setDataSimgos(&input, &data) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Debug().Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MPolihfis, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := esimgos.MPolihfis{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"id\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.SpecialistLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + data := esimgos.MPolihfis{} + + setDataSimgos(&input, &data) + data.Id = dataSimgos.Simgos_Id + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 HardDeleteSimgosData(data *esimgos.MPolihfis, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.SpecialistLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.SpecialistLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.SpecialistLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.SpecialistLink, 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 +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/specialist/middleware-runner.go b/internal/use-case/simgos-sync-use-case/new/specialist/middleware-runner.go new file mode 100644 index 00000000..938c1f92 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/specialist/middleware-runner.go @@ -0,0 +1,104 @@ +package specialist + +import ( + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/specialist" +) + +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.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/simgos-sync-use-case/new/specialist/middleware.go b/internal/use-case/simgos-sync-use-case/new/specialist/middleware.go new file mode 100644 index 00000000..298e51a8 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/specialist/middleware.go @@ -0,0 +1,9 @@ +package specialist + +// 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/simgos-sync-use-case/new/specialist/tycovar.go b/internal/use-case/simgos-sync-use-case/new/specialist/tycovar.go new file mode 100644 index 00000000..16fa50b0 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/specialist/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 specialist + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/specialist" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Specialist, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Specialist, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Specialist, 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/simgos-sync-use-case/new/subspecialist/case.go b/internal/use-case/simgos-sync-use-case/new/subspecialist/case.go new file mode 100644 index 00000000..2c633101 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/subspecialist/case.go @@ -0,0 +1,199 @@ +package subspecialist + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/subspecialist" + //esimgos "simrs-vx/internal/domain/simgos-entities/specialist" + elog "simrs-vx/internal/domain/sync-entities/log" + //esync "simrs-vx/internal/domain/sync-entities/subspecialist" +) + +const source = "subspecialist" + +func Create(input e.CreateDto) (*d.Data, error) { + //var ( + // sgData *esimgos.MUnit + // syncLink *esync.SubspecialistLink + // err error + //) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + //err = db.WithDualTx(func(tx *db.Dualtx) error { + // // STEP 1: Insert to simgos + // sgData, err = CreateSimgosData(input, &event, tx.Simgos) + // if err != nil { + // return err + // } + // + // // STEP 2: Insert to Link + // syncLink, err = CreateLinkData(*input.Id, sgData.KodeUnit, &event, tx.Sync) + // if err != nil { + // return err + // } + // + // return nil + //}) + // + //if err != nil { + // if syncLink != nil { + // go func() { _ = DeleteLinkData(syncLink, &event) }() + // } + // return nil, err + //} + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + //// STEP 1: Get Link + //syncLink, err := ReadDetailLinkData(*input.Id, &event) + //if err != nil { + // return nil, err + //} + // + //tx := db.NewTx() + //err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // // Step 2: Update Simgos + // if err = UpdateSimgosData(input, syncLink, &event, tx); err != nil { + // return err + // } + // + // return nil + //}) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + //var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + //// STEP 1: Get Link + //syncLink, err := ReadDetailLinkData(*input.Id, &event) + //if err != nil { + // return nil, err + //} + // + //// STEP 2: Get Simgos + //sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + //if err != nil { + // return nil, err + //} + // + //err = db.WithDualTx(func(tx *db.Dualtx) error { + // // STEP 3: Delete Simgos + // err = HardDeleteSimgosData(sgData, &event, tx.Simgos) + // if err != nil { + // return err + // } + // + // // STEP 4: Delete Link + // err = DeleteLinkData(syncLink, &event, tx.Sync) + // if err != nil { + // return err + // } + // + // isLinkDeleted = true + // return nil + //}) + // + //if err != nil { + // if isLinkDeleted { + // go func() { + // _, _ = CreateLinkData(uint(*input.Id), sgData.KodeUnit, &event) + // }() + // } + // return nil, err + //} + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/new/subspecialist/helper.go b/internal/use-case/simgos-sync-use-case/new/subspecialist/helper.go new file mode 100644 index 00000000..898f161c --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/subspecialist/helper.go @@ -0,0 +1,59 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package subspecialist + +import ( + "encoding/json" + erc "simrs-vx/internal/domain/references/common" + //esimgos "simrs-vx/internal/domain/simgos-entities/specialist" + esyncLog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +//func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MPolihfis) { +// 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.Poliklinik = inputSrc.Name +// data.CodePolirs = *inputSrc.Unit_Code +// data.Active = 1 +// data.Status = 1 +// +// return +//} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.SpecialistSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.SpecialistLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/new/subspecialist/lib.go b/internal/use-case/simgos-sync-use-case/new/subspecialist/lib.go new file mode 100644 index 00000000..781e899d --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/subspecialist/lib.go @@ -0,0 +1,187 @@ +package subspecialist + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + //esimgos "simrs-vx/internal/domain/simgos-entities/specialist" + esynclog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +var now = time.Now() + +//func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MPolihfis, error) { +// pl.SetLogInfo(event, nil, "started", "DBCreate") +// +// data := setDataSimgos(&input) +// +// var tx *gorm.DB +// if len(dbx) > 0 { +// tx = dbx[0] +// } else { +// tx = dg.IS["simrs"] +// } +// +// if err := tx.Create(&data).Error; err != nil { +// return nil, plh.HandleCreateError(input, event, err) +// } +// +// pl.SetLogInfo(event, nil, "complete") +// return &data, nil +//} + +//func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MPolihfis, error) { +// pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") +// data := esimgos.MPolihfis{} +// +// var tx = dg.IS["simrs"] +// +// if err := tx. +// Where("\"kode_unit\" = ?", simgosId). +// First(&data).Error; err != nil { +// if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { +// return nil, processedErr +// } +// } +// +// pl.SetLogInfo(event, nil, "complete") +// return &data, nil +//} + +//func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.SpecialistLink, event *pl.Event, dbx ...*gorm.DB) error { +// pl.SetLogInfo(event, input, "started", "DBUpdate") +// +// data := setDataSimgos(&input) +// data.Id = dataSimgos.Simgos_Id +// +// var tx *gorm.DB +// if len(dbx) > 0 { +// tx = dbx[0] +// } else { +// tx = dg.IS["simrs"] +// } +// +// 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 HardDeleteSimgosData(data *esimgos.MPolihfis, event *pl.Event, dbx ...*gorm.DB) error { +// pl.SetLogInfo(event, data, "started", "DBDelete") +// +// var tx *gorm.DB +// if len(dbx) > 0 { +// tx = dbx[0] +// } else { +// tx = dg.IS["simrs"] +// } +// +// 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 +//} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.SpecialistLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.SpecialistLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.SpecialistLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.SpecialistLink, 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 +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/new/subspecialist/middleware-runner.go b/internal/use-case/simgos-sync-use-case/new/subspecialist/middleware-runner.go new file mode 100644 index 00000000..134041f1 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/subspecialist/middleware-runner.go @@ -0,0 +1,104 @@ +package subspecialist + +import ( + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/subspecialist" +) + +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.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != 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/simgos-sync-use-case/new/subspecialist/middleware.go b/internal/use-case/simgos-sync-use-case/new/subspecialist/middleware.go new file mode 100644 index 00000000..ad2ba452 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/subspecialist/middleware.go @@ -0,0 +1,9 @@ +package subspecialist + +// 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/simgos-sync-use-case/new/subspecialist/tycovar.go b/internal/use-case/simgos-sync-use-case/new/subspecialist/tycovar.go new file mode 100644 index 00000000..ed4540b8 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/subspecialist/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 subspecialist + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/subspecialist" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Subspecialist, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Subspecialist, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Subspecialist, 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/simgos-sync-use-case/new/unit/case.go b/internal/use-case/simgos-sync-use-case/new/unit/case.go new file mode 100644 index 00000000..3450a4cb --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/unit/case.go @@ -0,0 +1,198 @@ +package unit + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/unit" + esimgos "simrs-vx/internal/domain/simgos-entities/m-poly" + elog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/unit" +) + +const source = "unit" + +func Create(input e.CreateDto) (*d.Data, error) { + var ( + sgData *esimgos.MPoly + syncLink *esync.UnitLink + err error + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to simgos + sgData, err = CreateSimgosData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to Link + syncLink, err = CreateLinkData(*input.Id, sgData.Kode, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // STEP 1: Get Installation Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // Step 2: Update Simgos + err = UpdateSimgosData(input, syncLink, &event, tx) + if err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Installation Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete M_Poly Simgos + err = HardDeleteSimgosData(sgData, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Delete Installation Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(uint(*input.Id), sgData.Kode, &event) + }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/new/unit/helper.go b/internal/use-case/simgos-sync-use-case/new/unit/helper.go new file mode 100644 index 00000000..d7dfb1f6 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/unit/helper.go @@ -0,0 +1,62 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package unit + +import ( + "encoding/json" + erc "simrs-vx/internal/domain/references/common" + "strconv" + + e "simrs-vx/internal/domain/main-entities/unit" + + esimgos "simrs-vx/internal/domain/simgos-entities/m-poly" + esyncLog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/unit" +) + +func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MPoly) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Nama = inputSrc.Name + data.Jenispoly = 0 + + kodePoly, _ := strconv.Atoi(inputSrc.Code) + data.Kode = uint(kodePoly) + return +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.UnitSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.UnitLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/new/unit/lib.go b/internal/use-case/simgos-sync-use-case/new/unit/lib.go new file mode 100644 index 00000000..8712ab03 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/new/unit/lib.go @@ -0,0 +1,188 @@ +package unit + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/unit" + esimgos "simrs-vx/internal/domain/simgos-entities/m-poly" + esynclog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/unit" +) + +var now = time.Now() + +func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MPoly, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setDataSimgos(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MPoly, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := esimgos.MPoly{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"kode\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.UnitLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + data := setDataSimgos(&input) + data.Kode = dataSimgos.Simgos_Id + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 HardDeleteSimgosData(data *esimgos.MPoly, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + 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 +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.UnitLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.UnitLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.UnitLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.UnitLink, 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 +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/main-use-case/room/middleware-runner.go b/internal/use-case/simgos-sync-use-case/new/unit/middleware-runner.go similarity index 88% rename from internal/use-case/main-use-case/room/middleware-runner.go rename to internal/use-case/simgos-sync-use-case/new/unit/middleware-runner.go index eaeb46fd..64426eb9 100644 --- a/internal/use-case/main-use-case/room/middleware-runner.go +++ b/internal/use-case/simgos-sync-use-case/new/unit/middleware-runner.go @@ -1,11 +1,12 @@ -package room +package unit import ( - e "simrs-vx/internal/domain/main-entities/room" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/unit" ) type middlewareRunner struct { @@ -23,7 +24,7 @@ func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Room) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Unit) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -38,7 +39,7 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e return nil } -func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Room) error { +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Unit) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -53,7 +54,7 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu return nil } -func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Room) error { +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,7 +69,7 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Room) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -83,7 +84,7 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Room) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { for _, middleware := range middlewares { logData := pu.GetLogData(input, data) diff --git a/internal/use-case/main-use-case/room/middleware.go b/internal/use-case/simgos-sync-use-case/new/unit/middleware.go similarity index 94% rename from internal/use-case/main-use-case/room/middleware.go rename to internal/use-case/simgos-sync-use-case/new/unit/middleware.go index 668f18e2..bac48f4d 100644 --- a/internal/use-case/main-use-case/room/middleware.go +++ b/internal/use-case/simgos-sync-use-case/new/unit/middleware.go @@ -1,4 +1,4 @@ -package room +package unit // example of middleware // func init() { diff --git a/internal/use-case/main-use-case/room/tycovar.go b/internal/use-case/simgos-sync-use-case/new/unit/tycovar.go similarity index 78% rename from internal/use-case/main-use-case/room/tycovar.go rename to internal/use-case/simgos-sync-use-case/new/unit/tycovar.go index 789e3f6f..e1a7c69f 100644 --- a/internal/use-case/main-use-case/room/tycovar.go +++ b/internal/use-case/simgos-sync-use-case/new/unit/tycovar.go @@ -6,27 +6,27 @@ 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 room +package unit import ( "gorm.io/gorm" - e "simrs-vx/internal/domain/main-entities/room" + e "simrs-vx/internal/domain/main-entities/unit" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Room, tx *gorm.DB) error + Func func(input *e.CreateDto, data *e.Unit, tx *gorm.DB) error } type readListMw struct { Name string - Func func(input *e.ReadListDto, data *e.Room, tx *gorm.DB) error + Func func(input *e.ReadListDto, data *e.Unit, tx *gorm.DB) error } type readDetailMw struct { Name string - Func func(input *e.ReadDetailDto, data *e.Room, tx *gorm.DB) error + Func func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error } type UpdateMw = readDetailMw diff --git a/internal/use-case/simgos-sync-use-case/old/patient/case.go b/internal/use-case/simgos-sync-use-case/old/patient/case.go new file mode 100644 index 00000000..09afa2bd --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/old/patient/case.go @@ -0,0 +1,165 @@ +package patient + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + cfg "simrs-vx/internal/infra/sync-cfg" + pl "simrs-vx/pkg/logger" + + e "simrs-vx/internal/domain/main-entities/patient" + un "simrs-vx/internal/use-case/simgos-sync-use-case/new/patient" + + d "github.com/karincake/dodol" +) + +const source = "old-to-new-patient" + +var path = "patient" + +func Create(input e.Patient) (*d.Data, error) { + evt := pl.Event{ + Feature: "Create", + Source: source, + } + + pl.SetLogInfo(&evt, input, "started", "create") + + // create request body + jsonPatient, err := json.Marshal(input) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + reqBody := bytes.NewBuffer(jsonPatient) + // send data to main-api + resp, err := send(http.MethodPost, path, reqBody, *input.RegisteredBy_User_Name) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + // getting response + var data MainApiResp + err = json.Unmarshal(resp, &data) + if err != nil { + return nil, pl.SetLogError(&evt, string(resp)) + } + // create PatientLink + un.CreateLinkData(data.Data.Id, input.Id, &evt) + pl.SetLogInfo(&evt, nil, "complete") + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: input.ToResponse(), + }, nil +} + +func Update(input e.Patient) (*d.Data, error) { + evt := pl.Event{ + Feature: "Update", + Source: source, + } + pl.SetLogInfo(&evt, input, "started", "update") + + // get patient link from database + patientLink, err := ReadDetailLinkData(input.Id) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + + // get data patient from main-api + resp, err := send(http.MethodGet, fmt.Sprintf("%s%v", "patient/", patientLink.Simx_Id), nil, *input.RegisteredBy_User_Name) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + // unpack data from resp + var respData MainApiResp + err = json.Unmarshal(resp, &respData) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + + // copy data from simgos m_patient to simx Patient + preserve := map[string]bool{ + "Main.Id": true, + "Person.Id": true, + } + simxPatient := respData.Data + SetPatient(&simxPatient, &input, preserve) + + jsonPatient, err := json.Marshal(simxPatient) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + + // send data to main api + url := fmt.Sprintf("%s%v", "patient/", simxPatient.Id) + reqBody := bytes.NewBuffer(jsonPatient) + _, err = send(http.MethodPatch, url, reqBody, *input.RegisteredBy_User_Name) + if err != nil { + return nil, pl.SetLogError(&evt, input) + } + + pl.SetLogInfo(&evt, nil, "complete") + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: input.ToResponse(), + }, nil +} + +func Delete(input e.Patient) (*d.Data, error) { + evt := pl.Event{ + Feature: "Delete", + Source: source, + } + pl.SetLogInfo(&evt, input, "started", "delete") + + // get patient link from database + patientLink, err := ReadDetailLinkData(input.Id) + if err != nil { + return nil, err + } + _, err = send(http.MethodDelete, fmt.Sprintf("%s%v", "patient/", patientLink.Simx_Id), nil, *input.RegisteredBy_User_Name) + if err != nil { + return nil, err + } + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: input.ToResponse(), + }, nil +} + +func send(method string, endpoint string, body *bytes.Buffer, username string) ([]byte, error) { + var url string = cfg.O.NewHost + endpoint + var reader io.Reader = nil + if body != nil { + reader = body + } + req, err := http.NewRequest(method, url, reader) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Sync-Source", cfg.O.OldSource) + req.Header.Set("X-Sync-SecretKey", cfg.O.NewSecretKey) + req.Header.Set("X-Sync-UserName", username) + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + respBody, _ := io.ReadAll(resp.Body) + return respBody, nil +} diff --git a/internal/use-case/simgos-sync-use-case/old/patient/helper.go b/internal/use-case/simgos-sync-use-case/old/patient/helper.go new file mode 100644 index 00000000..2d89bff9 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/old/patient/helper.go @@ -0,0 +1,69 @@ +package patient + +import ( + "reflect" + "strings" +) + +func SetPatient(dst, src interface{}, preserve map[string]bool) { + dv := reflect.ValueOf(dst).Elem() + sv := reflect.ValueOf(src).Elem() + + for i := 0; i < dv.NumField(); i++ { + f := dv.Type().Field(i) + fieldName := f.Name + + // skip preserved fields + if preserve[fieldName] { + continue + } + + df := dv.Field(i) + sf := sv.Field(i) + if !df.CanSet() { + // skip unexported skip + continue + } + + switch df.Kind() { + + case reflect.Struct: + nestedPreserve := map[string]bool{} + + for key := range preserve { + if strings.HasPrefix(key, fieldName+".") { + nestedPreserve[strings.TrimPrefix(key, fieldName+".")] = true + } + } + + SetPatient(df.Addr().Interface(), sf.Addr().Interface(), nestedPreserve) + case reflect.Pointer: + // Check if pointer points to a struct + if df.Type().Elem().Kind() == reflect.Struct { + if sf.IsNil() { + break + } + + // If dest pointer is nil, allocate it + if df.IsNil() { + df.Set(reflect.New(df.Type().Elem())) + } + + // Recurse into struct via Elem() + nestedPreserve := map[string]bool{} + for key := range preserve { + if strings.HasPrefix(key, fieldName+".") { + nestedPreserve[strings.TrimPrefix(key, fieldName+".")] = true + } + } + + SetPatient(df.Elem().Addr().Interface(), sf.Elem().Addr().Interface(), nestedPreserve) + } + default: + // Overwrite only when src has non-zero value + if !sf.IsZero() { + df.Set(sf) + } + } + } +} diff --git a/internal/use-case/simgos-sync-use-case/old/patient/lib.go b/internal/use-case/simgos-sync-use-case/old/patient/lib.go new file mode 100644 index 00000000..d6b5f470 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/old/patient/lib.go @@ -0,0 +1,19 @@ +package patient + +import ( + esync "simrs-vx/internal/domain/sync-entities/patient" + + dg "github.com/karincake/apem/db-gorm-pg" +) + +func ReadDetailLinkData(simgosId uint) (*esync.PatientLink, error) { + // log event + var data esync.PatientLink + var tx = dg.I + + if err := tx.Where("\"Simgos_Id\" = ?", simgosId).First(&data).Error; err != nil { + return nil, err + } + // log end event + return &data, nil +} diff --git a/internal/use-case/simgos-sync-use-case/old/patient/tycovar.go b/internal/use-case/simgos-sync-use-case/old/patient/tycovar.go new file mode 100644 index 00000000..15d99d0f --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/old/patient/tycovar.go @@ -0,0 +1,14 @@ +package patient + +import e "simrs-vx/internal/domain/main-entities/patient" + +type MainApiResp struct { + Meta MetaData `json:"meta"` + Data e.Patient `json:"data"` +} + +type MetaData struct { + Source string `json:"source"` + Status string `json:"status"` + Structure string `json:"structure"` +} diff --git a/pkg/conv-helper/conv-helper.go b/pkg/conv-helper/conv-helper.go new file mode 100644 index 00000000..9b9bc44d --- /dev/null +++ b/pkg/conv-helper/conv-helper.go @@ -0,0 +1,161 @@ +package convhelper + +import ( + "fmt" + "strconv" + "time" + + "gorm.io/gorm" +) + +const StandartDateTimeFormat = "2006-01-02 15:04:05" + +// check string pointer, if nil return default value +func StrConvDefault(f *string, def string) string { + if f == nil { + return def + } + return *f +} + +// check string pointer, if nil return empty string +func StrConvEmpty(f *string) string { + return StrConvDefault(f, "-") +} + +func ByteConvStr(f *byte) string { + if f != nil { + return strconv.Itoa(int(*f)) + } + return "" +} + +func Float32Conv(f *float32) float32 { + if f == nil { + return 0 + } + return *f +} + +func StrRelConv(b bool, d string) string { + if b { + return d + } else { + return "" + } +} + +func UintToString(f interface{}) *string { + if f == nil { + return nil + } + + var t string + switch v := f.(type) { + case uint: + t = strconv.FormatUint(uint64(v), 10) + case uint8: + t = strconv.FormatUint(uint64(v), 10) + case uint16: + t = strconv.FormatUint(uint64(v), 10) + case uint32: + t = strconv.FormatUint(uint64(v), 10) + case uint64: + t = strconv.FormatUint(v, 10) + // Handle pointer types + case *uint: + if v != nil { + t = strconv.FormatUint(uint64(*v), 10) + } + case *uint8: + if v != nil { + t = strconv.FormatUint(uint64(*v), 10) + } + case *uint16: + if v != nil { + t = strconv.FormatUint(uint64(*v), 10) + } + case *uint32: + if v != nil { + t = strconv.FormatUint(uint64(*v), 10) + } + case *uint64: + if v != nil { + t = strconv.FormatUint(*v, 10) + } + default: + return nil // Unsupported type + } + + return &t +} + +func BoolToString(f *bool) *string { + if f == nil { + return nil + } + t := strconv.FormatBool(*f) + return &t +} + +// Handling gorm.DeletedAt +func DeletedAtToString(deletedAt *gorm.DeletedAt) *string { + if deletedAt == nil || !deletedAt.Valid { + return nil + } + return TimeToStringWithFormat(&deletedAt.Time, "") +} + +func BoolToFloat64(b bool) float64 { + if b { + return 1.0 + } + return 0.0 +} + +func Float64ToBool(f float64) bool { + return f == 1.0 +} + +func StringToBool(s string) bool { + return s == "1" +} + +func StringToFloat32(s string) float32 { + f, _ := strconv.ParseFloat(s, 32) + return float32(f) +} + +func StringToFloat64(s string) float64 { + f, _ := strconv.ParseFloat(s, 64) + return f +} + +func Float64ToString(f float64) string { + return fmt.Sprintf("%.2f", f) +} + +func StringToUint64(s string) *uint64 { + if s == "" { + return nil + } + u, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return nil + } + return &u +} + +func TimeToStringWithFormat(t *time.Time, format string) *string { + result := "" + if t == nil || t.IsZero() { + return &result + } + + if format == "" { + format = StandartDateTimeFormat + } + + result = t.Format(format) + return &result +} diff --git a/pkg/dualtrx-helper/dualtrx-helper.go b/pkg/dualtrx-helper/dualtrx-helper.go new file mode 100644 index 00000000..144337c5 --- /dev/null +++ b/pkg/dualtrx-helper/dualtrx-helper.go @@ -0,0 +1,69 @@ +package dualtrx_helper + +import ( + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" +) + +type Dualtx struct { + Sync *gorm.DB + Simgos *gorm.DB +} + +func NewDualtx() *Dualtx { + simgosTx := dg.IS["simrs"].Begin() + simgosTx.Exec(`SET LOCAL simx.sync_source = 'new'`) + + return &Dualtx{ + Sync: dg.I.Begin(), + Simgos: simgosTx, + } +} + +func NewTx() *Dualtx { + return &Dualtx{ + Sync: dg.I, + Simgos: dg.IS["simrs"], + } +} + +func (t *Dualtx) Commit() error { + if err := t.Sync.Commit().Error; err != nil { + return err + } + + if err := t.Simgos.Commit().Error; err != nil { + return err + } + return nil +} + +func (t *Dualtx) Rollback() { + t.Sync.Rollback() + t.Simgos.Rollback() +} + +type DualTxFunc func(tx *Dualtx) error + +func WithDualTx(fn DualTxFunc) error { + var ( + tx = NewDualtx() + err error + ) + + defer func() { + if err != nil { + tx.Rollback() + } + }() + + if err = fn(tx); err != nil { + return err + } + + if err = tx.Commit(); err != nil { + return err + } + + return nil +} diff --git a/pkg/file-helper/file-helper.go b/pkg/file-helper/file-helper.go new file mode 100644 index 00000000..bd0849c7 --- /dev/null +++ b/pkg/file-helper/file-helper.go @@ -0,0 +1,33 @@ +package filehelper + +import ( + "fmt" + "os" + "path/filepath" +) + +// const DEFAULT_EXPIRY_FILES = time.Hour * 24 * 7 + +func PathAgreement(medicalNumber string) (string, error) { + outputPath := fmt.Sprintf("./public/patient/%s", medicalNumber) + err := os.MkdirAll(outputPath, os.ModePerm) + return outputPath, err +} + +func PathToSaveFile(outputPath string) (string, error) { + err := os.MkdirAll(outputPath, os.ModePerm) + return outputPath, err +} + +func RenameFile(srcPath, dstPath string) error { + return os.Rename(srcPath, dstPath) +} + +func DeleteFolder(path string) error { + return os.RemoveAll(path) +} + +func PathToUrl(fileName string) *string { + fileUrl := filepath.ToSlash(fmt.Sprintf("%c%s", os.PathSeparator, fileName)) + return &fileUrl +} diff --git a/pkg/handler-crud-helper/handler-crud-helper.go b/pkg/handler-crud-helper/handler-crud-helper.go index df475094..3003e812 100644 --- a/pkg/handler-crud-helper/handler-crud-helper.go +++ b/pkg/handler-crud-helper/handler-crud-helper.go @@ -74,3 +74,36 @@ func RegCrudByCode(r *http.ServeMux, path string, mwAndRouter ...any) { "DELETE /{code}": c.Delete, }) } + +func SyncCrud(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].(SyncCrudBase) + if !ok { + panic("non CrudBase used in the last paramter") + } + + hk.GroupRoutes(path, r, mwList, hk.MapHandlerFunc{ + "POST /": c.Create, + "POST /log": c.CreateLog, + "PATCH /{id}": c.Update, + "DELETE /{id}": c.Delete, + }) +} diff --git a/pkg/handler-crud-helper/types.go b/pkg/handler-crud-helper/types.go index e85f22fc..891af38e 100644 --- a/pkg/handler-crud-helper/types.go +++ b/pkg/handler-crud-helper/types.go @@ -9,3 +9,10 @@ type CrudBase interface { Update(w http.ResponseWriter, r *http.Request) Delete(w http.ResponseWriter, r *http.Request) } + +type SyncCrudBase interface { + Create(w http.ResponseWriter, r *http.Request) + CreateLog(w http.ResponseWriter, r *http.Request) + Update(w http.ResponseWriter, r *http.Request) + Delete(w http.ResponseWriter, r *http.Request) +} diff --git a/pkg/pdf-helper/pdf-helper.go b/pkg/pdf-helper/pdf-helper.go new file mode 100644 index 00000000..9b1dc129 --- /dev/null +++ b/pkg/pdf-helper/pdf-helper.go @@ -0,0 +1,147 @@ +package pdfhelper + +import ( + "bytes" + "html/template" + "log" + "os" + "os/exec" + "strconv" + "strings" + "time" + + "github.com/SebastiaanKlippert/go-wkhtmltopdf" +) + +// pdf requestpdf struct +type RequestPdf struct { + body string +} + +// new request to pdf function +func NewRequestPdf(body string) *RequestPdf { + return &RequestPdf{ + body: body, + } +} + +// parsing template function +func (r *RequestPdf) ParseTemplate(templatePath string, data interface{}) error { + f := strings.Split(templatePath, "/") + fileName := f[len(f)-1] + funcs := template.FuncMap{ + "nl2br": func(text string) template.HTML { + return template.HTML(strings.Replace(template.HTMLEscapeString(text), "\n", "
", -1)) + }, + "safeHTML": func(text string) template.HTML { + return template.HTML(text) + }, + } + t, err := template.New(fileName).Funcs(funcs).ParseFiles(templatePath) + if err != nil { + return err + } + buf := new(bytes.Buffer) + if err = t.Execute(buf, data); err != nil { + return err + } + r.body = buf.String() + + return nil +} + +func (r *RequestPdf) GenerateByCommand(pdfPath string, templatePath string, useA5Lanscape bool) (bool, error) { + t := time.Now().Unix() + var cmd *exec.Cmd + + if _, err := os.Stat("cloneTemplate/"); os.IsNotExist(err) { + errDir := os.Mkdir("cloneTemplate/", 0777) + if errDir != nil { + log.Fatal(errDir) + } + } + htmlName := strconv.FormatInt(int64(t), 10) + ".html" + err := os.WriteFile("cloneTemplate/"+htmlName, []byte(r.body), 0644) + if err != nil { + panic(err) + } + + if !useA5Lanscape { + cmd = exec.Command("wkhtmltopdf", "--enable-local-file-access", "-L", "0", "-R", "0", "-B", "0", "-s", "A4", "cloneTemplate/"+htmlName, pdfPath) + } else { + cmd = exec.Command("wkhtmltopdf", + "--enable-local-file-access", + "-L", "0", // left margin + "-R", "0", // right margin + "-B", "0", // bottom margin + "-T", "0", // top margin + "-s", "A5", // page size A5 + "-O", "Landscape", // landscape mode + "cloneTemplate/"+htmlName, + pdfPath) + } + + if err := cmd.Run(); err != nil { + return false, err + } + dir, err := os.Getwd() + if err != nil { + panic(err) + } + defer os.RemoveAll(dir + "/cloneTemplate") + return true, nil +} + +// generate pdf function +func (r *RequestPdf) GeneratePDF(pdfPath string) (bool, error) { + t := time.Now().Unix() + + if _, err := os.Stat("cloneTemplate/"); os.IsNotExist(err) { + errDir := os.Mkdir("cloneTemplate/", 0777) + if errDir != nil { + log.Fatal(errDir) + } + } + err1 := os.WriteFile("cloneTemplate/"+strconv.FormatInt(int64(t), 10)+".html", []byte(r.body), 0644) + if err1 != nil { + panic(err1) + } + + f, err := os.Open("cloneTemplate/" + strconv.FormatInt(int64(t), 10) + ".html") + if f != nil { + defer f.Close() + } + if err != nil { + log.Fatal(err) + } + + pdfg, err := wkhtmltopdf.NewPDFGenerator() + if err != nil { + log.Fatal(err) + } + + pdfg.AddPage(wkhtmltopdf.NewPageReader(f)) + + pdfg.PageSize.Set(wkhtmltopdf.PageSizeA4) + + pdfg.Dpi.Set(300) + + err = pdfg.Create() + if err != nil { + log.Fatal(err) + } + + err = pdfg.WriteFile(pdfPath) + if err != nil { + log.Fatal(err) + } + + dir, err := os.Getwd() + if err != nil { + panic(err) + } + + defer os.RemoveAll(dir + "/cloneTemplate") + + return true, nil +} diff --git a/pkg/upload-helper/upload-helper.go b/pkg/upload-helper/upload-helper.go index d6f1cd29..0dce8fd7 100644 --- a/pkg/upload-helper/upload-helper.go +++ b/pkg/upload-helper/upload-helper.go @@ -5,21 +5,21 @@ import ( "path/filepath" "strings" - ere "simrs-vx/internal/domain/references/upload" + ere "simrs-vx/internal/domain/references/encounter" ) func getBucketForType(docType string) (string, error) { switch strings.ToLower(docType) { case "resident", "resident-number", "ktp": - return string(ere.UCPRN), nil + return string(ere.DTCPRN), nil case "driver-license", "sim", "license": - return string(ere.UCPDL), nil + return string(ere.DTCPDL), nil case "passport", "paspor": - return string(ere.UCPP), nil + return string(ere.DTCPP), nil case "family-card", "kk", "family": - return string(ere.UCPFC), nil + return string(ere.DTCPFC), nil case "mcu", "medical", "mcu-result": - return string(ere.UCMIR), nil + return string(ere.DTCMIR), nil default: return "", fmt.Errorf("unknown document type: %s", docType) } @@ -28,9 +28,9 @@ func getBucketForType(docType string) (string, error) { // getValidFileTypesForBucket returns allowed file types for each bucket func getValidFileTypesForBucket(bucketName string) []string { switch bucketName { - case string(ere.UCPRN), string(ere.UCPDL), string(ere.UCPP), string(ere.UCPFC): + case string(ere.DTCPRN), string(ere.DTCPDL), string(ere.DTCPP), string(ere.DTCPFC): return []string{".jpg", ".jpeg", ".png", ".pdf", ".gif"} - case string(ere.UCMIR): + case string(ere.DTCMIR): return []string{".jpg", ".jpeg", ".png", ".pdf", ".gif", ".doc", ".docx", ".xls", ".xlsx"} default: return []string{".jpg", ".jpeg", ".png", ".pdf"} diff --git a/pkg/use-case-helper/use-case-helper.go b/pkg/use-case-helper/use-case-helper.go index a80595bb..7d0ec17f 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" + "net/url" "strings" "time" @@ -150,3 +151,70 @@ func IsDateBeforeNow(t *time.Time) bool { } return t.Before(time.Now()) } + +// Contains reports whether v is present in s. +func Contains[S ~[]E, E comparable](s S, v E) bool { + return index(s, v) >= 0 +} + +// Index returns the index of the first occurrence of v in s, +// or -1 if not present. +func index[S ~[]E, E comparable](s S, v E) int { + for i := range s { + if v == s[i] { + return i + } + } + return -1 +} + +func FormatIndonesianDate(t time.Time) string { + monthNames := [...]string{ + "", // dummy index 0 + "Januari", + "Februari", + "Maret", + "April", + "Mei", + "Juni", + "Juli", + "Agustus", + "September", + "Oktober", + "November", + "Desember", + } + + return fmt.Sprintf("%d %s %d", t.Day(), monthNames[int(t.Month())], t.Year()) +} + +func GetLastTwoPathSegments(s string) string { + u, err := url.Parse(s) + var path string + + if err == nil && u.Path != "" { + path = u.Path + } else { + path = s + } + + parts := strings.Split(strings.Trim(path, "/"), "/") + n := len(parts) + + if n >= 2 { + return parts[n-2] + "/" + parts[n-1] + } + + // fallback: return entire string if less than 2 segments + return strings.Trim(path, "/") +} + +func FormatPlaceAndDate(place string, t time.Time) string { + // Ensure place is uppercase + place = strings.ToUpper(strings.TrimSpace(place)) + + // Format date: DD-MM-YYYY + dateStr := t.Format("02-01-2006") + + return place + ", " + dateStr +}