Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
83e0557
[#639] Create alemnbic migration for Oct 2025 PL updates
wayangalihpratama Oct 22, 2025
c66618f
[#639] Remove is_option column from migration
wayangalihpratama Oct 22, 2025
46a4b75
[#639] Create new models & initial schema for new PL
wayangalihpratama Oct 22, 2025
c3b64d3
[#639] Create new PL transformer
wayangalihpratama Oct 22, 2025
9cf6cc8
[#639] Create new PL seeder
wayangalihpratama Oct 22, 2025
1ace538
[#639] Use v2 naming
wayangalihpratama Oct 22, 2025
048d828
[#639] Init pl practice v2 routes
wayangalihpratama Oct 22, 2025
461f742
[#639] Remove unused params from serializer property
wayangalihpratama Oct 22, 2025
9813659
Merge branch 'main' into feature/639-new-procurement-library-oct-2025
wayangalihpratama Oct 24, 2025
378e801
[#639] Update sourcing strategy cycle attribut name
wayangalihpratama Oct 24, 2025
b6ee86c
[#639] Fix lint
wayangalihpratama Oct 24, 2025
5b4d815
[#639] Add category/attributes endpoint & update pratice get all
wayangalihpratama Oct 24, 2025
ff2b620
[#639] Create GET practices by attributes ID endpoint
wayangalihpratama Oct 24, 2025
b62dfeb
[#639] Create test case for PL v2 models and practices endpoints
wayangalihpratama Oct 24, 2025
b9ead90
[#639] Create test case for category attributes endpoint
wayangalihpratama Oct 24, 2025
5c83674
Merge branch 'main' into feature/639-new-procurement-library-oct-2025
wayangalihpratama Oct 27, 2025
478e293
[#639] Add filter by attributes_id into get practices by attribute en…
wayangalihpratama Oct 27, 2025
4df7238
Merge branch 'main' into feature/639-new-procurement-library-oct-2025
wayangalihpratama Nov 10, 2025
93dc040
Merge branch 'main' into feature/639-new-procurement-library-oct-2025
wayangalihpratama Nov 10, 2025
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""create new procurement library updates oct 2025

Revision ID: 92819753edfb
Revises: 7d088afac59f
Create Date: 2025-10-22 01:01:07.013270

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = '92819753edfb'
down_revision: Union[str, None] = '7d088afac59f'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# === pl_category ===
op.create_table(
"pl_category",
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
sa.Column("name", sa.String(length=125), nullable=False),
sa.Column("description", sa.Text(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), nullable=False, server_default=sa.func.now(), onupdate=sa.func.now()),
)
op.create_index(op.f("ix_pl_category_id"), "pl_category", ["id"], unique=True)
op.create_index(op.f("ix_pl_category_name"), "pl_category", ["name"], unique=False)

# === pl_attribute ===
op.create_table(
"pl_attribute",
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
sa.Column(
"category_id",
sa.Integer(),
sa.ForeignKey("pl_category.id", ondelete="SET NULL"),
nullable=True,
),
sa.Column("label", sa.String(length=125), nullable=False),
sa.Column("description", sa.Text(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), nullable=False, server_default=sa.func.now(), onupdate=sa.func.now()),
)
op.create_index(op.f("ix_pl_attribute_id"), "pl_attribute", ["id"], unique=True)
op.create_index(op.f("ix_pl_attribute_label"), "pl_attribute", ["label"], unique=False)
op.create_index(op.f("ix_pl_attribute_category_id"), "pl_attribute", ["category_id"], unique=False)

# === pl_practice_intervention ===
op.create_table(
"pl_practice_intervention",
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
sa.Column("label", sa.String(length=225), nullable=False),
sa.Column("intervention_definition", sa.Text(), nullable=True),
sa.Column("enabling_conditions", sa.Text(), nullable=True),
sa.Column("business_rationale", sa.Text(), nullable=True),
sa.Column("farmer_rationale", sa.Text(), nullable=True),
sa.Column("risks_n_trade_offs", sa.Text(), nullable=True),
sa.Column("intervention_impact_income", sa.Text(), nullable=True),
sa.Column("intervention_impact_env", sa.Text(), nullable=True),
sa.Column("source_or_evidence", sa.Text(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), nullable=False, server_default=sa.func.now(), onupdate=sa.func.now()),
)
op.create_index(op.f("ix_pl_practice_intervention_id"), "pl_practice_intervention", ["id"], unique=True)
op.create_index(op.f("ix_pl_practice_intervention_label"), "pl_practice_intervention", ["label"], unique=False)

# === pl_practice_intervention_tag ===
op.create_table(
"pl_practice_intervention_tag",
sa.Column(
"practice_intervention_id",
sa.Integer(),
sa.ForeignKey("pl_practice_intervention.id", ondelete="CASCADE"),
primary_key=True,
),
sa.Column(
"attribute_id",
sa.Integer(),
sa.ForeignKey("pl_attribute.id", ondelete="CASCADE"),
primary_key=True,
),
sa.Column("created_at", sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), nullable=False, server_default=sa.func.now(), onupdate=sa.func.now()),
)
op.create_index(op.f("ix_pl_practice_intervention_tag_practice_intervention_id"), "pl_practice_intervention_tag", ["practice_intervention_id"], unique=False)
op.create_index(op.f("ix_pl_practice_intervention_tag_attribute_id"), "pl_practice_intervention_tag", ["attribute_id"], unique=False)

# === pl_indicator ===
op.create_table(
"pl_indicator",
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
sa.Column("name", sa.String(length=50), nullable=False),
sa.Column("label", sa.String(length=125), nullable=False),
sa.Column("description", sa.Text(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), nullable=False, server_default=sa.func.now(), onupdate=sa.func.now()),
)
op.create_index(op.f("ix_pl_indicator_id"), "pl_indicator", ["id"], unique=True)
op.create_index(op.f("ix_pl_indicator_name"), "pl_indicator", ["name"], unique=True)
op.create_index(op.f("ix_pl_indicator_label"), "pl_indicator", ["label"], unique=False)

# === pl_practice_intervention_indicator_score ===
op.create_table(
"pl_practice_intervention_indicator_score",
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
sa.Column(
"practice_intervention_id",
sa.Integer(),
sa.ForeignKey("pl_practice_intervention.id", ondelete="CASCADE"),
nullable=False,
),
sa.Column(
"indicator_id",
sa.Integer(),
sa.ForeignKey("pl_indicator.id", ondelete="CASCADE"),
nullable=False,
),
sa.Column("score", sa.Float(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False, server_default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), nullable=False, server_default=sa.func.now(), onupdate=sa.func.now()),
)
op.create_index(op.f("ix_pl_practice_intervention_indicator_score_id"), "pl_practice_intervention_indicator_score", ["id"], unique=True)
op.create_index(op.f("ix_pl_practice_intervention_indicator_score_practice_intervention_id"), "pl_practice_intervention_indicator_score", ["practice_intervention_id"], unique=False)
op.create_index(op.f("ix_pl_practice_intervention_indicator_score_indicator_id"), "pl_practice_intervention_indicator_score", ["indicator_id"], unique=False)
op.create_unique_constraint(
"uq_pl_practice_intervention_indicator_score_practice_indicator",
"pl_practice_intervention_indicator_score",
["practice_intervention_id", "indicator_id"],
)


def downgrade() -> None:
op.drop_constraint("uq_pl_practice_intervention_indicator_score_practice_indicator", "pl_practice_intervention_indicator_score", type_="unique")
op.drop_index(op.f("ix_pl_practice_intervention_indicator_score_id"), table_name="pl_practice_intervention_indicator_score")
op.drop_index(op.f("ix_pl_practice_intervention_indicator_score_practice_intervention_id"), table_name="pl_practice_intervention_indicator_score")
op.drop_index(op.f("ix_pl_practice_intervention_indicator_score_indicator_id"), table_name="pl_practice_intervention_indicator_score")
op.drop_table("pl_practice_intervention_indicator_score")

op.drop_index(op.f("ix_pl_indicator_id"), table_name="pl_indicator")
op.drop_index(op.f("ix_pl_indicator_name"), table_name="pl_indicator")
op.drop_index(op.f("ix_pl_indicator_label"), table_name="pl_indicator")
op.drop_table("pl_indicator")

op.drop_index(op.f("ix_pl_practice_intervention_tag_practice_intervention_id"), table_name="pl_practice_intervention_tag")
op.drop_index(op.f("ix_pl_practice_intervention_tag_attribute_id"), table_name="pl_practice_intervention_tag")
op.drop_table("pl_practice_intervention_tag")

op.drop_index(op.f("ix_pl_practice_intervention_id"), table_name="pl_practice_intervention")
op.drop_index(op.f("ix_pl_practice_intervention_label"), table_name="pl_practice_intervention")
op.drop_table("pl_practice_intervention")

op.drop_index(op.f("ix_pl_attribute_id"), table_name="pl_attribute")
op.drop_index(op.f("ix_pl_attribute_label"), table_name="pl_attribute")
op.drop_index(op.f("ix_pl_attribute_category_id"), table_name="pl_attribute")
op.drop_table("pl_attribute")

op.drop_index(op.f("ix_pl_category_id"), table_name="pl_category")
op.drop_index(op.f("ix_pl_category_name"), table_name="pl_category")
op.drop_table("pl_category")
4 changes: 4 additions & 0 deletions backend/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from routes.procurement_library.procurement_process import (
procurement_process_route,
)
from routes.procurement_library_v2.practice import pl_practice_router_v2
from routes.procurement_library_v2.category import pl_cat_router_v2

import os
from jsmin import jsmin
Expand Down Expand Up @@ -140,6 +142,8 @@ def generate_config_file() -> None:
app.include_router(assessment_question_route)
app.include_router(practice_route)
app.include_router(procurement_process_route)
app.include_router(pl_cat_router_v2)
app.include_router(pl_practice_router_v2)


@app.get("/", tags=["Dev"])
Expand Down
Empty file.
18 changes: 18 additions & 0 deletions backend/db/procurement_library_v2/crud_category.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from sqlalchemy.orm import Session, joinedload
from typing import List, Dict

from models.procurement_library_v2.pl_models import PLCategory


def get_categories_with_attributes(db: Session) -> List[Dict]:
"""Return all categories with their attributes using ORM query."""
categories = (
db.query(PLCategory)
.options(joinedload(PLCategory.attributes))
.order_by(PLCategory.id)
.all()
)

return [
cat.category_with_attributes for cat in categories
]
Loading