Skip to content

Commit bf0ae52

Browse files
authored
Related document image changes + field in Charge Recommendation (#594)
* related doc image + setence descriptionin cr * related document image changes
1 parent 0822382 commit bf0ae52

File tree

17 files changed

+534
-54
lines changed

17 files changed

+534
-54
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""related document image + sentence description
2+
3+
Revision ID: d7a6c2d9d8f3
4+
Revises: 3d9e96992c02
5+
Create Date: 2025-10-20 11:27:16.674828
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = 'd7a6c2d9d8f3'
14+
down_revision = '3d9e96992c02'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table('inspection_req_detail_doc_images_version',
22+
sa.Column('id', sa.Integer(), autoincrement=False, nullable=False, comment='The unique identifier'),
23+
sa.Column('req_detail_doc_id', sa.Integer(), autoincrement=False, nullable=True, comment='The requirement detail document id'),
24+
sa.Column('original_file_name', sa.String(), autoincrement=False, nullable=True, comment='The original filename of the uploaded image'),
25+
sa.Column('relative_url', sa.String(), autoincrement=False, nullable=True, comment='The actual url of the final uploaded image'),
26+
sa.Column('is_deleted', sa.Boolean(), autoincrement=False, nullable=True),
27+
sa.Column('created_date', sa.DateTime(), autoincrement=False, nullable=True),
28+
sa.Column('updated_date', sa.DateTime(), autoincrement=False, nullable=True),
29+
sa.Column('created_by', sa.String(length=100), autoincrement=False, nullable=True),
30+
sa.Column('updated_by', sa.String(length=100), autoincrement=False, nullable=True),
31+
sa.Column('is_active', sa.Boolean(), server_default='t', autoincrement=False, nullable=True),
32+
sa.Column('transaction_id', sa.BigInteger(), autoincrement=False, nullable=False),
33+
sa.Column('end_transaction_id', sa.BigInteger(), nullable=True),
34+
sa.Column('operation_type', sa.SmallInteger(), nullable=False),
35+
sa.Column('req_detail_doc_id_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
36+
sa.Column('original_file_name_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
37+
sa.Column('relative_url_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
38+
sa.Column('is_deleted_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
39+
sa.Column('created_date_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
40+
sa.Column('updated_date_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
41+
sa.Column('created_by_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
42+
sa.Column('updated_by_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
43+
sa.Column('is_active_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False),
44+
sa.PrimaryKeyConstraint('id', 'transaction_id')
45+
)
46+
with op.batch_alter_table('inspection_req_detail_doc_images_version', schema=None) as batch_op:
47+
batch_op.create_index(batch_op.f('ix_inspection_req_detail_doc_images_version_end_transaction_id'), ['end_transaction_id'], unique=False)
48+
batch_op.create_index(batch_op.f('ix_inspection_req_detail_doc_images_version_operation_type'), ['operation_type'], unique=False)
49+
batch_op.create_index(batch_op.f('ix_inspection_req_detail_doc_images_version_req_detail_doc_id'), ['req_detail_doc_id'], unique=False)
50+
batch_op.create_index(batch_op.f('ix_inspection_req_detail_doc_images_version_transaction_id'), ['transaction_id'], unique=False)
51+
52+
op.create_table('inspection_req_detail_doc_images',
53+
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False, comment='The unique identifier'),
54+
sa.Column('req_detail_doc_id', sa.Integer(), nullable=False, comment='The requirement detail document id'),
55+
sa.Column('original_file_name', sa.String(), nullable=False, comment='The original filename of the uploaded image'),
56+
sa.Column('relative_url', sa.String(), nullable=False, comment='The actual url of the final uploaded image'),
57+
sa.Column('is_deleted', sa.Boolean(), nullable=False),
58+
sa.Column('created_date', sa.DateTime(), nullable=False),
59+
sa.Column('updated_date', sa.DateTime(), nullable=True),
60+
sa.Column('created_by', sa.String(length=100), nullable=False),
61+
sa.Column('updated_by', sa.String(length=100), nullable=True),
62+
sa.Column('is_active', sa.Boolean(), server_default='t', nullable=False),
63+
sa.ForeignKeyConstraint(['req_detail_doc_id'], ['inspection_req_detail_documents.id'], name='inspection_req_detail_doc_images_req_detail_doc_id_fkey'),
64+
sa.PrimaryKeyConstraint('id')
65+
)
66+
with op.batch_alter_table('inspection_req_detail_doc_images', schema=None) as batch_op:
67+
batch_op.create_index(batch_op.f('ix_inspection_req_detail_doc_images_req_detail_doc_id'), ['req_detail_doc_id'], unique=False)
68+
batch_op.create_index('unique_non_deleted_req_detail_doc_relative_url', ['req_detail_doc_id', 'relative_url'], unique=True, postgresql_where=False)
69+
70+
with op.batch_alter_table('charge_recommendations', schema=None) as batch_op:
71+
batch_op.add_column(sa.Column('sentence_description', sa.String(), nullable=True, comment='Description of the fine'))
72+
73+
with op.batch_alter_table('charge_recommendations_version', schema=None) as batch_op:
74+
batch_op.add_column(sa.Column('sentence_description', sa.String(), autoincrement=False, nullable=True, comment='Description of the fine'))
75+
batch_op.add_column(sa.Column('sentence_description_mod', sa.Boolean(), server_default=sa.text('false'), nullable=False))
76+
77+
# ### end Alembic commands ###
78+
79+
80+
def downgrade():
81+
# ### commands auto generated by Alembic - please adjust! ###
82+
with op.batch_alter_table('charge_recommendations_version', schema=None) as batch_op:
83+
batch_op.drop_column('sentence_description_mod')
84+
batch_op.drop_column('sentence_description')
85+
86+
with op.batch_alter_table('charge_recommendations', schema=None) as batch_op:
87+
batch_op.drop_column('sentence_description')
88+
89+
with op.batch_alter_table('inspection_req_detail_doc_images', schema=None) as batch_op:
90+
batch_op.drop_index('unique_non_deleted_req_detail_doc_relative_url', postgresql_where=False)
91+
batch_op.drop_index(batch_op.f('ix_inspection_req_detail_doc_images_req_detail_doc_id'))
92+
93+
op.drop_table('inspection_req_detail_doc_images')
94+
with op.batch_alter_table('inspection_req_detail_doc_images_version', schema=None) as batch_op:
95+
batch_op.drop_index(batch_op.f('ix_inspection_req_detail_doc_images_version_transaction_id'))
96+
batch_op.drop_index(batch_op.f('ix_inspection_req_detail_doc_images_version_req_detail_doc_id'))
97+
batch_op.drop_index(batch_op.f('ix_inspection_req_detail_doc_images_version_operation_type'))
98+
batch_op.drop_index(batch_op.f('ix_inspection_req_detail_doc_images_version_end_transaction_id'))
99+
100+
op.drop_table('inspection_req_detail_doc_images_version')
101+
# ### end Alembic commands ###

compliance-api/src/compliance_api/models/charge_recommendation.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,11 @@ class ChargeRecommendation(BaseModelVersioned):
207207
nullable=True,
208208
comment="Date when the sentence was given",
209209
)
210+
sentence_description = Column(
211+
String,
212+
nullable=True,
213+
comment="Description of the fine",
214+
)
210215
# Relationships
211216
inspection = relationship("Inspection", foreign_keys=[inspection_id], lazy="joined")
212217
is_deleted = Column(Boolean, default=False, server_default="f", nullable=False)

compliance-api/src/compliance_api/models/inspection/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from .inspection_option import (
1010
InspectionAttendanceOption, InspectionInitiationOption, InspectionTypeOption, IRStatusOption)
1111
from .inspection_req_detail_doc import InspectionReqDetailDocument
12+
from .inspection_req_detail_doc_image import InspectionRequirementDetailDocImage
1213
from .inspection_req_detail_image import InspectionRequirementDetailImage
1314
from .inspection_req_enforcement_map import InspectionReqEnforcementMap
1415
from .inspection_req_image import InspectionRequirementImage

compliance-api/src/compliance_api/models/inspection/inspection_req_detail_doc.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ class InspectionReqDetailDocument(BaseModelVersioned):
7171
"DocumentType", foreign_keys=[document_type_id], lazy="select"
7272
)
7373
appendix = relationship("Appendix", foreign_keys=[appendix_id], lazy="joined")
74+
images = relationship(
75+
"InspectionRequirementDetailDocImage",
76+
foreign_keys="InspectionRequirementDetailDocImage.req_detail_doc_id",
77+
lazy="select",
78+
primaryjoin="and_(InspectionRequirementDetailDocImage.req_detail_doc_id == InspectionReqDetailDocument.id, "
79+
"InspectionRequirementDetailDocImage.is_active == True, "
80+
"InspectionRequirementDetailDocImage.is_deleted == False)",
81+
order_by="InspectionRequirementDetailDocImage.id.asc()",
82+
)
7483

7584
__table_args__ = (
7685
Index(
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
"""Model to handle the image uploads in inspection requirement detail documents."""
2+
3+
from sqlalchemy import Boolean, Column, ForeignKey, Index, Integer, String
4+
5+
from compliance_api.utils.constant import DELETE_DIC_PARAMS
6+
7+
from ..base_model import BaseModelVersioned
8+
from ..utils import with_session
9+
10+
11+
class InspectionRequirementDetailDocImage(BaseModelVersioned):
12+
"""InspectionRequirementDetailDocImage."""
13+
14+
__tablename__ = "inspection_req_detail_doc_images"
15+
id = Column(
16+
Integer,
17+
primary_key=True,
18+
autoincrement=True,
19+
comment="The unique identifier",
20+
)
21+
req_detail_doc_id = Column(
22+
Integer,
23+
ForeignKey(
24+
"inspection_req_detail_documents.id",
25+
name="inspection_req_detail_doc_images_req_detail_doc_id_fkey",
26+
),
27+
nullable=False,
28+
index=True,
29+
comment="The requirement detail document id",
30+
)
31+
original_file_name = Column(
32+
String, nullable=False, comment="The original filename of the uploaded image"
33+
)
34+
relative_url = Column(
35+
String, nullable=False, comment="The actual url of the final uploaded image"
36+
)
37+
38+
is_deleted = Column(Boolean, nullable=False, default=False)
39+
40+
__table_args__ = (
41+
Index(
42+
"unique_non_deleted_req_detail_doc_relative_url", # Index name
43+
"req_detail_doc_id",
44+
"relative_url",
45+
unique=True,
46+
postgresql_where=(is_deleted is False), # Condition for uniqueness
47+
),
48+
)
49+
50+
@classmethod
51+
@with_session
52+
def bulk_insert(cls, images, session=None):
53+
"""Insert images."""
54+
session.add_all(images)
55+
session.flush()
56+
57+
@classmethod
58+
@with_session
59+
def create_image(cls, image_obj, session=None):
60+
"""Persist the image object."""
61+
img_obj = InspectionRequirementDetailDocImage(**image_obj)
62+
session.add(img_obj)
63+
session.flush()
64+
return img_obj
65+
66+
@classmethod
67+
@with_session
68+
def update_image(cls, image_id, image_data, session=None):
69+
"""Update image details."""
70+
query = cls.query.filter_by(id=image_id)
71+
image_detail: InspectionRequirementDetailDocImage = query.first()
72+
if not image_detail or image_detail.is_deleted:
73+
return None
74+
image_detail.update(image_data, commit=False)
75+
session.flush()
76+
return image_detail
77+
78+
@classmethod
79+
def find_all_images_by_req_detail_doc_id(cls, req_detail_doc_id):
80+
"""Get all images by req_detail_doc_id."""
81+
return (
82+
cls.query.filter_by(
83+
req_detail_doc_id=req_detail_doc_id,
84+
is_active=True,
85+
is_deleted=False,
86+
)
87+
.order_by(cls.id)
88+
.all()
89+
)
90+
91+
@classmethod
92+
def find_image_by_url(cls, req_detail_doc_id, relative_url):
93+
"""Get image object by url."""
94+
return cls.query.filter(
95+
cls.req_detail_doc_id == req_detail_doc_id,
96+
cls.relative_url == relative_url,
97+
cls.is_active.is_(True),
98+
cls.is_deleted.is_(False),
99+
).first()
100+
101+
@classmethod
102+
@with_session
103+
def delete_image(cls, image_id, session=None):
104+
"""Delete the image."""
105+
image = cls.find_by_id(image_id)
106+
if not image:
107+
return None
108+
image.update(DELETE_DIC_PARAMS, commit=False)
109+
session.flush()
110+
return image
111+
112+
@classmethod
113+
@with_session
114+
def delete_images_by_req_detail_doc_id(cls, req_detail_doc_id, session=None):
115+
"""Delete images by requirement detail document id."""
116+
images = cls.query.filter_by(
117+
req_detail_doc_id=req_detail_doc_id, is_deleted=False
118+
).all()
119+
for image in images:
120+
image.update(DELETE_DIC_PARAMS, commit=False)
121+
session.flush()
122+
123+
@classmethod
124+
@with_session
125+
def delete_images_by_req_detail_doc_ids(cls, req_detail_doc_ids, session=None):
126+
"""Delete images by requirement detail document ids."""
127+
images = cls.query.filter(
128+
cls.req_detail_doc_id.in_(req_detail_doc_ids), cls.is_deleted.is_(False)
129+
).all()
130+
for image in images:
131+
image.update(DELETE_DIC_PARAMS, commit=False)
132+
session.flush()

compliance-api/src/compliance_api/resources/inspection_requirement.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
from compliance_api.exceptions import BadRequestError
1010
from compliance_api.models.inspection import ImageTypeEnum
1111
from compliance_api.schemas.inspection_requirement import (
12-
InspectionReqDetailImageSchema, InspectionReqImageSchema, InspectionRequirementCreateSchema,
13-
InspectionRequirementSchema, InspectionRequirementUpdateSchema, InspectionSortOrderSchema)
12+
InspectionReqDetailDocImageSchema, InspectionReqDetailImageSchema, InspectionReqImageSchema,
13+
InspectionRequirementCreateSchema, InspectionRequirementSchema, InspectionRequirementUpdateSchema,
14+
InspectionSortOrderSchema)
1415
from compliance_api.services import InspectionRequirementService
1516
from compliance_api.utils.enum import PermissionEnum
1617
from compliance_api.utils.util import cors_preflight
@@ -235,3 +236,27 @@ def get(inspection_id, requirement_id):
235236
inspection_id, requirement_id
236237
)
237238
return InspectionReqDetailImageSchema(many=True).dump(images), HTTPStatus.OK
239+
240+
241+
@cors_preflight("GET, OPTIONS")
242+
@API.route(
243+
"/<int:requirement_id>/requirement-detail/<int:detail_id>/document/<int:doc_id>/images",
244+
methods=["OPTIONS", "GET"],
245+
)
246+
class InspectionReqSourceDocImages(Resource):
247+
"""Manage the images uploaded as part of inspection requirement detail documents."""
248+
249+
@staticmethod
250+
@ApiHelper.swagger_decorators(
251+
API,
252+
endpoint_description="Get all images for a requirement detail document",
253+
)
254+
@auth.require
255+
@API.response(code=200, description="Success", model=[inspesction_req_image_schema])
256+
@API.response(404, "Not Found")
257+
def get(inspection_id, requirement_id, detail_id, doc_id):
258+
"""Get all images by requirement detail document id."""
259+
images = InspectionRequirementService.get_all_requirement_detail_doc_images(
260+
inspection_id, requirement_id, detail_id, doc_id
261+
)
262+
return InspectionReqDetailDocImageSchema(many=True).dump(images), HTTPStatus.OK

compliance-api/src/compliance_api/schemas/charge_recommendation.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ class ChargeRecommendationUpdateSchema(
9292
},
9393
metadata={"description": "The sentence date"},
9494
)
95+
sentence_description = fields.String(
96+
allow_none=True,
97+
metadata={"description": "The sentence description"},
98+
)
9599
sentence_type_option_ids = fields.List(
96100
fields.Integer(),
97101
allow_none=True,

0 commit comments

Comments
 (0)