Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions controllers/login_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ func NewLoginHandler(r gin.IRouter, us entities.LoginUseCase, secretKey []byte)
}

func (l *LoginHandler) Login(c *gin.Context) {
// username and password are in the json body
// username is in the json body
var u entities.LoginPayload
if err := c.ShouldBindJSON(&u); err != nil {
// Use type assertion to check if err is of type validator.ValidationErrors
if _, ok := err.(validator.ValidationErrors); ok {
c.JSON(http.StatusBadRequest, gin.H{"error": "Username or password must be a non-empty string!"})
c.JSON(http.StatusBadRequest, gin.H{"error": "Username must be a non-empty string!"})
return // exit on first error
} else {
// Handle other types of errors (e.g., JSON binding errors)
Expand Down
31 changes: 31 additions & 0 deletions controllers/prescription_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"sothea-backend/controllers/middleware"
"sothea-backend/entities"
"sothea-backend/repository/postgres"
db "sothea-backend/repository/sqlc"
)

Expand Down Expand Up @@ -187,6 +188,16 @@ func (h *PrescriptionHandler) AddLine(c *gin.Context) {
ctx := c.Request.Context()
created, err := h.Usecase.AddLine(ctx, &line)
if err != nil {
if stockErr, ok := err.(*postgres.InsufficientStockError); ok {
c.JSON(http.StatusBadRequest, gin.H{
"error": stockErr.Error(),
"code": stockErr.Code(),
"drug_id": stockErr.DrugID,
"total_required": stockErr.TotalRequired,
"total_available": stockErr.TotalAvailable,
})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
Expand Down Expand Up @@ -224,6 +235,16 @@ func (h *PrescriptionHandler) UpdateLine(c *gin.Context) {
ctx := c.Request.Context()
updated, err := h.Usecase.UpdateLine(ctx, &line)
if err != nil {
if stockErr, ok := err.(*postgres.InsufficientStockError); ok {
c.JSON(http.StatusBadRequest, gin.H{
"error": stockErr.Error(),
"code": stockErr.Code(),
"drug_id": stockErr.DrugID,
"total_required": stockErr.TotalRequired,
"total_available": stockErr.TotalAvailable,
})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
Expand Down Expand Up @@ -286,6 +307,16 @@ func (h *PrescriptionHandler) SetLineAllocations(c *gin.Context) {
ctx := c.Request.Context()
out, err := h.Usecase.SetLineAllocations(ctx, lineID, allocs)
if err != nil {
if stockErr, ok := err.(*postgres.InsufficientStockError); ok {
c.JSON(http.StatusBadRequest, gin.H{
"error": stockErr.Error(),
"code": stockErr.Code(),
"drug_id": stockErr.DrugID,
"total_required": stockErr.TotalRequired,
"total_available": stockErr.TotalAvailable,
})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
Expand Down
14 changes: 9 additions & 5 deletions db/queries/prescriptions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ RETURNING id, created_at, updated_at;

-- name: GetPrescriptionHeader :one
SELECT p.id, p.patient_id, p.vid, p.notes,
p.created_by, p.created_at, p.updated_at,
p.created_by, p.created_at, p.updated_at, p.updated_by,
p.is_dispensed, p.dispensed_by, p.dispensed_at,
uc.name AS creator_name,
uu.name AS updater_name,
ud.name AS dispenser_name
FROM prescriptions p
LEFT JOIN users uc ON uc.id = p.created_by
LEFT JOIN users uu ON uu.id = p.updated_by
LEFT JOIN users ud ON ud.id = p.dispensed_by
WHERE p.id = $1;

Expand All @@ -23,8 +25,9 @@ SELECT
pl.frequency_code,
pl.duration, pl.duration_unit,
pl.total_to_dispense, pl.is_packed, pl.packed_by, pl.packed_at,
u1.name AS packer_name,
u2.name AS updater_name,
u_packer.name AS packer_name,
u_updater.name AS updater_name,
u_creator.name AS creator_name,
d.generic_name AS drug_name,
d.route_code AS route_code,
d.dispense_unit AS dispense_unit,
Expand All @@ -36,8 +39,9 @@ SELECT
END AS display_strength
FROM prescription_lines pl
LEFT JOIN drugs d ON d.id = pl.drug_id
LEFT JOIN users u1 ON u1.id = pl.packed_by
LEFT JOIN users u2 ON u2.id = pl.updated_by
LEFT JOIN users u_packer ON u_packer.id = pl.packed_by
LEFT JOIN users u_updater ON u_updater.id = pl.updated_by
LEFT JOIN users u_creator ON u_creator.id = pl.created_by
WHERE pl.prescription_id = $1
ORDER BY pl.id;

Expand Down
4 changes: 2 additions & 2 deletions db/queries/users.sql
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
-- name: GetUserByUsername :one
SELECT id, username, password_hash
SELECT id, username
FROM users
WHERE username = $1;

-- name: GetUserByID :one
SELECT id, username, password_hash
SELECT id, username
FROM users
WHERE id = $1;
66 changes: 64 additions & 2 deletions db/schema/patients.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ CREATE TABLE patient_details
gender VARCHAR(1) NOT NULL,
village TEXT NOT NULL,
contact_no TEXT NOT NULL,
drug_allergies TEXT
drug_allergies TEXT,

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id)
);

CREATE TABLE admin
Expand All @@ -20,6 +25,12 @@ CREATE TABLE admin
pregnant BOOLEAN NOT NULL,
last_menstrual_period DATE,
sent_to_id BOOLEAN NOT NULL,

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid) -- Composite primary key
);

Expand All @@ -43,6 +54,12 @@ CREATE TABLE past_medical_history
sexually_transmitted_disease BOOLEAN, -- Allow NULL for 'Nil' option
specified_stds TEXT,
others TEXT,

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid), -- Composite primary key
CONSTRAINT fk_admin FOREIGN KEY (id, vid) REFERENCES admin (id, vid) ON DELETE CASCADE -- Foreign key referencing the composite key in admin
);
Expand All @@ -57,6 +74,12 @@ CREATE TABLE social_history
cigarettes_per_day INTEGER,
alcohol_history BOOLEAN NOT NULL,
how_regular VARCHAR(1),

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid), -- Composite primary key
CONSTRAINT fk_admin FOREIGN KEY (id, vid) REFERENCES admin (id, vid) ON DELETE CASCADE -- Foreign key referencing the composite key in admin
);
Expand All @@ -78,6 +101,12 @@ CREATE TABLE vital_statistics
avg_hr NUMERIC(5, 1) NOT NULL,
rand_blood_glucose_mmol_l NUMERIC(5, 1),
icope_high_bp BOOLEAN,

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid), -- Composite primary key
CONSTRAINT fk_admin FOREIGN KEY (id, vid) REFERENCES admin (id, vid) ON DELETE CASCADE -- Foreign key referencing the composite key in admin
);
Expand All @@ -95,6 +124,12 @@ CREATE TABLE height_and_weight

icope_lost_weight_past_months BOOLEAN,
icope_no_desire_to_eat BOOLEAN,

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid), -- Composite primary key
CONSTRAINT fk_admin FOREIGN KEY (id, vid) REFERENCES admin (id, vid) ON DELETE CASCADE -- Foreign key referencing the composite key in admin
);
Expand All @@ -112,6 +147,11 @@ CREATE TABLE visual_acuity
icope_eye_problem BOOLEAN,
icope_treated_for_diabetes_or_bp BOOLEAN,

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid), -- Composite primary key
CONSTRAINT fk_admin FOREIGN KEY (id, vid) REFERENCES admin (id, vid) ON DELETE CASCADE -- Foreign key referencing the composite key in admin
);
Expand All @@ -130,6 +170,11 @@ CREATE TABLE dental
icope_pain_in_mouth BOOLEAN,
dental_notes TEXT,

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid), -- Composite primary key
CONSTRAINT fk_admin FOREIGN KEY (id, vid) REFERENCES admin (id, vid) ON DELETE CASCADE -- Foreign key referencing the composite key in admin
);
Expand All @@ -146,6 +191,11 @@ CREATE TABLE fall_risk
fall_risk_score INTEGER NOT NULL,
icope_complete_chair_stands BOOLEAN,
icope_chair_stands_time BOOLEAN,

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid), -- Composite primary key
CONSTRAINT fk_admin FOREIGN KEY (id, vid) REFERENCES admin (id, vid) ON DELETE CASCADE -- Foreign key referencing the composite key in admin
Expand All @@ -170,6 +220,12 @@ CREATE TABLE doctors_consultation
referral_needed BOOLEAN NOT NULL,
referral_loc TEXT,
remarks TEXT,

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid), -- Composite primary key
CONSTRAINT fk_admin FOREIGN KEY (id, vid) REFERENCES admin (id, vid) -- Foreign key referencing the composite key in admin
);
Expand All @@ -183,6 +239,12 @@ CREATE TABLE physiotherapy
objective_assessment TEXT, -- Objective Assessment (Open Ended)
intervention TEXT, -- Intervention (Open Ended)
evaluation TEXT, -- Evaluation (Open Ended)

created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES users(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES users(id),

PRIMARY KEY (id, vid), -- Composite primary key
CONSTRAINT fk_admin FOREIGN KEY (id, vid) REFERENCES admin (id, vid) -- Foreign key referencing the composite key in admin
);
);
3 changes: 1 addition & 2 deletions db/schema/users.sql
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
/*******************
Add usernames and passwords
Add usernames
*/
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
name TEXT,
password_hash TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
Expand Down
7 changes: 5 additions & 2 deletions entities/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,15 @@ type DrugStock struct {

type Prescription struct {
db.Prescription
Lines []PrescriptionLine `json:"lines"`
DispenserName *string `json:"dispenser_name"`
Lines []PrescriptionLine `json:"lines"`
}

type PrescriptionLine struct {
db.PrescriptionLine
PackerName *string `json:"packer_name"`
UpdaterName *string `json:"updater_name"`
CreatorName *string `json:"creator_name"`
Allocations []db.PrescriptionBatchItem `json:"allocations"`
DispenseUnit string `json:"dispense_unit,omitempty"`
}
Expand All @@ -106,7 +110,6 @@ type SetAllocReq struct {

type LoginPayload struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}

// ---------------- Interfaces ----------------
Expand Down
5 changes: 2 additions & 3 deletions repository/postgres/postgres_patient.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,9 +472,8 @@ func (p *postgresPatientRepository) GetDBUser(ctx context.Context, username stri
return nil, err
}
return &db.User{
ID: row.ID,
Username: row.Username,
PasswordHash: row.PasswordHash,
ID: row.ID,
Username: row.Username,
}, nil
}

Expand Down
13 changes: 8 additions & 5 deletions repository/postgres/postgres_prescription_errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (
"errors"
"fmt"

"github.com/lib/pq"
"github.com/jackc/pgx/v5/pgconn"
)

type InsufficientStockError struct {
PresentationID int64 `json:"presentation+id"`
DrugID int64 `json:"drug_id"`
TotalRequired int64 `json:"total_required"`
TotalAvailable int64 `json:"total_available"`
}
Expand All @@ -20,14 +20,17 @@ func (e *InsufficientStockError) Error() string {
func (e *InsufficientStockError) Code() string { return "INSUFFICIENT_STOCK" }

func mapPrescriptionSQLError(err error) error {
var pe *pq.Error
var pe *pgconn.PgError
if !errors.As(err, &pe) {
return err
}
// 23514 = check_violation; you raised with CONSTRAINT 'ck_insufficient_stock'
if string(pe.Code) == "23514" && pe.Constraint == "ck_insufficient_stock" {
if pe.Code == "23514" && pe.ConstraintName == "ck_insufficient_stock" {
var d InsufficientStockError
_ = json.Unmarshal([]byte(pe.Detail), &d)
if err := json.Unmarshal([]byte(pe.Detail), &d); err != nil {
// If unmarshaling fails, return the original error with detail
return fmt.Errorf("insufficient stock: %s", pe.Detail)
}
return &d
}
return err
Expand Down
4 changes: 4 additions & 0 deletions repository/postgres/postgres_prescriptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ func (r *postgresPrescriptionRepository) GetPrescriptionByID(ctx context.Context
DispensedBy: header.DispensedBy,
DispensedAt: header.DispensedAt,
},
DispenserName: header.DispenserName,
}

lineRows, err := q.ListPrescriptionLines(ctx, id)
Expand All @@ -131,6 +132,9 @@ func (r *postgresPrescriptionRepository) GetPrescriptionByID(ctx context.Context
PackedBy: row.PackedBy,
PackedAt: row.PackedAt,
},
PackerName: row.PackerName,
UpdaterName: row.UpdaterName,
CreatorName: row.CreatorName,
}
lines = append(lines, l)
lineIDs = append(lineIDs, row.ID)
Expand Down
2 changes: 1 addition & 1 deletion repository/sqlc/db.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading