diff --git a/.gitignore b/.gitignore
index d693a8be..5e83d15b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
**/__pycache__/**
-.vscode/settings.json
+.vscode/**
test/**
.env
0.1.3.json
@@ -7,4 +7,3 @@ ml_structure.json
.DS_Store
.venv
venv
-.vscode/extensions.json
diff --git a/datastore/__init__.py b/datastore/__init__.py
index 55cb89fd..92026f72 100644
--- a/datastore/__init__.py
+++ b/datastore/__init__.py
@@ -505,7 +505,7 @@ async def get_folder_pictures(self, cursor: Cursor, folder_id: UUID, user_id: UU
- user_id (str): The UUID of the user.
Returns:
- - A list of the pictures of the folder.
+ - A list of the pictures (BLOB) of the folder.
"""
# Check if user exists
if self.container_client is None or not self.container_client.exists():
diff --git a/fertiscan/__init__.py b/fertiscan/__init__.py
index 7ac8140c..a8054f3f 100644
--- a/fertiscan/__init__.py
+++ b/fertiscan/__init__.py
@@ -4,12 +4,28 @@
from azure.storage.blob import ContainerClient
from dotenv import load_dotenv
from psycopg import Cursor
+from datetime import datetime
import datastore
import datastore.db.queries.picture as picture
import datastore.db.queries.user as user
import fertiscan.db.metadata.inspection as data_inspection
-import fertiscan.db.queries.inspection as inspection
+from fertiscan.db.queries import (
+ ingredient,
+ inspection,
+ label,
+ metric,
+ nutrients,
+ organization,
+ registration_number,
+ sub_label,
+ fertilizer,
+)
+
+from datastore import ContainerController, ClientController, User
+
+from pydantic import BaseModel
+from typing import Optional
load_dotenv()
@@ -26,112 +42,532 @@
print("Warning: FERTISCAN_STORAGE_URL not set")
-async def register_analysis(
- cursor: Cursor,
- container_client: ContainerClient,
- user_id,
- hashed_pictures,
- analysis_dict,
-):
+class InspectionController:
+ def __init__(self, inspection_model: data_inspection.Inspection):
+ self.model: data_inspection.Inspection = inspection_model
+ self.id: UUID = inspection_model.inspection_id
+ return
+
+ def get_inspection_image_location_data(self, cursor: Cursor) -> tuple[UUID, UUID]:
+ """
+ Retrieve the relevant information regarding where the Inspection Images are stored
+ This is usefull to perform Container_Controller.get_folder_pictures()
+
+ Parameters:
+ - cursor (Cursor): Database cursor for executing queries.
+
+ Returns:
+ - tuple (container_id: UUID, folder: UUID): The id necessary to locate the images
+ """
+ if not inspection.is_a_inspection_id(cursor=cursor, inspection_id=self.id):
+ raise inspection.InspectionNotFoundError(
+ f"Inspection not found based on the given id: {self.id}"
+ )
+ picture_set_id = inspection.get_inspection_fk(cursor, self.id)[2]
+
+ container_id = picture.get_picture_set_container_id(
+ cursor=cursor, picture_set_id=picture_set_id
+ )
+ return (container_id, picture_set_id)
+
+ def update_inspection(
+ self,
+ cursor: Cursor,
+ user_id: UUID,
+ updated_data: dict | data_inspection.Inspection,
+ ) -> data_inspection.Inspection:
+ """
+ Update an existing inspection record in the database.
+
+ Parameters:
+ - cursor (Cursor): Database cursor for executing queries.
+ - inspection_id (str | UUID): UUID of the inspection to update.
+ - user_id (str | UUID): UUID of the user performing the update.
+ - updated_data (dict | data_inspection.Inspection): Dictionary or Inspection model containing updated inspection data.
+
+ Returns:
+ - data_inspection.Inspection: Updated inspection data from the database.
+
+ Raises:
+ - InspectionUpdateError: If an error occurs during the update.
+ """
+ if not user.is_a_user_id(cursor=cursor, user_id=user_id):
+ raise user.UserNotFoundError(
+ f"User not found based on the given id: {user_id}"
+ )
+ if not isinstance(updated_data, data_inspection.Inspection):
+ updated_data = data_inspection.Inspection.model_validate(updated_data)
+ # The inspection record must exist before updating it
+ if not inspection.is_a_inspection_id(cursor, str(updated_data.inspection_id)):
+ raise inspection.InspectionNotFoundError(
+ f"Inspection not found based on the given id: {self.model.inspection_id}"
+ )
+ if (
+ self.model.container_id != updated_data.container_id
+ or self.model.folder_id != updated_data.folder_id
+ ):
+ raise Warning(
+ "You should not update an Inspection picture location. This does not cause issues in the DB but could result in errors when attempting to fetch the pictures"
+ )
+ if not datastore.container_db.is_a_container(
+ cursor=cursor, container_id=updated_data.container_id
+ ):
+ raise datastore.ContainerCreationError(
+ f"Container not found based on the given id: {updated_data.container_id}"
+ )
+ # Make sure the user can verify this inspection
+ if not datastore.verify_user_can_write(
+ cursor=cursor, container_id=updated_data.container_id, user_id=user_id
+ ):
+ raise datastore.PermissionNotHighEnough(
+ f"The user {user_id} does not have the write permission or higher which mean he cannot upload an inspection in the container {self.id}"
+ )
+ # A completed inspection cannot be updated
+ if inspection.is_inspection_verified(
+ cursor=cursor, inspection_id=updated_data.inspection_id
+ ):
+ raise inspection.InspectionUpdateError(
+ "The inspection you are trying to update is already verified"
+ )
+ else:
+ updated_at = inspection.update_inspection(
+ cursor=cursor,
+ inspection_id=updated_data.inspection_id,
+ verified=updated_data.verified,
+ inspection_comment=updated_data.inspection_comment,
+ )
+ updated_data.updated_at = updated_at
+ self.model.updated_at = updated_at # just in case
+ # --------
+ label_to_update = updated_data.product
+ label_id = updated_data.product.label_id
+ # Label Information
+ label.update_label_info(
+ cursor=cursor,
+ label_id=label_to_update.label_id,
+ name=label_to_update.name,
+ lot_number=label_to_update.lot_number,
+ npk=label_to_update.npk,
+ n=label_to_update.n,
+ p=label_to_update.p,
+ k=label_to_update.k,
+ title_en=updated_data.guaranteed_analysis.title.en,
+ title_fr=updated_data.guaranteed_analysis.title.fr,
+ is_minimal=updated_data.guaranteed_analysis.is_minimal,
+ record_keeping=label_to_update.record_keeping,
+ )
+
+ # Organization Information
+ org_ids = []
+ for org in updated_data.organizations:
+ if org.id is not None:
+ org_ids.append(org.id)
+ # delete any orgs that have been removed from the list
+ organization.delete_absent_organisation_information_from_label(
+ cursor=cursor, label_id=label_id, org_ids=org_ids
+ )
+ for org in updated_data.organizations:
+ if org.id is not None:
+ organization.update_organization_info(
+ cursor=cursor,
+ information_id=org.id,
+ name=org.name,
+ website=org.website,
+ phone_number=org.phone_number,
+ address=org.address,
+ is_main_contact=org.is_main_contact,
+ )
+ # An org was added by the user and not detected by the pipeline
+ else:
+ org.id = organization.new_organization_information(
+ cursor=cursor,
+ address=org.address,
+ name=org.name,
+ website=org.website,
+ phone_number=org.phone_number,
+ label_id=label_to_update.label_id,
+ edited=True,
+ is_main_contact=org.is_main_contact,
+ )
+
+ # Metrics (Weigth - Density - Volume)
+ metric.upsert_metric(
+ cursor=cursor,
+ label_id=label_id,
+ metrics=updated_data.product.metrics.model_dump(),
+ )
+
+ # Ingredient
+ ingredient.upsert_ingredient(
+ cursor=cursor,
+ label_id=label_id,
+ ingredients=updated_data.ingredients.model_dump(),
+ )
+
+ # GA
+ nutrients.upsert_guaranteed_analysis(
+ cursor=cursor,
+ label_id=label_id,
+ GA=updated_data.guaranteed_analysis.model_dump(),
+ )
+
+ # Sublabel
+ # This use the whole dict as parameter since we fetch and loop for all the Sub_label_types
+ sub_label.upsert_sub_label(
+ cursor=cursor,
+ label_id=label_id,
+ inspection_dict=updated_data.model_dump(),
+ )
+
+ # Reg numbers
+ reg_numbers = []
+ for entry in updated_data.product.registration_numbers:
+ reg_numbers.append(entry.model_dump())
+ registration_number.update_registration_number(
+ cursor=cursor, label_id=label_id, registration_numbers=reg_numbers
+ )
+
+ # Verified
+ if updated_data.verified:
+ fertilizer_name = updated_data.product.name
+
+ # Check If there is a Reg Number for this fertilizer :(if there are only one)
+ registration_number_value = None
+ for reg_number in updated_data.product.registration_numbers:
+ if not reg_number.is_an_ingredient:
+ registration_number_value = reg_number.registration_number
+
+ # Insert Organization
+ main_org = None
+ if len(updated_data.organizations) == 0:
+ raise Warning(
+ "at least one Organization information is required for a verified inspection"
+ )
+ elif len(updated_data.organizations) == 1:
+ main_org = updated_data.organizations[0]
+ else:
+ for org in updated_data.organizations:
+ if org.is_main_contact:
+ main_org = org
+ if main_org is None:
+ raise Warning(
+ "'Main contact organization information is required and was not found'"
+ )
+ else:
+ organization_id = organization.upsert_organization(
+ cursor=cursor,
+ name=main_org.name,
+ website=main_org.website,
+ phone_number=main_org.phone_number,
+ address=main_org.address,
+ )
+ # Since it it verified, we upsert the Fertilizer inspected
+ fertilizer.upsert_fertilizer(
+ cursor=cursor,
+ name=fertilizer_name,
+ reg_number=registration_number_value,
+ org_owner_id=organization_id,
+ latest_inspection_id=updated_data.inspection_id,
+ )
+ else:
+ updated_data.verified = False
+ # ------------
+ updated_data.updated_at = updated_at
+ return data_inspection.Inspection.model_validate(updated_data)
+
+ async def delete_inspection(
+ self,
+ cursor: Cursor,
+ user_id: UUID,
+ ) -> data_inspection.DBInspection:
+ """
+ Delete an existing inspection record and its associated picture set from the database.
+
+ Parameters:
+ - cursor (Cursor): Database cursor for executing queries.
+ - inspection_id (str | UUID): UUID of the inspection to delete.
+ - user_id (str | UUID): UUID of the user performing the deletion.
+
+ Returns:
+ - data_inspection.Inspection: The deleted inspection data from the database.
+
+ """
+ if not user.is_a_user_id(cursor=cursor, user_id=user_id):
+ raise user.UserNotFoundError(
+ f"User not found based on the given id: {user_id}"
+ )
+ if not datastore.container_db.is_a_container(
+ cursor=cursor, container_id=self.model.container_id
+ ):
+ raise datastore.ContainerCreationError(
+ f"Container not found based on the given id: {self.model.container_id}"
+ )
+ if not datastore.verify_user_can_write(
+ cursor=cursor, container_id=self.model.container_id, user_id=user_id
+ ):
+ raise datastore.PermissionNotHighEnough(
+ f"The user {user_id} does not have the write permission or higher which mean he cannot upload an inspection in the container {self.id}"
+ )
+
+ # Delete the inspection and get the returned data
+ deleted_inspection = inspection.delete_inspection(cursor, self.id, user_id)
+ deleted_inspection = data_inspection.DBInspection.model_validate(
+ deleted_inspection
+ )
+
+ container_controller: ContainerController = (
+ await datastore.get_container_controller(
+ cursor, self.model.container_id, FERTISCAN_STORAGE_URL, None
+ )
+ )
+
+ await container_controller.delete_folder_permanently(
+ cursor, user_id, self.model.folder_id
+ )
+ return deleted_inspection
+
+
+def new_inspection(
+ cursor: Cursor, user_id: UUID, analysis_dict, container_id: UUID, folder_id: UUID
+) -> InspectionController:
"""
Register an analysis in the database
Parameters:
- cursor: The cursor object to interact with the database.
- container_client: The container client of the user.
- - analysis_dict (dict): The analysis to register in a dict string.
- - picture: The picture encoded to upload.
+ - analysis_dict (dict): The analysis to register in a dict string
Returns:
- The analysis_dict with the analysis_id added.
"""
if not user.is_a_user_id(cursor=cursor, user_id=user_id):
raise user.UserNotFoundError(f"User not found based on the given id: {user_id}")
- if not container_client.exists():
+ if not datastore.container_db.is_a_container(
+ cursor=cursor, container_id=container_id
+ ):
raise datastore.ContainerCreationError(
- f"Container not found based on the given user_id: {user_id}"
+ f"Container not found based on the given id: {container_id}"
+ )
+ if not datastore.verify_user_can_write(
+ cursor=cursor, container_id=container_id, user_id=user_id
+ ):
+ raise datastore.PermissionNotHighEnough(
+ f"The user {user_id} does not have the write permission or higher which mean he cannot upload an inspection in the container {container_id}"
)
- picture_set_id = await datastore.create_picture_set(
- cursor, container_client, len(hashed_pictures), user_id
+ formatted_analysis = data_inspection.build_inspection_import(
+ analysis_form=analysis_dict,
+ user_id=user_id,
+ folder_id=folder_id,
+ container_id=container_id,
)
-
- # Upload pictures to storage
- await datastore.upload_pictures(
+ # ----------
+ # Label info
+ label_info_id = label.new_label_information(
cursor=cursor,
- user_id=str(user_id),
- container_client=container_client,
- picture_set_id=str(picture_set_id),
- hashed_pictures=hashed_pictures,
+ name=formatted_analysis.product.name,
+ lot_number=formatted_analysis.product.lot_number,
+ npk=formatted_analysis.product.npk,
+ n=formatted_analysis.product.n,
+ p=formatted_analysis.product.p,
+ k=formatted_analysis.product.k,
+ title_en=formatted_analysis.guaranteed_analysis.title.en,
+ title_fr=formatted_analysis.guaranteed_analysis.title.fr,
+ is_minimal=formatted_analysis.guaranteed_analysis.is_minimal,
+ record_keeping=formatted_analysis.product.record_keeping,
)
-
- # Register analysis in the database
- formatted_analysis = data_inspection.build_inspection_import(analysis_dict,user_id)
-
- analysis_db = inspection.new_inspection_with_label_info(
- cursor, user_id, picture_set_id, formatted_analysis
+ formatted_analysis.product.label_id = label_info_id
+ # Metrics
+ # Weight
+ for record in formatted_analysis.product.metrics.weight:
+ metric.new_metric(
+ cursor=cursor,
+ value=record.value,
+ read_unit=record.unit,
+ label_id=label_info_id,
+ metric_type="weight",
+ edited=False,
+ )
+ # Density
+ metric.new_metric(
+ cursor=cursor,
+ value=formatted_analysis.product.metrics.density.value,
+ read_unit=formatted_analysis.product.metrics.density.unit,
+ label_id=label_info_id,
+ metric_type="density",
+ edited=False,
+ )
+ # Volume
+ metric.new_metric(
+ cursor=cursor,
+ value=formatted_analysis.product.metrics.volume.value,
+ read_unit=formatted_analysis.product.metrics.volume.unit,
+ label_id=label_info_id,
+ metric_type="volume",
+ edited=False,
)
- return analysis_db
-
-async def update_inspection(
- cursor: Cursor,
- inspection_id: str | UUID,
- user_id: str | UUID,
- updated_data: dict | data_inspection.Inspection,
-):
- """
- Update an existing inspection record in the database.
+ # Ingredients
+ for ingredient_en in formatted_analysis.ingredients.en:
+ ingredient.new_ingredient(
+ cursor=cursor,
+ name=ingredient_en.name,
+ value=ingredient_en.value,
+ read_unit=ingredient_en.unit,
+ label_id=label_info_id,
+ language="en",
+ organic=None,
+ active=None,
+ edited=False,
+ )
+ for ingredient_fr in formatted_analysis.ingredients.fr:
+ ingredient.new_ingredient(
+ cursor=cursor,
+ name=ingredient_fr.name,
+ value=ingredient_fr.value,
+ read_unit=ingredient_fr.unit,
+ label_id=label_info_id,
+ language="fr",
+ organic=None,
+ active=None,
+ edited=False,
+ )
- Parameters:
- - cursor (Cursor): Database cursor for executing queries.
- - inspection_id (str | UUID): UUID of the inspection to update.
- - user_id (str | UUID): UUID of the user performing the update.
- - updated_data (dict | data_inspection.Inspection): Dictionary or Inspection model containing updated inspection data.
+ # Sub Label
+ instruction_id = sub_label.get_sub_type_id(cursor, "instructions")
+ caution_id = sub_label.get_sub_type_id(cursor, "cautions")
+ max_instruction = max(
+ len(formatted_analysis.instructions.en), len(formatted_analysis.instructions.fr)
+ )
+ max_caution = max(
+ len(formatted_analysis.cautions.en), len(formatted_analysis.cautions.fr)
+ )
+ for i in range(0, max_instruction):
+ if i >= len(formatted_analysis.instructions.fr):
+ fr = None
+ en = formatted_analysis.instructions.en[i]
+ elif i >= len(formatted_analysis.instructions.en):
+ fr = formatted_analysis.instructions.fr[i]
+ en = None
+ else:
+ fr = formatted_analysis.instructions.fr[i]
+ en = formatted_analysis.instructions.en[i]
+ sub_label.new_sub_label(
+ cursor=cursor,
+ text_fr=fr,
+ text_en=en,
+ label_id=label_info_id,
+ sub_type_id=str(instruction_id),
+ edited=False,
+ )
- Returns:
- - data_inspection.Inspection: Updated inspection data from the database.
+ for i in range(0, max_caution):
+ if i >= len(formatted_analysis.cautions.fr):
+ fr = None
+ en = formatted_analysis.cautions.en[i]
+ elif i >= len(formatted_analysis.cautions.en):
+ fr = formatted_analysis.cautions.fr[i]
+ en = None
+ else:
+ fr = formatted_analysis.cautions.fr[i]
+ en = formatted_analysis.cautions.en[i]
+ sub_label.new_sub_label(
+ cursor=cursor,
+ text_fr=formatted_analysis.cautions.fr[i],
+ text_en=formatted_analysis.cautions.en[i],
+ label_id=label_info_id,
+ sub_type_id=str(caution_id),
+ edited=False,
+ )
- Raises:
- - InspectionUpdateError: If an error occurs during the update.
- """
- if isinstance(inspection_id, str):
- inspection_id = UUID(inspection_id)
- if isinstance(user_id, str):
- user_id = UUID(user_id)
- if not user.is_a_user_id(cursor, str(user_id)):
- raise user.UserNotFoundError(f"User not found based on the given id: {user_id}")
+ # Guaranteed Analysis
+ for record in formatted_analysis.guaranteed_analysis.en:
+ nutrients.new_guaranteed_analysis(
+ cursor=cursor,
+ read_name=record.name,
+ value=record.value,
+ unit=record.unit,
+ label_id=label_info_id,
+ language="en",
+ element_id=None,
+ edited=False,
+ )
+ for record in formatted_analysis.guaranteed_analysis.fr:
+ nutrients.new_guaranteed_analysis(
+ cursor=cursor,
+ read_name=record.name,
+ value=record.value,
+ unit=record.unit,
+ label_id=label_info_id,
+ language="fr",
+ element_id=None,
+ edited=False,
+ )
- if not isinstance(updated_data, data_inspection.Inspection):
- updated_data = data_inspection.Inspection.model_validate(updated_data)
+ # Reg numbers
+ for record in formatted_analysis.product.registration_numbers:
+ registration_number.new_registration_number(
+ cursor=cursor,
+ registration_number=record.registration_number,
+ label_id=label_info_id,
+ is_an_ingredient=record.is_an_ingredient,
+ read_name=None,
+ edited=False,
+ )
- # The inspection record must exist before updating it
- if not inspection.is_a_inspection_id(cursor, str(inspection_id)):
- raise inspection.InspectionNotFoundError(
- f"Inspection not found based on the given id: {inspection_id}"
+ # Organization
+ flag = True
+ for record in formatted_analysis.organizations:
+ record.id = organization.new_organization_information(
+ cursor=cursor,
+ address=record.address,
+ name=record.name,
+ website=record.website,
+ phone_number=record.phone_number,
+ label_id=label_info_id,
+ edited=False,
+ is_main_contact=flag,
)
+ if flag == True:
+ # We do this since we have no way of knowing who is the main contact
+ record.is_main_contact = True # We assume the first one is the main contact
+ flag = False
- updated_result = inspection.update_inspection(
- cursor, inspection_id, user_id, updated_data.model_dump()
+ # Inspection
+ inspection_id, upload_date = inspection.new_inspection(
+ cursor=cursor,
+ user_id=user_id,
+ picture_set_id=folder_id,
+ verified=False,
+ label_id=label_info_id,
+ container_id=container_id,
+ )
+ formatted_analysis.inspection_id = inspection_id
+ formatted_analysis.upload_date = upload_date
+ formatted_analysis.updated_at = upload_date
+ analysis_db = data_inspection.Inspection.model_validate(formatted_analysis)
+ inspection.save_inspection_original_dataset(
+ cursor=cursor,
+ inspection_id=formatted_analysis.inspection_id,
+ og_data=analysis_db.model_dump_json(),
)
- return data_inspection.Inspection.model_validate(updated_result)
+ # ------------
+ inspection_controller = InspectionController(analysis_db)
-async def get_full_inspection_json(
+ return inspection_controller
+
+
+def get_inspection(
cursor: Cursor,
- inspection_id,
- user_id=None,
- picture_set_id=None,
- label_info_id=None,
- company_info_id=None,
- manufacturer_info_id=None,
-):
+ inspection_id: UUID,
+) -> InspectionController:
"""
- Get the full inspection json from the database
+ Get the full inspection json from the database and return a controller for it
Parameters:
- cursor: The cursor object to interact with the database.
- - inspection_id: The inspection id of the inspection.
Returns:
- The inspection json.
@@ -141,82 +577,18 @@ async def get_full_inspection_json(
f"Inspection not found based on the given id: {inspection_id}"
)
- # Check Ids
- if (
- (
- picture_set_id is None
- or picture_set_id == ""
- or not picture.is_a_picture_set_id(
- cursor=cursor, picture_set_id=picture_set_id
- )
- )
- or (
- user_id is None
- or user_id == ""
- or not user.is_a_user_id(cursor=cursor, user_id=user_id)
- )
- or (label_info_id is None or label_info_id == "")
- or (company_info_id is None or company_info_id == "")
- or (manufacturer_info_id is None or manufacturer_info_id == "")
- ):
- ids = inspection.get_inspection_fk(cursor, inspection_id)
- picture_set_id = ids[2]
- label_info_id = ids[0]
- company_info_id = ids[3]
- manufacturer_info_id = ids[4]
- user_id = ids[1]
- else:
- if not picture.is_a_picture_set_id(
- cursor=cursor, picture_set_id=picture_set_id
- ):
- raise picture.PictureSetNotFoundError(
- f"Picture set not found based on the given id: {picture_set_id}"
- )
- if not user.is_a_user_id(cursor=cursor, user_id=user_id):
- raise user.UserNotFoundError(
- f"User not found based on the given id: {user_id}"
- )
- ids = inspection.get_inspection_fk(cursor, inspection_id)
- if not picture_set_id == ids[2]:
- raise Warning(
- "Picture set id does not match the picture_set_id in the inspection for the given inspection_id"
- )
- if not label_info_id == ids[0]:
- raise Warning(
- "Label info id does not match the label_info_id in the inspection for the given inspection_id"
- )
- if not company_info_id == ids[3]:
- raise Warning(
- "Company info id does not match the company_info_id in the inspection for the given inspection_id"
- )
- if not manufacturer_info_id == ids[4]:
- raise Warning(
- "Manufacturer info id does not match the manufacturer_info_id in the inspection for the given inspection_id"
- )
- if not user_id == ids[1]:
- raise Warning(
- "User id does not match the user_id in the inspection for the given inspection_id"
- )
-
- # Retrieve pictures
- # pictures_ids = picture.get_picture_in_picture_set(cursor, picture_set_id)
-
# Retrieve label_info
- inspection_metadata = data_inspection.build_inspection_export(
- cursor, inspection_id
- )
+ inspection_metadata = data_inspection.build_inspection_export(cursor, inspection_id)
+ inspection_controller = InspectionController(inspection_model=inspection_metadata)
+ return inspection_controller
- return inspection_metadata
-
-async def get_user_analysis_by_verified(cursor: Cursor, user_id, verified: bool):
+def get_user_analysis_by_verified(cursor: Cursor, user_id: UUID, verified: bool):
"""
This function fetch all the inspection of a user
-
Parameters:
- cursor: The cursor object to interact with the database.
- user_id: The user id of the user.
-
Returns:
- List of unverified analysis.
[
@@ -227,46 +599,97 @@ async def get_user_analysis_by_verified(cursor: Cursor, user_id, verified: bool)
inspection.picture_set_id,
label_info.id as label_info_id,
label_info.product_name,
+ label_info.company_info_id,
+ label_info.manufacturer_info_id
company_info.id as company_info_id,
- company_info.name as company_name,
- inspection.verified
+ company_info.company_name
]
"""
-
if not user.is_a_user_id(cursor=cursor, user_id=user_id):
raise user.UserNotFoundError(f"User not found based on the given id: {user_id}")
return inspection.get_all_user_inspection_filter_verified(cursor, user_id, verified)
-async def delete_inspection(
+def search_inspection(
cursor: Cursor,
- inspection_id: str | UUID,
- user_id: str | UUID,
- container_client: ContainerClient,
-) -> data_inspection.DBInspection:
+ fertilizer_name: str,
+ reg_number: str,
+ lot_number: str,
+ inspector_name: str,
+ lower_bound_date: datetime,
+ upper_bound_date: datetime,
+ organization_name: str,
+ organization_address: str,
+ organization_phone: str,
+):
"""
- Delete an existing inspection record and its associated picture set from the database.
-
+ This function search all the verified inspection based on the given parameters
Parameters:
- - cursor (Cursor): Database cursor for executing queries.
- - inspection_id (str | UUID): UUID of the inspection to delete.
- - user_id (str | UUID): UUID of the user performing the deletion.
+ - cursor (Cursor): The cursor object to interact with the database.
+ - fertilizer_name (str): The name of the fertilizer.
+ - reg_number (str): The registration number of the fertilizer.
+ - lot_number (str): The lot number of the fertilizer.
+ - inspector_name (str): The name of the inspector. (Not used at the moment)
+ - lower_bound_date (str): The lower bound date of the inspection.
+ - upper_bound_date (str): The upper bound date of the inspection.
+ - organization_name (str): The name of the organization.
+ - organization_address (str): The address of the organization.
+ - organization_phone (str): The phone number of the organization.
Returns:
- - data_inspection.Inspection: The deleted inspection data from the database.
-
+ - List of inspection tuple.
+ [
+ inspection.id,
+ inspection.verified
+ inspection.upload_date,
+ inspection.updated_at,
+ inspection.inspector_id
+ inspection.label_info_id,
+ inspection.container_id,
+ inspection.folder_id,
+ inspection.inspection_comment,
+ inspection.verified_date,
+ label_info.product_name,
+ organization_info.id, (main_contact_id)
+ organization_info.name,
+ organization_info.phone_number,
+ organization_info.address,
+ label_info.is_minimal,
+ label_info.record_keeping,
+ registration_number.identifiers, (list of reg numbers)
+ ]
"""
- if isinstance(inspection_id, str):
- inspection_id = UUID(inspection_id)
- if isinstance(user_id, str):
- user_id = UUID(user_id)
-
- # Delete the inspection and get the returned data
- deleted_inspection = inspection.delete_inspection(cursor, inspection_id, user_id)
- deleted_inspection = data_inspection.DBInspection.model_validate(deleted_inspection)
-
- await datastore.delete_picture_set_permanently(
- cursor, str(user_id), str(deleted_inspection.picture_set_id), container_client
+ label_ids = []
+ # search based on Organization info
+ if (
+ organization_name is not None
+ or organization_address is not None
+ or organization_phone is not None
+ ):
+ orgs = organization.search_organization_information(
+ cursor=cursor,
+ name=organization_name,
+ address=organization_address,
+ phone_number=organization_phone,
+ website=None,
+ )
+ if org is not None and len(orgs) > 0:
+ for org in orgs:
+ label_ids.append(org[1])
+ # search based on registration number
+ if reg_number is not None and reg_number.strip() == "":
+ reg_result = registration_number.search_registration_number(
+ cursor=cursor, registration_number=reg_number
+ )
+ if reg_result is not None and len(reg_result) > 0:
+ for reg in reg_result:
+ label_ids.append(reg[1])
+ return inspection.search_inspection(
+ cursor=cursor,
+ fertilizer_name=fertilizer_name,
+ lower_bound_date=lower_bound_date,
+ upper_bound_date=upper_bound_date,
+ lot_number=lot_number,
+ label_ids=label_ids,
+ inspector_name=inspector_name
)
-
- return deleted_inspection
diff --git a/fertiscan/db/bytebase/OLAP/guaranteed_triggers.sql b/fertiscan/db/bytebase/OLAP/guaranteed_triggers.sql
index 90e3bd6c..08ae0d8c 100644
--- a/fertiscan/db/bytebase/OLAP/guaranteed_triggers.sql
+++ b/fertiscan/db/bytebase/OLAP/guaranteed_triggers.sql
@@ -1,11 +1,11 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_guaranteed_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_guaranteed_creation()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
IF (NEW.id IS NOT NULL) AND (NEW.label_id IS NOT NULL) THEN
-- Update the label_dimension table with the new guaranteed_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET guaranteed_ids = array_append(guaranteed_ids, NEW.id)
WHERE label_dimension.label_id = NEW.label_id;
ELSE
@@ -17,19 +17,19 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS guaranteed_creation ON "fertiscan_0.0.18".guaranteed;
+DROP TRIGGER IF EXISTS guaranteed_creation ON "fertiscan_0.1.1".guaranteed;
CREATE TRIGGER guaranteed_creation
-AFTER INSERT ON "fertiscan_0.0.18".guaranteed
+AFTER INSERT ON "fertiscan_0.1.1".guaranteed
FOR EACH ROW
EXECUTE FUNCTION olap_guaranteed_creation();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_guaranteed_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_guaranteed_deletion()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
IF (OLD.id IS NOT NULL) AND (OLD.label_id IS NOT NULL) THEN
-- Update the label_dimension table with the new guaranteed_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET guaranteed_ids = array_remove(guaranteed_ids, OLD.id)
WHERE label_dimension.label_id = OLD.label_id;
ELSE
@@ -41,8 +41,8 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS guaranteed_deletion ON "fertiscan_0.0.18".guaranteed;
+DROP TRIGGER IF EXISTS guaranteed_deletion ON "fertiscan_0.1.1".guaranteed;
CREATE TRIGGER guaranteed_deletion
-AFTER DELETE ON "fertiscan_0.0.18".guaranteed
+AFTER DELETE ON "fertiscan_0.1.1".guaranteed
FOR EACH ROW
EXECUTE FUNCTION olap_guaranteed_deletion();
diff --git a/fertiscan/db/bytebase/OLAP/ingredient_trigger.sql b/fertiscan/db/bytebase/OLAP/ingredient_trigger.sql
index 2078fef4..2a6e9ba0 100644
--- a/fertiscan/db/bytebase/OLAP/ingredient_trigger.sql
+++ b/fertiscan/db/bytebase/OLAP/ingredient_trigger.sql
@@ -1,11 +1,11 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_ingredient_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_ingredient_creation()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
IF (NEW.id IS NOT NULL) AND (NEW.label_id IS NOT NULL) THEN
-- Update the label_dimension table with the new ingredient_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET ingredient_ids = array_append(ingredient_ids, NEW.id)
WHERE label_dimension.label_id = NEW.label_id;
ELSE
@@ -17,19 +17,19 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS ingredient_creation ON "fertiscan_0.0.18".ingredient;
+DROP TRIGGER IF EXISTS ingredient_creation ON "fertiscan_0.1.1".ingredient;
CREATE TRIGGER ingredient_creation
-AFTER INSERT ON "fertiscan_0.0.18".ingredient
+AFTER INSERT ON "fertiscan_0.1.1".ingredient
FOR EACH ROW
EXECUTE FUNCTION olap_ingredient_creation();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_ingredient_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_ingredient_deletion()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
IF (OLD.id IS NOT NULL) AND (OLD.label_id IS NOT NULL) THEN
-- Update the label_dimension table with the new ingredient_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET ingredient_ids = array_remove(ingredient_ids, OLD.id)
WHERE label_dimension.label_id = OLD.label_id;
ELSE
@@ -41,8 +41,8 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS ingredient_deletion ON "fertiscan_0.0.18".ingredient;
+DROP TRIGGER IF EXISTS ingredient_deletion ON "fertiscan_0.1.1".ingredient;
CREATE TRIGGER ingredient_deletion
-AFTER DELETE ON "fertiscan_0.0.18".ingredient
+AFTER DELETE ON "fertiscan_0.1.1".ingredient
FOR EACH ROW
EXECUTE FUNCTION olap_ingredient_deletion();
diff --git a/fertiscan/db/bytebase/OLAP/inspection_triggers.sql b/fertiscan/db/bytebase/OLAP/inspection_triggers.sql
index 9519ac75..478d529e 100644
--- a/fertiscan/db/bytebase/OLAP/inspection_triggers.sql
+++ b/fertiscan/db/bytebase/OLAP/inspection_triggers.sql
@@ -1,5 +1,5 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_inspection_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_inspection_creation()
RETURNS TRIGGER AS $$
DECLARE
time_id UUID;
@@ -7,7 +7,7 @@ BEGIN
IF (TG_OP = 'INSERT') THEN
IF (NEW.id IS NOT NULL) AND (NEW.label_info_id IS NOT NULL) THEN
-- Time Dimension
- INSERT INTO "fertiscan_0.0.18".time_dimension (
+ INSERT INTO "fertiscan_0.1.1".time_dimension (
date_value, year,month,day)
VALUES (
CURRENT_DATE,
@@ -16,7 +16,7 @@ BEGIN
EXTRACT(DAY FROM CURRENT_DATE)
) RETURNING id INTO time_id;
-- Create the Inspection_factual entry
- INSERT INTO "fertiscan_0.0.18".inspection_factual (
+ INSERT INTO "fertiscan_0.1.1".inspection_factual (
inspection_id, inspector_id, label_info_id, time_id, sample_id, picture_set_id, original_dataset
) VALUES (
NEW.id,
@@ -36,19 +36,19 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS inspection_creation ON "fertiscan_0.0.18".inspection;
+DROP TRIGGER IF EXISTS inspection_creation ON "fertiscan_0.1.1".inspection;
CREATE TRIGGER inspection_creation
-AFTER INSERT ON "fertiscan_0.0.18".inspection
+AFTER INSERT ON "fertiscan_0.1.1".inspection
FOR EACH ROW
EXECUTE FUNCTION olap_inspection_creation();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_inspection_update()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_inspection_update()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'UPDATE') THEN
IF (NEW.id IS NOT NULL) THEN
IF (NEW.label_info_id != OLD.label_info_id) OR (NEW.inspector_id != OLD.inspector_id) OR (NEW.picture_set_id != OLD.picture_set_id) THEN
- UPDATE "fertiscan_0.0.18".inspection_factual
+ UPDATE "fertiscan_0.1.1".inspection_factual
SET inspector_id = NEW.inspector_id, label_info_id = NEW.label_info_id, picture_set_id = NEW.picture_set_id
WHERE inspection_id = NEW.id;
END IF;
@@ -61,18 +61,18 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS inspection_update ON "fertiscan_0.0.18".inspection;
+DROP TRIGGER IF EXISTS inspection_update ON "fertiscan_0.1.1".inspection;
CREATE TRIGGER inspection_update
-BEFORE UPDATE ON "fertiscan_0.0.18".inspection
+BEFORE UPDATE ON "fertiscan_0.1.1".inspection
FOR EACH ROW
EXECUTE FUNCTION olap_inspection_update();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_inspection_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_inspection_deletion()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
IF (OLD.id IS NOT NULL) THEN
- DELETE FROM "fertiscan_0.0.18".inspection_factual
+ DELETE FROM "fertiscan_0.1.1".inspection_factual
WHERE inspection_id = OLD.id;
ELSE
-- Raise a warning if the condition is not met
@@ -83,8 +83,8 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS inspection_deletion ON "fertiscan_0.0.18".inspection;
+DROP TRIGGER IF EXISTS inspection_deletion ON "fertiscan_0.1.1".inspection;
CREATE TRIGGER inspection_deletion
-AFTER DELETE ON "fertiscan_0.0.18".inspection
+AFTER DELETE ON "fertiscan_0.1.1".inspection
FOR EACH ROW
EXECUTE FUNCTION olap_inspection_deletion();
diff --git a/fertiscan/db/bytebase/OLAP/label_information_triggers.sql b/fertiscan/db/bytebase/OLAP/label_information_triggers.sql
index ddca34c2..e436783d 100644
--- a/fertiscan/db/bytebase/OLAP/label_information_triggers.sql
+++ b/fertiscan/db/bytebase/OLAP/label_information_triggers.sql
@@ -1,10 +1,10 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_label_information_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_label_information_creation()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
IF (NEW.id IS NOT NULL) THEN
- INSERT INTO "fertiscan_0.0.18"."label_dimension" (
+ INSERT INTO "fertiscan_0.1.1"."label_dimension" (
label_id
) VALUES (
NEW.id
@@ -18,19 +18,19 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS label_information_creation ON "fertiscan_0.0.18".label_information;
+DROP TRIGGER IF EXISTS label_information_creation ON "fertiscan_0.1.1".label_information;
CREATE TRIGGER label_information_creation
-AFTER INSERT ON "fertiscan_0.0.18".label_information
+AFTER INSERT ON "fertiscan_0.1.1".label_information
FOR EACH ROW
EXECUTE FUNCTION olap_label_information_creation();
--- CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_label_information_update()
+-- CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_label_information_update()
-- RETURNS TRIGGER AS $$
-- BEGIN
-- IF (TG_OP = 'UPDATE') THEN
-- IF (NEW.id IS NOT NULL) THEN
-- IF (NEW.company_info_id !=OLD.company_info_id) OR (NEW.manufacturer_info_id != OLD.manufacturer_info_id) THEN
--- UPDATE "fertiscan_0.0.18"."label_dimension"
+-- UPDATE "fertiscan_0.1.1"."label_dimension"
-- SET company_info_id = NEW.company_info_id, manufacturer_info_id = NEW.manufacturer_info_id
-- WHERE label_id = NEW.id;
-- END IF;
@@ -43,18 +43,18 @@ EXECUTE FUNCTION olap_label_information_creation();
-- END;
-- $$ LANGUAGE plpgsql;
--- DROP TRIGGER IF EXISTS label_information_update ON "fertiscan_0.0.18".label_information;
+-- DROP TRIGGER IF EXISTS label_information_update ON "fertiscan_0.1.1".label_information;
-- CREATE TRIGGER label_information_update
--- BEFORE UPDATE ON "fertiscan_0.0.18".label_information
+-- BEFORE UPDATE ON "fertiscan_0.1.1".label_information
-- FOR EACH ROW
-- EXECUTE FUNCTION olap_label_information_update();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_label_information_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_label_information_deletion()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
IF (OLD.id IS NOT NULL) THEN
- DELETE FROM "fertiscan_0.0.18"."label_dimension"
+ DELETE FROM "fertiscan_0.1.1"."label_dimension"
WHERE label_id = OLD.id;
ELSE
-- Raise a warning if the condition is not met
@@ -65,8 +65,8 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS label_information_deletion ON "fertiscan_0.0.18".label_information;
+DROP TRIGGER IF EXISTS label_information_deletion ON "fertiscan_0.1.1".label_information;
CREATE TRIGGER label_information_deletion
-AFTER DELETE ON "fertiscan_0.0.18".label_information
+AFTER DELETE ON "fertiscan_0.1.1".label_information
FOR EACH ROW
EXECUTE FUNCTION olap_label_information_deletion();
diff --git a/fertiscan/db/bytebase/OLAP/metrics_triggers.sql b/fertiscan/db/bytebase/OLAP/metrics_triggers.sql
index 104c2c0f..4a8c5106 100644
--- a/fertiscan/db/bytebase/OLAP/metrics_triggers.sql
+++ b/fertiscan/db/bytebase/OLAP/metrics_triggers.sql
@@ -1,5 +1,5 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_metrics_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_metrics_creation()
RETURNS TRIGGER AS $$
DECLARE
metric_type TEXT;
@@ -11,7 +11,7 @@ BEGIN
IF (metric_type ILIKE 'test%') THEN
RETURN NEW;
END IF;
- EXECUTE format('UPDATE "fertiscan_0.0.18"."label_dimension"
+ EXECUTE format('UPDATE "fertiscan_0.1.1"."label_dimension"
SET %I = array_append(%I, %L)
WHERE label_dimension.label_id = %L',
metric_type, metric_type, NEW.id, NEW.label_id);
@@ -24,13 +24,13 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS metrics_creation ON "fertiscan_0.0.18".metric;
+DROP TRIGGER IF EXISTS metrics_creation ON "fertiscan_0.1.1".metric;
CREATE TRIGGER metrics_creation
-AFTER INSERT ON "fertiscan_0.0.18".metric
+AFTER INSERT ON "fertiscan_0.1.1".metric
FOR EACH ROW
EXECUTE FUNCTION olap_metrics_creation();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_metrics_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_metrics_deletion()
RETURNS TRIGGER AS $$
DECLARE
metric_type TEXT;
@@ -42,7 +42,7 @@ BEGIN
IF (metric_type ILIKE 'test%') THEN
RETURN OLD;
END IF;
- EXECUTE format('UPDATE "fertiscan_0.0.18"."label_dimension"
+ EXECUTE format('UPDATE "fertiscan_0.1.1"."label_dimension"
SET %I = array_remove(%I, %L)
WHERE label_dimension.label_id = %L',
metric_type, metric_type, OLD.id, OLD.label_id);
@@ -55,8 +55,8 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS metrics_deletion ON "fertiscan_0.0.18".metric;
+DROP TRIGGER IF EXISTS metrics_deletion ON "fertiscan_0.1.1".metric;
CREATE TRIGGER metrics_deletion
-AFTER DELETE ON "fertiscan_0.0.18".metric
+AFTER DELETE ON "fertiscan_0.1.1".metric
FOR EACH ROW
EXECUTE FUNCTION olap_metrics_deletion();
diff --git a/fertiscan/db/bytebase/OLAP/micronutrient_triggers.sql b/fertiscan/db/bytebase/OLAP/micronutrient_triggers.sql
index f23fefa1..39a1cb88 100644
--- a/fertiscan/db/bytebase/OLAP/micronutrient_triggers.sql
+++ b/fertiscan/db/bytebase/OLAP/micronutrient_triggers.sql
@@ -1,11 +1,11 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_micronutrient_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_micronutrient_creation()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
IF (NEW.id IS NOT NULL) AND (NEW.label_id IS NOT NULL) THEN
-- Update the label_dimension table with the new micronutrient_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET micronutrient_ids = array_append(micronutrient_ids, NEW.id)
WHERE label_dimension.label_id = NEW.label_id;
ELSE
@@ -17,19 +17,19 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS micronutrient_creation ON "fertiscan_0.0.18".micronutrient;
+DROP TRIGGER IF EXISTS micronutrient_creation ON "fertiscan_0.1.1".micronutrient;
CREATE TRIGGER micronutrient_creation
-AFTER INSERT ON "fertiscan_0.0.18".micronutrient
+AFTER INSERT ON "fertiscan_0.1.1".micronutrient
FOR EACH ROW
EXECUTE FUNCTION olap_micronutrient_creation();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_micronutrient_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_micronutrient_deletion()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
IF (OLD.id IS NOT NULL) AND (OLD.label_id IS NOT NULL) THEN
-- Update the label_dimension table with the new micronutrient_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET micronutrient_ids = array_remove(micronutrient_ids, OLD.id)
WHERE label_dimension.label_id = OLD.label_id;
ELSE
@@ -41,8 +41,8 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS micronutrient_deletion ON "fertiscan_0.0.18".micronutrient;
+DROP TRIGGER IF EXISTS micronutrient_deletion ON "fertiscan_0.1.1".micronutrient;
CREATE TRIGGER micronutrient_deletion
-AFTER DELETE ON "fertiscan_0.0.18".micronutrient
+AFTER DELETE ON "fertiscan_0.1.1".micronutrient
FOR EACH ROW
EXECUTE FUNCTION olap_micronutrient_deletion();
diff --git a/fertiscan/db/bytebase/OLAP/organization_triggers.sql b/fertiscan/db/bytebase/OLAP/organization_triggers.sql
index 04c308be..57ec2d80 100644
--- a/fertiscan/db/bytebase/OLAP/organization_triggers.sql
+++ b/fertiscan/db/bytebase/OLAP/organization_triggers.sql
@@ -1,10 +1,10 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_organization_information_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_organization_information_creation()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
IF (NEW.id IS NOT NULL) THEN
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET organization_info_ids = array_append(organization_info_ids, NEW.id)
WHERE label_dimension.label_id = NEW.label_id;
ELSE
@@ -16,18 +16,18 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS organization_information_creation ON "fertiscan_0.0.18".organization_information;
+DROP TRIGGER IF EXISTS organization_information_creation ON "fertiscan_0.1.1".organization_information;
CREATE TRIGGER organization_information_creation
-AFTER INSERT ON "fertiscan_0.0.18".organization_information
+AFTER INSERT ON "fertiscan_0.1.1".organization_information
FOR EACH ROW
EXECUTE FUNCTION olap_organization_information_creation();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_organization_information_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_organization_information_deletion()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
IF (OLD.id IS NOT NULL) THEN
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET organization_info_ids = array_remove(organization_info_ids, OLD.id)
WHERE label_dimension.label_id = OLD.label_id;
ELSE
diff --git a/fertiscan/db/bytebase/OLAP/registration_number_triggers.sql b/fertiscan/db/bytebase/OLAP/registration_number_triggers.sql
index fcccc1ef..60c70e07 100644
--- a/fertiscan/db/bytebase/OLAP/registration_number_triggers.sql
+++ b/fertiscan/db/bytebase/OLAP/registration_number_triggers.sql
@@ -1,5 +1,5 @@
-- Trigger function
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_registration_number_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_registration_number_creation()
RETURNS TRIGGER AS $$
BEGIN
-- Check if the operation is an INSERT
@@ -7,7 +7,7 @@ BEGIN
-- Check if the NEW.id is not NULL
IF (NEW.id IS NOT NULL) AND (NEW.label_id IS NOT NULL) AND (NEW.identifier IS NOT NULL) THEN
-- Update the label_dimension table with the new guaranteed_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET registration_number_ids = array_append(registration_number_ids, NEW.id)
WHERE label_dimension.label_id = NEW.label_id;
ELSE
@@ -20,14 +20,14 @@ END;
$$ LANGUAGE plpgsql;
-- Trigger
-DROP TRIGGER IF EXISTS registration_number_creation ON "fertiscan_0.0.18".registration_number_information;
+DROP TRIGGER IF EXISTS registration_number_creation ON "fertiscan_0.1.1".registration_number_information;
CREATE TRIGGER registration_number_creation
-AFTER INSERT ON "fertiscan_0.0.18".registration_number_information
+AFTER INSERT ON "fertiscan_0.1.1".registration_number_information
FOR EACH ROW
EXECUTE FUNCTION olap_registration_number_creation();
-- Trigger function
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_registration_number_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_registration_number_deletion()
RETURNS TRIGGER AS $$
BEGIN
-- Check if the operation is an INSERT
@@ -35,7 +35,7 @@ BEGIN
-- Check if the NEW.id is not NULL
IF (OLD.id IS NOT NULL) AND (OLD.label_id IS NOT NULL) THEN
-- Update the label_dimension table with the new guaranteed_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET registration_number_ids = array_remove(registration_number_ids, OLD.id)
WHERE label_dimension.label_id = OLD.label_id;
ELSE
@@ -48,8 +48,8 @@ END;
$$ LANGUAGE plpgsql;
-- Trigger
-DROP TRIGGER IF EXISTS registration_number_deletion ON "fertiscan_0.0.18".registration_number_information;
+DROP TRIGGER IF EXISTS registration_number_deletion ON "fertiscan_0.1.1".registration_number_information;
CREATE TRIGGER registration_number_deletion
-AFTER INSERT ON "fertiscan_0.0.18".registration_number_information
+AFTER INSERT ON "fertiscan_0.1.1".registration_number_information
FOR EACH ROW
EXECUTE FUNCTION olap_registration_number_deletion();
diff --git a/fertiscan/db/bytebase/OLAP/specification_triggers.sql b/fertiscan/db/bytebase/OLAP/specification_triggers.sql
index 840e0678..e13a31f3 100644
--- a/fertiscan/db/bytebase/OLAP/specification_triggers.sql
+++ b/fertiscan/db/bytebase/OLAP/specification_triggers.sql
@@ -1,11 +1,11 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_specification_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_specification_creation()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
IF (NEW.id IS NOT NULL) AND (NEW.label_id IS NOT NULL) THEN
-- Update the label_dimension table with the new specification_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET specification_ids = array_append(specification_ids, NEW.id)
WHERE label_dimension.label_id = NEW.label_id;
ELSE
@@ -17,19 +17,19 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS specification_creation ON "fertiscan_0.0.18".specification;
+DROP TRIGGER IF EXISTS specification_creation ON "fertiscan_0.1.1".specification;
CREATE TRIGGER specification_creation
-AFTER INSERT ON "fertiscan_0.0.18".specification
+AFTER INSERT ON "fertiscan_0.1.1".specification
FOR EACH ROW
EXECUTE FUNCTION olap_specification_creation();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_specification_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_specification_deletion()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
IF (OLD.id IS NOT NULL) AND (OLD.label_id IS NOT NULL) THEN
-- Update the label_dimension table with the new specification_analysis_id
- UPDATE "fertiscan_0.0.18"."label_dimension"
+ UPDATE "fertiscan_0.1.1"."label_dimension"
SET specification_ids = array_remove(specification_ids, OLD.id)
WHERE label_dimension.label_id = OLD.label_id;
ELSE
@@ -41,8 +41,8 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS specification_deletion ON "fertiscan_0.0.18".specification;
+DROP TRIGGER IF EXISTS specification_deletion ON "fertiscan_0.1.1".specification;
CREATE TRIGGER specification_deletion
-AFTER DELETE ON "fertiscan_0.0.18".specification
+AFTER DELETE ON "fertiscan_0.1.1".specification
FOR EACH ROW
EXECUTE FUNCTION olap_specification_deletion();
diff --git a/fertiscan/db/bytebase/OLAP/sub_label_triggers.sql b/fertiscan/db/bytebase/OLAP/sub_label_triggers.sql
index e8ba9298..e525c79a 100644
--- a/fertiscan/db/bytebase/OLAP/sub_label_triggers.sql
+++ b/fertiscan/db/bytebase/OLAP/sub_label_triggers.sql
@@ -1,5 +1,5 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_sub_label_creation()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_sub_label_creation()
RETURNS TRIGGER AS $$
DECLARE
type_str TEXT;
@@ -7,12 +7,12 @@ BEGIN
IF (TG_OP = 'INSERT') THEN
IF (NEW.id IS NOT NULL) AND (NEW.label_id IS NOT NULL) AND (NEW.sub_type_id IS NOT NULL) THEN
-- FIND THE SUB_TYPE TO GET THE COLUMN IDENTIFIER
- SELECT sub_type.type_en INTO type_str FROM "fertiscan_0.0.18".sub_type WHERE sub_type.id = NEW.sub_type_id;
+ SELECT sub_type.type_en INTO type_str FROM "fertiscan_0.1.1".sub_type WHERE sub_type.id = NEW.sub_type_id;
IF (type_str ILIKE 'test%') THEN
RETURN NEW; -- Do not update the OLAP dimension for test sub_labels
END IF;
type_str = type_str || '_ids';
- EXECUTE format('UPDATE "fertiscan_0.0.18".label_dimension
+ EXECUTE format('UPDATE "fertiscan_0.1.1".label_dimension
SET %I = array_append(%I, %L)
WHERE label_id = %L;',
type_str, type_str, NEW.id, NEW.label_id);
@@ -23,13 +23,13 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS sub_label_creation ON "fertiscan_0.0.18".sub_label;
+DROP TRIGGER IF EXISTS sub_label_creation ON "fertiscan_0.1.1".sub_label;
CREATE TRIGGER sub_label_creation
-AFTER INSERT ON "fertiscan_0.0.18".sub_label
+AFTER INSERT ON "fertiscan_0.1.1".sub_label
FOR EACH ROW
EXECUTE FUNCTION olap_sub_label_creation();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".olap_sub_label_deletion()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".olap_sub_label_deletion()
RETURNS TRIGGER AS $$
DECLARE
type_str TEXT;
@@ -37,12 +37,12 @@ BEGIN
IF (TG_OP = 'DELETE') THEN
IF (OLD.id IS NOT NULL) AND (OLD.label_id IS NOT NULL) AND (OLD.sub_type_id IS NOT NULL) THEN
-- FIND THE SUB_TYPE TO GET THE COLUMN IDENTIFIER
- SELECT sub_type.type_en INTO type_str FROM "fertiscan_0.0.18".sub_type WHERE sub_type.id = OLD.sub_type_id;
+ SELECT sub_type.type_en INTO type_str FROM "fertiscan_0.1.1".sub_type WHERE sub_type.id = OLD.sub_type_id;
IF (type_str ILIKE 'test%') THEN
RETURN OLD; -- Do not update the OLAP dimension for test sub_labels
END IF;
type_str = type_str || '_ids';
- EXECUTE format('UPDATE "fertiscan_0.0.18".label_dimension
+ EXECUTE format('UPDATE "fertiscan_0.1.1".label_dimension
SET %I = array_remove(%I, %L)
WHERE label_id = %L;',
type_str, type_str, OLD.id, OLD.label_id);
@@ -55,8 +55,8 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS sub_label_deletion ON "fertiscan_0.0.18".sub_label;
+DROP TRIGGER IF EXISTS sub_label_deletion ON "fertiscan_0.1.1".sub_label;
CREATE TRIGGER sub_label_deletion
-AFTER DELETE ON "fertiscan_0.0.18".sub_label
+AFTER DELETE ON "fertiscan_0.1.1".sub_label
FOR EACH ROW
EXECUTE FUNCTION olap_sub_label_deletion();
diff --git a/fertiscan/db/bytebase/delete_inspection_function.sql b/fertiscan/db/bytebase/delete_inspection_function.sql
index 0fdfefe1..be502500 100644
--- a/fertiscan/db/bytebase/delete_inspection_function.sql
+++ b/fertiscan/db/bytebase/delete_inspection_function.sql
@@ -1,17 +1,17 @@
-- To avoid potential schema drift issues
-SET search_path TO "fertiscan_0.0.18";
+SET search_path TO "fertiscan_0.1.1";
-- Trigger function to handle after organization_information delete for location deletion
-DROP TRIGGER IF EXISTS after_organization_delete_main_location ON "fertiscan_0.0.18".organization;
-drop FUNCTION IF EXISTS "fertiscan_0.0.18".after_org_delete_location_trig();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".after_org_delete_location_trig()
+DROP TRIGGER IF EXISTS after_organization_delete_main_location ON "fertiscan_0.1.1".organization;
+drop FUNCTION IF EXISTS "fertiscan_0.1.1".after_org_delete_location_trig();
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".after_org_delete_location_trig()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
IF OLD.main_location_id IS NOT NULL THEN
BEGIN
- DELETE FROM "fertiscan_0.0.18".location
+ DELETE FROM "fertiscan_0.1.1".location
WHERE id = OLD.main_location_id;
EXCEPTION WHEN foreign_key_violation THEN
RAISE NOTICE 'Location % is still referenced by another record and cannot be deleted.', OLD.main_location_id;
@@ -24,12 +24,12 @@ $$;
-- Trigger definition on organization_information table for location deletion
CREATE TRIGGER after_organization_delete_main_location
-AFTER DELETE ON "fertiscan_0.0.18".organization
+AFTER DELETE ON "fertiscan_0.1.1".organization
FOR EACH ROW
-EXECUTE FUNCTION "fertiscan_0.0.18".after_org_delete_location_trig();
+EXECUTE FUNCTION "fertiscan_0.1.1".after_org_delete_location_trig();
-- Function to delete an inspection and related data
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".delete_inspection(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".delete_inspection(
p_inspection_id uuid,
p_inspector_id uuid
)
@@ -41,7 +41,7 @@ DECLARE
BEGIN
IF NOT EXISTS (
SELECT 1
- FROM "fertiscan_0.0.18".inspection
+ FROM "fertiscan_0.1.1".inspection
WHERE id = p_inspection_id
AND inspector_id = p_inspector_id
) THEN
@@ -50,7 +50,7 @@ BEGIN
-- Delete the inspection record and retrieve it
WITH deleted_inspection AS (
- DELETE FROM "fertiscan_0.0.18".inspection
+ DELETE FROM "fertiscan_0.1.1".inspection
WHERE id = p_inspection_id
RETURNING *
)
@@ -64,7 +64,7 @@ END;
$$;
-- Combined trigger function to handle after inspection delete for sample and label_information deletion
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".after_insp_delete_cleanup_trig()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".after_insp_delete_cleanup_trig()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
@@ -72,30 +72,30 @@ DECLARE
newest_inspection_id uuid;
BEGIN
IF OLD.sample_id IS NOT NULL THEN
- DELETE FROM "fertiscan_0.0.18".sample
+ DELETE FROM "fertiscan_0.1.1".sample
WHERE id = OLD.sample_id;
END IF;
IF OLD.label_info_id IS NOT NULL THEN
- DELETE FROM "fertiscan_0.0.18".label_information
+ DELETE FROM "fertiscan_0.1.1".label_information
WHERE id = OLD.label_info_id;
END IF;
IF OLD.fertilizer_id IS NOT NULL THEN
-- Select the newest inspection for the fertilizer.latest_inspection_id
SELECT id INTO newest_inspection_id
- from "fertiscan_0.0.18".inspection
+ from "fertiscan_0.1.1".inspection
WHERE fertilizer_id = OLD.fertilizer_id AND verified_date IS NOT NULL AND id != OLD.id
ORDER BY verified_date DESC
LIMIT 1;
if newest_inspection_id IS NOT NULL THEN
- UPDATE "fertiscan_0.0.18".fertilizer
+ UPDATE "fertiscan_0.1.1".fertilizer
SET latest_inspection_id = newest_inspection_id
WHERE id = OLD.fertilizer_id;
ELSE
--This was the only inspection for the fertilizer so we delete it
- DELETE FROM "fertiscan_0.0.18".fertilizer
+ DELETE FROM "fertiscan_0.1.1".fertilizer
WHERE id = OLD.fertilizer_id;
end if;
END IF;
@@ -105,8 +105,8 @@ END;
$$;
-- Trigger definition on inspection table for combined cleanup (sample and label_information deletion)
-DROP TRIGGER IF EXISTS after_inspection_delete_cleanup ON "fertiscan_0.0.18".inspection;
+DROP TRIGGER IF EXISTS after_inspection_delete_cleanup ON "fertiscan_0.1.1".inspection;
CREATE TRIGGER after_inspection_delete_cleanup
-AFTER DELETE ON "fertiscan_0.0.18".inspection
+AFTER DELETE ON "fertiscan_0.1.1".inspection
FOR EACH ROW
-EXECUTE FUNCTION "fertiscan_0.0.18".after_insp_delete_cleanup_trig();
+EXECUTE FUNCTION "fertiscan_0.1.1".after_insp_delete_cleanup_trig();
diff --git a/fertiscan/db/bytebase/get_inspection/get_guaranteed_analysis.sql b/fertiscan/db/bytebase/get_inspection/get_guaranteed_analysis.sql
index e652cfb7..911982b6 100644
--- a/fertiscan/db/bytebase/get_inspection/get_guaranteed_analysis.sql
+++ b/fertiscan/db/bytebase/get_inspection/get_guaranteed_analysis.sql
@@ -1,4 +1,4 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_guaranteed_analysis_json(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_guaranteed_analysis_json(
label_info_id uuid
)
RETURNS jsonb
@@ -28,7 +28,7 @@ BEGIN
) FILTER (WHERE guaranteed.language = 'fr'), '[]'::jsonb)
)
INTO result_json
- FROM "fertiscan_0.0.18".guaranteed
+ FROM "fertiscan_0.1.1".guaranteed
WHERE guaranteed.label_id = label_info_id;
-- build Guaranteed_analysis title json
@@ -38,7 +38,7 @@ BEGIN
'is_minimal', title_is_minimal
)
INTO result_json_title
- FROM "fertiscan_0.0.18".label_information
+ FROM "fertiscan_0.1.1".label_information
WHERE id = label_info_id;
-- merge JSONs
diff --git a/fertiscan/db/bytebase/get_inspection/get_ingredients_json.sql b/fertiscan/db/bytebase/get_inspection/get_ingredients_json.sql
index 5df6576d..15750cc9 100644
--- a/fertiscan/db/bytebase/get_inspection/get_ingredients_json.sql
+++ b/fertiscan/db/bytebase/get_inspection/get_ingredients_json.sql
@@ -1,5 +1,5 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_ingredients_json(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_ingredients_json(
label_info_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
diff --git a/fertiscan/db/bytebase/get_inspection/get_label_info_json.sql b/fertiscan/db/bytebase/get_inspection/get_label_info_json.sql
index 011cd1d1..95760404 100644
--- a/fertiscan/db/bytebase/get_inspection/get_label_info_json.sql
+++ b/fertiscan/db/bytebase/get_inspection/get_label_info_json.sql
@@ -1,4 +1,4 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_label_info_json(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_label_info_json(
label_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
diff --git a/fertiscan/db/bytebase/get_inspection/get_metrics_json.sql b/fertiscan/db/bytebase/get_inspection/get_metrics_json.sql
index 93c340ec..dd0caa36 100644
--- a/fertiscan/db/bytebase/get_inspection/get_metrics_json.sql
+++ b/fertiscan/db/bytebase/get_inspection/get_metrics_json.sql
@@ -1,4 +1,4 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_metrics_json(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_metrics_json(
label_info_id uuid
)
RETURNS jsonb
diff --git a/fertiscan/db/bytebase/get_inspection/get_micronutrients_json.sql b/fertiscan/db/bytebase/get_inspection/get_micronutrients_json.sql
index 420f51d8..1eb7cfe0 100644
--- a/fertiscan/db/bytebase/get_inspection/get_micronutrients_json.sql
+++ b/fertiscan/db/bytebase/get_inspection/get_micronutrients_json.sql
@@ -1,5 +1,5 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_micronutrient_json(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_micronutrient_json(
label_info_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
diff --git a/fertiscan/db/bytebase/get_inspection/get_organizations_json.sql b/fertiscan/db/bytebase/get_inspection/get_organizations_json.sql
index 5ebd1500..afb7619b 100644
--- a/fertiscan/db/bytebase/get_inspection/get_organizations_json.sql
+++ b/fertiscan/db/bytebase/get_inspection/get_organizations_json.sql
@@ -1,7 +1,7 @@
--Unverified organization data
-DROP FUNCTION IF EXISTS "fertiscan_0.0.18".get_organizations_information_json(label_id_value uuid);
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_organizations_information_json(
+DROP FUNCTION IF EXISTS "fertiscan_0.1.1".get_organizations_information_json(label_id_value uuid);
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_organizations_information_json(
label_id_value uuid)
RETURNS jsonb
LANGUAGE plpgsql
@@ -31,8 +31,8 @@ END;
$function$;
-- verified organization
-DROP FUNCTION IF EXISTS "fertiscan_0.0.18".get_organizations_json();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_organizations_json()
+DROP FUNCTION IF EXISTS "fertiscan_0.1.1".get_organizations_json();
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_organizations_json()
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
diff --git a/fertiscan/db/bytebase/get_inspection/get_registration_numbers_json.sql b/fertiscan/db/bytebase/get_inspection/get_registration_numbers_json.sql
index cf2e372a..c0fdbdfc 100644
--- a/fertiscan/db/bytebase/get_inspection/get_registration_numbers_json.sql
+++ b/fertiscan/db/bytebase/get_inspection/get_registration_numbers_json.sql
@@ -1,5 +1,5 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_registration_numbers_json(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_registration_numbers_json(
label_info_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
diff --git a/fertiscan/db/bytebase/get_inspection/get_specification_json.sql b/fertiscan/db/bytebase/get_inspection/get_specification_json.sql
index 5dc0cce9..135f8072 100644
--- a/fertiscan/db/bytebase/get_inspection/get_specification_json.sql
+++ b/fertiscan/db/bytebase/get_inspection/get_specification_json.sql
@@ -1,4 +1,4 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_specification_json(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_specification_json(
label_info_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
diff --git a/fertiscan/db/bytebase/get_inspection/get_sub_label.sql b/fertiscan/db/bytebase/get_inspection/get_sub_label.sql
index 4393c15f..d1a38fbc 100644
--- a/fertiscan/db/bytebase/get_inspection/get_sub_label.sql
+++ b/fertiscan/db/bytebase/get_inspection/get_sub_label.sql
@@ -1,4 +1,4 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_sub_label_json(label_info_id uuid)
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".get_sub_label_json(label_info_id uuid)
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
diff --git a/fertiscan/db/bytebase/new_inspection/new_guaranteed_analysis.sql b/fertiscan/db/bytebase/new_inspection/new_guaranteed_analysis.sql
index 9f865123..34b46c69 100644
--- a/fertiscan/db/bytebase/new_inspection/new_guaranteed_analysis.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_guaranteed_analysis.sql
@@ -1,9 +1,9 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_guaranteed_analysis(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_guaranteed_analysis(
name TEXT,
value FLOAT,
unit TEXT,
label_id UUID,
-language "fertiscan_0.0.18".language,
+language "fertiscan_0.1.1".language,
edited BOOLEAN = FALSE,
element_id int = NULL
)
diff --git a/fertiscan/db/bytebase/new_inspection/new_ingredient.sql b/fertiscan/db/bytebase/new_inspection/new_ingredient.sql
index 07438b89..ce3e9131 100644
--- a/fertiscan/db/bytebase/new_inspection/new_ingredient.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_ingredient.sql
@@ -1,9 +1,9 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_ingredient(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_ingredient(
name TEXT,
value FLOAt,
read_unit TEXT,
label_id UUID,
-language "fertiscan_0.0.18".language,
+language "fertiscan_0.1.1".language,
organic BOOLEAN,
active BOOLEAN,
edited BOOLEAN = FALSE
diff --git a/fertiscan/db/bytebase/new_inspection/new_label_information.sql b/fertiscan/db/bytebase/new_inspection/new_label_information.sql
index 004bfb02..d8db357b 100644
--- a/fertiscan/db/bytebase/new_inspection/new_label_information.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_label_information.sql
@@ -1,5 +1,5 @@
-drOp FUNCTION IF EXISTS "fertiscan_0.0.18".new_label_information(TEXT, TEXT, TEXT, FLOAT, FLOAT, FLOAT, TEXT, TEXT, BOOLEAN, UUID, UUID);
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_label_information(
+drOp FUNCTION IF EXISTS "fertiscan_0.1.1".new_label_information(TEXT, TEXT, TEXT, FLOAT, FLOAT, FLOAT, TEXT, TEXT, BOOLEAN, UUID, UUID);
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_label_information(
name TEXT,
lot_number TEXT,
npk TEXT,
@@ -18,7 +18,7 @@ DECLARE
label_id uuid;
record RECORD;
BEGIN
- SET SEARCH_PATH TO "fertiscan_0.0.18";
+ SET SEARCH_PATH TO "fertiscan_0.1.1";
-- LABEL INFORMATION
INSERT INTO label_information (
product_name,lot_number, npk, n, p, k, guaranteed_title_en, guaranteed_title_fr, title_is_minimal, record_keeping
diff --git a/fertiscan/db/bytebase/new_inspection/new_metric_unit.sql b/fertiscan/db/bytebase/new_inspection/new_metric_unit.sql
index 0adc4bc4..ab8120f8 100644
--- a/fertiscan/db/bytebase/new_inspection/new_metric_unit.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_metric_unit.sql
@@ -1,8 +1,8 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_metric_unit(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_metric_unit(
value FLOAT,
read_unit TEXT,
label_id UUID,
- metric_type "fertiscan_0.0.18".metric_type,
+ metric_type "fertiscan_0.1.1".metric_type,
edited BOOLEAN = FALSE
)
RETURNS UUID
diff --git a/fertiscan/db/bytebase/new_inspection/new_micronutrient.sql b/fertiscan/db/bytebase/new_inspection/new_micronutrient.sql
index 59c7a9f5..19c7fbd2 100644
--- a/fertiscan/db/bytebase/new_inspection/new_micronutrient.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_micronutrient.sql
@@ -1,9 +1,9 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_micronutrient(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_micronutrient(
name TEXT,
value FLOAT,
unit TEXT,
label_id UUID,
-language "fertiscan_0.0.18".language,
+language "fertiscan_0.1.1".language,
edited BOOLEAN = FALSE,
element_id int = NULL
)
diff --git a/fertiscan/db/bytebase/new_inspection/new_organization_information.sql b/fertiscan/db/bytebase/new_inspection/new_organization_information.sql
index f1647203..a3cece3f 100644
--- a/fertiscan/db/bytebase/new_inspection/new_organization_information.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_organization_information.sql
@@ -1,6 +1,6 @@
-DROP FUNCTION IF EXISTS "fertiscan_0.0.18".new_organization_located(TEXT, TEXT, TEXT, TEXT, BOOLEAN, UUID, BOOLEAN);
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_organization_information(
+DROP FUNCTION IF EXISTS "fertiscan_0.1.1".new_organization_located(TEXT, TEXT, TEXT, TEXT, BOOLEAN, UUID, BOOLEAN);
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_organization_information(
name TEXT,
address_str TEXT,
website TEXT,
diff --git a/fertiscan/db/bytebase/new_inspection/new_organization_located.sql b/fertiscan/db/bytebase/new_inspection/new_organization_located.sql
index 0d92aae2..e40da031 100644
--- a/fertiscan/db/bytebase/new_inspection/new_organization_located.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_organization_located.sql
@@ -1,6 +1,6 @@
-DROP FUNCTION IF EXISTS "fertiscan_0.0.18".new_organization_located(TEXT, TEXT, TEXT, TEXT, BOOLEAN, UUID, BOOLEAN);
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_organization_info_located(
+DROP FUNCTION IF EXISTS "fertiscan_0.1.1".new_organization_located(TEXT, TEXT, TEXT, TEXT, BOOLEAN, UUID, BOOLEAN);
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_organization_info_located(
name TEXT,
address_str TEXT,
website TEXT,
diff --git a/fertiscan/db/bytebase/new_inspection/new_registration_number.sql b/fertiscan/db/bytebase/new_inspection/new_registration_number.sql
index e0e2eaab..191ceee8 100644
--- a/fertiscan/db/bytebase/new_inspection/new_registration_number.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_registration_number.sql
@@ -1,6 +1,6 @@
-DROP FUNCTION IF EXISTS "fertiscan_0.0.18".new_registration_number(TEXT, UUID,BOOLEAN, TEXT, BOOLEAN);
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_registration_number(
+DROP FUNCTION IF EXISTS "fertiscan_0.1.1".new_registration_number(TEXT, UUID,BOOLEAN, TEXT, BOOLEAN);
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_registration_number(
identifier TEXT,
label_info_id UUID,
is_an_ingredient_val BOOLEAN DEFAULT NULL,
diff --git a/fertiscan/db/bytebase/new_inspection/new_specification.sql b/fertiscan/db/bytebase/new_inspection/new_specification.sql
index de586aea..c91bbd5c 100644
--- a/fertiscan/db/bytebase/new_inspection/new_specification.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_specification.sql
@@ -1,8 +1,8 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_specification(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_specification(
humidity FLOAT,
ph FLOAT,
solubility FLOAT,
-language "fertiscan_0.0.18".language,
+language "fertiscan_0.1.1".language,
label_id UUID,
edited BOOLEAN = FALSE
)
diff --git a/fertiscan/db/bytebase/new_inspection/new_sub_label.sql b/fertiscan/db/bytebase/new_inspection/new_sub_label.sql
index 9f4cb8c1..364fcea8 100644
--- a/fertiscan/db/bytebase/new_inspection/new_sub_label.sql
+++ b/fertiscan/db/bytebase/new_inspection/new_sub_label.sql
@@ -1,4 +1,4 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_sub_label(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_sub_label(
content_fr text DEFAULT NULL::text,
content_en text DEFAULT NULL::text,
label_id uuid DEFAULT NULL::uuid,
diff --git a/fertiscan/db/bytebase/new_inspection_function.sql b/fertiscan/db/bytebase/new_inspection_function.sql
index 8eba9fd3..1b54d6ae 100644
--- a/fertiscan/db/bytebase/new_inspection_function.sql
+++ b/fertiscan/db/bytebase/new_inspection_function.sql
@@ -1,5 +1,5 @@
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".new_inspection(user_id uuid, picture_set_id uuid, input_json jsonb)
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".new_inspection(user_id uuid, picture_set_id uuid, input_json jsonb)
RETURNS jsonb
LANGUAGE plpgsql
AS $function$
@@ -56,7 +56,7 @@ BEGIN
-- phone_number_string,
-- '') <> ''
-- THEN
--- company_id := "fertiscan_0.0.18".new_organization_info_located(
+-- company_id := "fertiscan_0.1.1".new_organization_info_located(
-- input_json->'company'->>'name',
-- input_json->'company'->>'address',
-- input_json->'company'->>'website',
@@ -81,7 +81,7 @@ BEGIN
-- phone_number_string,
-- '') <> ''
-- THEN
--- manufacturer_id := "fertiscan_0.0.18".new_organization_info_located(
+-- manufacturer_id := "fertiscan_0.1.1".new_organization_info_located(
-- input_json->'manufacturer'->>'name',
-- input_json->'manufacturer'->>'address',
-- input_json->'manufacturer'->>'website',
@@ -94,7 +94,7 @@ BEGIN
-- Manufacturer end
-- LABEL INFORMATION
- label_info_id := "fertiscan_0.0.18".new_label_information(
+ label_info_id := "fertiscan_0.1.1".new_label_information(
input_json->'product'->>'name',
input_json->'product'->>'lot_number',
input_json->'product'->>'npk',
@@ -124,11 +124,11 @@ BEGIN
'') <> ''
THEN
-- Insert the new weight
- weight_id = "fertiscan_0.0.18".new_metric_unit(
+ weight_id = "fertiscan_0.1.1".new_metric_unit(
read_value::float,
record->>'unit',
label_info_id,
- 'weight'::"fertiscan_0.0.18".metric_type,
+ 'weight'::"fertiscan_0.1.1".metric_type,
FALSE
);
END IF;
@@ -145,11 +145,11 @@ BEGIN
read_unit,
'') <> ''
THEN
- density_id := "fertiscan_0.0.18".new_metric_unit(
+ density_id := "fertiscan_0.1.1".new_metric_unit(
read_value::float,
read_unit,
label_info_id,
- 'density'::"fertiscan_0.0.18".metric_type,
+ 'density'::"fertiscan_0.1.1".metric_type,
FALSE
);
END IF;
@@ -168,11 +168,11 @@ BEGIN
'') <> ''
THEN
-- Insert the new volume
- volume_id := "fertiscan_0.0.18".new_metric_unit(
+ volume_id := "fertiscan_0.1.1".new_metric_unit(
value_float,
read_unit,
label_info_id,
- 'volume'::"fertiscan_0.0.18".metric_type,
+ 'volume'::"fertiscan_0.1.1".metric_type,
FALSE
);
END IF;
@@ -191,11 +191,11 @@ BEGIN
-- '') <> ''
-- THEN
-- -- Insert the new specification
--- specification_id := "fertiscan_0.0.18".new_specification(
+-- specification_id := "fertiscan_0.1.1".new_specification(
-- (record->>'humidity')::float,
-- (record->>'ph')::float,
-- (record->>'solubility')::float,
--- ingredient_language::"fertiscan_0.0.18".language,
+-- ingredient_language::"fertiscan_0.1.1".language,
-- label_info_id,
-- FALSE
-- );
@@ -221,12 +221,12 @@ BEGIN
'') <> ''
THEN
-- Insert the new ingredient
- ingredient_id := "fertiscan_0.0.18".new_ingredient(
+ ingredient_id := "fertiscan_0.1.1".new_ingredient(
record->>'name',
read_value::float,
read_unit,
label_info_id,
- ingredient_language::"fertiscan_0.0.18".language,
+ ingredient_language::"fertiscan_0.1.1".language,
NULL, --We cant tell atm
NULL, --We cant tell atm
FALSE --preset
@@ -265,7 +265,7 @@ BEGIN
en_value := en_values->>i;
-- Insert sub-label without deleting existing data
- sub_label_id := "fertiscan_0.0.18".new_sub_label(
+ sub_label_id := "fertiscan_0.1.1".new_sub_label(
fr_value,
en_value,
label_info_id,
@@ -289,12 +289,12 @@ BEGIN
-- '') <> ''
-- THEN
-- -- Insert the new Micronutrient
--- micronutrient_id := "fertiscan_0.0.18".new_micronutrient(
+-- micronutrient_id := "fertiscan_0.1.1".new_micronutrient(
-- record->> 'name',
-- (record->> 'value')::float,
-- record->> 'unit',
-- label_info_id,
--- micronutrient_language::"fertiscan_0.0.18".language
+-- micronutrient_language::"fertiscan_0.1.1".language
-- );
-- END IF;
-- END LOOP;
@@ -304,7 +304,7 @@ BEGIN
-- GUARANTEED
-- Loop through each language ('en' and 'fr')
- FOR guaranteed_analysis_language IN SELECT unnest(enum_range(NULL::"fertiscan_0.0.18".LANGUAGE))
+ FOR guaranteed_analysis_language IN SELECT unnest(enum_range(NULL::"fertiscan_0.1.1".LANGUAGE))
LOOP
FOR record IN SELECT * FROM jsonb_array_elements(input_json->'guaranteed_analysis'->guaranteed_analysis_language)
LOOP
@@ -315,12 +315,12 @@ BEGIN
'') <> ''
THEN
-- Insert the new guaranteed_analysis
- guaranteed_analysis_id := "fertiscan_0.0.18".new_guaranteed_analysis(
+ guaranteed_analysis_id := "fertiscan_0.1.1".new_guaranteed_analysis(
record->>'name',
(record->>'value')::float,
record->>'unit',
label_info_id,
- guaranteed_analysis_language::"fertiscan_0.0.18".language,
+ guaranteed_analysis_language::"fertiscan_0.1.1".language,
FALSE,
NULL -- We arent handeling element_id yet
);
@@ -339,7 +339,7 @@ BEGIN
'') <> ''
THEN
-- Insert the new registration number
- registration_number_id := "fertiscan_0.0.18".new_registration_number(
+ registration_number_id := "fertiscan_0.1.1".new_registration_number(
record->>'registration_number',
label_info_id,
(record->>'is_an_ingredient')::BOOLEAN,
@@ -364,7 +364,7 @@ BEGIN
'') <> ''
THEN
-- Insert the new organization info
- organization_id := "fertiscan_0.0.18".new_organization_information(
+ organization_id := "fertiscan_0.1.1".new_organization_information(
record->>'name',
record->>'address',
record->>'website',
@@ -389,24 +389,25 @@ BEGIN
-- ORGANIZATIONS INFO END
-- INSPECTION
- INSERT INTO "fertiscan_0.0.18".inspection (
- inspector_id, label_info_id, sample_id, picture_set_id, inspection_comment
+ INSERT INTO "fertiscan_0.1.1".inspection (
+ inspector_id, label_info_id, sample_id, picture_set_id, inspection_comment, container_id
) VALUES (
user_id, -- Assuming inspector_id is handled separately
label_info_id,
NULL, -- NOT handled yet
picture_set_id, -- Assuming picture_set_id is handled separately
- NULL
+ NULL,
+ (input_json ->> 'container_id')::UUID
)
RETURNING id INTO inspection_id_value;
-- Update input_json with inspection data
input_json := jsonb_set(input_json, '{inspection_id}', to_jsonb(inspection_id_value));
- input_json := jsonb_set(input_json, '{inspection_comment}', to_jsonb(''::text));
+ -- input_json := jsonb_set(input_json, '{inspection_comment}', to_jsonb(''::text));
-- TODO: remove olap transactions from Operational transactions
-- Update the Inspection_factual entry with the json
- UPDATE "fertiscan_0.0.18".inspection_factual
+ UPDATE "fertiscan_0.1.1".inspection_factual
SET original_dataset = input_json
WHERE inspection_factual."inspection_id" = inspection_id_value;
diff --git a/fertiscan/db/bytebase/schema_0.1.1.sql b/fertiscan/db/bytebase/schema_0.1.1.sql
new file mode 100644
index 00000000..3241b7fd
--- /dev/null
+++ b/fertiscan/db/bytebase/schema_0.1.1.sql
@@ -0,0 +1,437 @@
+
+
+CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
+
+ CREATE TABLE "fertiscan_0.1.1".roles (
+ "id" int PRIMARY KEY,
+ "name" text NOT NULL
+ );
+
+ CREATE TABLE "fertiscan_0.1.1".permission (
+ "id" int PRIMARY KEY,
+ "name" text NOT NULL
+ );
+
+ INSERT INTO "fertiscan_0.1.1".roles (id, name) VALUES
+ (1, 'dev'),
+ (2, 'admin'),
+ (3, 'team leader'),
+ (4, 'inspector');
+
+ INSERT INTO "fertiscan_0.1.1".permission (id, name) VALUES
+ (1, 'read'),
+ (2, 'write'),
+ (3, 'owner');
+
+
+ CREATE TABLE "fertiscan_0.1.1"."users" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_.uuid_generate_v4(),
+ "email" text NOT NULL UNIQUE,
+ "registration_date" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" timestamp,
+ "role_id" INT NOT NULL DEFAULT 4 REFERENCES "fertiscan_0.1.1".roles(id)
+ );
+
+ Create table "fertiscan_0.1.1"."groups" (
+ "id" uuid NOT NULL DEFAULT uuid_.uuid_generate_v4() PRIMARY KEY,
+ "name" text NOT NULL,
+ "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "created_by_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id)
+ );
+
+ Create table "fertiscan_0.1.1"."user_group" (
+ "id" uuid NOT NULL DEFAULT uuid_.uuid_generate_v4() PRIMARY KEY,
+ "user_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id) ON DELETE CASCADE,
+ "group_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".groups(id) ON DELETE CASCADE,
+ "updated_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "assigned_by_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id),
+ "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "permission_id" INT NOT NULL DEFAULT 1 REFERENCES "fertiscan_0.1.1".permission(id),
+ UNIQUE ("user_id", "group_id")
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."container" (
+ "id" uuid NOT NULL DEFAULT uuid_.uuid_generate_v4() PRIMARY KEY,
+ "name" text,
+ "is_public" boolean NOT NULL DEFAULT false,
+ "storage_prefix" text default 'user',
+ "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "created_by_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id) ON DELETE SET NULL,
+ "last_updated_by_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id)
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."container_user" (
+ "id" uuid NOT NULL DEFAULT uuid_.uuid_generate_v4() PRIMARY KEY,
+ "user_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id) ON DELETE cascade,
+ "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "created_by_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id) ON DELETE SET NULL,
+ "last_updated_by_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id) ON DELETE SET NULL,
+ "container_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".container(id) ON DELETE CASCADE,
+ "permission_id" INT NOT NULL DEFAULT 1 REFERENCES "fertiscan_0.1.1".permission(id),
+ UNIQUE ("user_id", "container_id")
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."container_group" (
+ "id" uuid NOT NULL DEFAULT uuid_.uuid_generate_v4() PRIMARY KEY,
+ "group_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".groups(id) ON DELETE cascade,
+ "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "created_by_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id) ON DELETE SET NULL,
+ "last_updated_by_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id) ON DELETE SET NULL,
+ "container_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".container(id) ON DELETE CASCADE,
+ "permission_id" INT NOT NULL DEFAULT 1 REFERENCES "fertiscan_0.1.1".permission(id),
+ UNIQUE ("group_id", "container_id")
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."picture_set" (
+ "id" uuid NOT NULL DEFAULT uuid_.uuid_generate_v4() PRIMARY KEY,
+ "picture_set" json NOT NULL,
+ "owner_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id),
+ "upload_date" date NOT NULL DEFAULT current_timestamp,
+ "name" text NOT NULL,
+ "container_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".container(id) ON DELETE CASCADE,
+ "parent_id" uuid REFERENCES "fertiscan_0.1.1".picture_set(id) ON DELETE CASCADE
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."picture" (
+ "id" uuid NOT NULL DEFAULT uuid_.uuid_generate_v4() PRIMARY KEY,
+ "picture" json NOT NULL,
+ "picture_set_id" uuid NOT null,
+ "nb_obj" integer NOT NULL,
+ "verified" boolean NOT NULL DEFAULT false,
+ "upload_date" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ FOREIGN KEY ("picture_set_id") REFERENCES "fertiscan_0.1.1"."picture_set"(id) ON DELETE CASCADE
+ );
+
+ -- CREATE A TYPE FOR FRENCH/ENGLISH LANGUAGE
+ CREATE TYPE "fertiscan_0.1.1".LANGUAGE AS ENUM ('fr', 'en');
+
+ CREATE TABLE "fertiscan_0.1.1"."province" (
+ "id" SERIAL PRIMARY KEY,
+ "name" text UNIQUE NOT NULL
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."region" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "province_id" int REFERENCES "fertiscan_0.1.1".province(id),
+ "name" text NOT NULL
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."unit" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "unit" text NOT NULL,
+ "to_si_unit" float
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."element_compound" (
+ "id" SERIAL PRIMARY KEY,
+ "number" int NOT NULL,
+ "name_fr" text NOT NULL,
+ "name_en" text NOT NULL,
+ "symbol" text NOT NULL UNIQUE
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."label_information" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "product_name" text,
+ "lot_number" text,
+ "npk" text,
+ "n" float,
+ "p" float,
+ "k" float,
+ "guaranteed_title_en" text,
+ "guaranteed_title_fr" text,
+ "title_is_minimal" boolean,
+ "record_keeping" boolean
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."label_dimension" (
+ "label_id" uuid PRIMARY KEY,
+ "organization_info_ids" uuid[] DEFAULT '{}',
+ "instructions_ids" uuid[] DEFAULT '{}',
+ "cautions_ids" uuid[] DEFAULT '{}',
+ "first_aid_ids" uuid[] DEFAULT '{}',
+ "warranties_ids" uuid[] DEFAULT '{}',
+ "specification_ids" uuid[] DEFAULT '{}',
+ "ingredient_ids" uuid[] DEFAULT '{}',
+ "micronutrient_ids" uuid[] DEFAULT '{}',
+ "guaranteed_ids" uuid[] DEFAULT '{}',
+ "registration_number_ids" uuid[] DEFAULT '{}',
+ "weight_ids" uuid[] DEFAULT '{}',
+ "volume_ids" uuid[] DEFAULT '{}',
+ "density_ids" uuid[] DEFAULT '{}'
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."time_dimension" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "date_value" date,
+ "year" int,
+ "month" int,
+ "day" int,
+ "month_name" text,
+ "day_name" text
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."inspection_factual" (
+ "inspection_id" uuid PRIMARY KEY,
+ "inspector_id" uuid ,
+ "label_info_id" uuid ,
+ "time_id" uuid REFERENCES "fertiscan_0.1.1".time_dimension(id),
+ "sample_id" uuid,
+ "picture_set_id" uuid,
+ "inspection_date" timestamp DEFAULT CURRENT_TIMESTAMP,
+ "original_dataset" json
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."organization_information" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "name" text,
+ "website" text,
+ "phone_number" text,
+ "address" text,
+ "edited" boolean DEFAULT false,
+ "label_id" uuid REFERENCES "fertiscan_0.1.1".label_information(id) ON DELETE CASCADE,
+ "is_main_contact" boolean DEFAULT false NOT NULL,
+ CONSTRAINT check_not_all_null CHECK (
+ (name IS NOT NULL)::integer +
+ (website IS NOT NULL)::integer +
+ (phone_number IS NOT NULL)::integer +
+ (address IS NOT NULL)::integer >= 1)
+ );
+
+
+ CREATE TABLE "fertiscan_0.1.1"."location" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "name" text,
+ "address" text NOT NULL,
+ "address_number" text,
+ "city" text,
+ "postal_code" text,
+ "region_id" uuid REFERENCES "fertiscan_0.1.1".region(id)
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."organization" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "name" text UNIQUE NOT NULL,
+ "website" text,
+ "phone_number" text,
+ "address" text,
+ "main_location_id" uuid REFERENCES "fertiscan_0.1.1".location(id),
+ "upload_date" timestamp DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" timestamp DEFAULT CURRENT_TIMESTAMP
+ );
+
+ Alter table "fertiscan_0.1.1".location ADD "organization_id" uuid REFERENCES "fertiscan_0.1.1".organization(id);
+
+ CREATE TABLE "fertiscan_0.1.1"."sample" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "number" uuid,
+ "collection_date" date,
+ "location" uuid REFERENCES "fertiscan_0.1.1".location(id)
+ );
+
+ CREATE TYPE "fertiscan_0.1.1".metric_type as ENUM ('volume', 'weight','density');
+
+ CREATE TABLE "fertiscan_0.1.1"."metric" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "value" float,
+ "edited" boolean,
+ "unit_id" uuid REFERENCES "fertiscan_0.1.1".unit(id),
+ "metric_type" "fertiscan_0.1.1".metric_type,
+ "label_id" uuid REFERENCES "fertiscan_0.1.1".label_information(id) ON DELETE CASCADE,
+ CONSTRAINT check_not_all_null CHECK (
+ (value IS NOT NULL)::integer +
+ (unit_id IS NOT NULL)::integer >= 1)
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."sub_type" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "type_fr" text Unique NOT NULL,
+ "type_en" text unique NOT NULL
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."registration_number_information" (
+ "id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "identifier" text NOT NULL,
+ "name" text,
+ "is_an_ingredient" BOOLEAN,
+ "label_id" uuid REFERENCES "fertiscan_0.1.1".label_information(id) ON DELETE CASCADE,
+ "edited" BOOLEAN DEFAULT FALSE
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."specification" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "humidity" float,
+ "ph" float,
+ "solubility" float,
+ "edited" boolean,
+ "label_id" uuid REFERENCES "fertiscan_0.1.1".label_information(id) ON DELETE CASCADE,
+ "language" "fertiscan_0.1.1".LANGUAGE
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."sub_label" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "text_content_fr" text NOT NULL DEFAULT '',
+ "text_content_en" text NOT NULL DEFAULT '',
+ "label_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1"."label_information" ("id") ON DELETE CASCADE,
+ "edited" boolean, --this is because with the current upsert we can not determine if it was edited or not
+ "sub_type_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1"."sub_type" ("id"),
+ CONSTRAINT check_not_all_null CHECK (
+ (COALESCE(sub_label.text_content_en, '') <> '') OR
+ (COALESCE(sub_label.text_content_fr, '') <> '')
+ )
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."micronutrient" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "read_name" text,
+ "value" float,
+ "unit" text ,
+ "element_id" int REFERENCES "fertiscan_0.1.1".element_compound(id),
+ "label_id" uuid REFERENCES "fertiscan_0.1.1".label_information(id) ON DELETE CASCADE,
+ "edited" boolean,
+ "language" "fertiscan_0.1.1".LANGUAGE
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."guaranteed" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "read_name" text,
+ "value" float ,
+ "unit" text ,
+ "language" "fertiscan_0.1.1".LANGUAGE,
+ "element_id" int REFERENCES "fertiscan_0.1.1".element_compound(id),
+ "label_id" uuid REFERENCES "fertiscan_0.1.1".label_information(id) ON DELETE CASCADE,
+ "edited" boolean,
+ CONSTRAINT check_not_all_null CHECK (
+ (read_name IS NOT NULL)::integer +
+ (value IS NOT NULL)::integer +
+ (unit IS NOT NULL)::integer >= 1)
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."ingredient" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "organic" boolean,
+ "active" boolean,
+ "name" text,
+ "value" float,
+ "unit" text,
+ "edited" boolean,
+ "label_id" uuid REFERENCES "fertiscan_0.1.1".label_information(id) ON DELETE CASCADE,
+ "language" "fertiscan_0.1.1".LANGUAGE
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."inspection" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "verified" boolean DEFAULT false,
+ "upload_date" timestamp DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" timestamp DEFAULT CURRENT_TIMESTAMP,
+ "inspector_id" uuid NOT NULL REFERENCES "fertiscan_0.1.1".users(id),
+ "label_info_id" uuid REFERENCES "fertiscan_0.1.1".label_information(id) ON DELETE CASCADE,
+ "sample_id" uuid REFERENCES "fertiscan_0.1.1".sample(id),
+ "container_id" uuid REFERENCES "fertiscan_0.1.1".container(id),
+ "picture_set_id" uuid REFERENCES "fertiscan_0.1.1".picture_set(id),
+ "inspection_comment" text,
+ "verified_date" timestamp default null
+ );
+
+ CREATE TABLE "fertiscan_0.1.1"."fertilizer" (
+ "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+ "name" text UNIQUE NOT NULL,
+ "registration_number" text,
+ "upload_date" timestamp DEFAULT CURRENT_TIMESTAMP,
+ "update_at" timestamp DEFAULT CURRENT_TIMESTAMP,
+ "latest_inspection_id" uuid REFERENCES "fertiscan_0.1.1".inspection(id) ON DELETE SET NULL,
+ "main_contact_id" uuid REFERENCES "fertiscan_0.1.1".organization(id) ON DELETE SET NULL
+ );-- It should actually try to seek if there are any other organization that can be found under the latest_inspection organisation_information instead of setting it to null
+
+ Alter table "fertiscan_0.1.1".inspection ADD "fertilizer_id" uuid REFERENCES "fertiscan_0.1.1".fertilizer(id);
+
+ -- Trigger function for the `user` table
+ CREATE OR REPLACE FUNCTION update_user_timestamp()
+ RETURNS TRIGGER AS $$
+ BEGIN
+ NEW.updated_at = CURRENT_TIMESTAMP;
+ RETURN NEW;
+ END;
+ $$ LANGUAGE plpgsql;
+
+ -- Trigger for the `user` table
+ CREATE TRIGGER user_update_before
+ BEFORE UPDATE ON "fertiscan_0.1.1".users
+ FOR EACH ROW
+ EXECUTE FUNCTION update_user_timestamp();
+
+ -- Trigger function for the `analysis` table
+ CREATE OR REPLACE FUNCTION update_analysis_timestamp()
+ RETURNS TRIGGER AS $$
+ BEGIN
+ NEW.updated_at = CURRENT_TIMESTAMP;
+ RETURN NEW;
+ END;
+ $$ LANGUAGE plpgsql;
+
+ -- Trigger for the `analysis` table
+ CREATE TRIGGER analysis_update_before
+ BEFORE UPDATE ON "fertiscan_0.1.1".inspection
+ FOR EACH ROW
+ EXECUTE FUNCTION update_analysis_timestamp();
+
+ -- Trigger function for the `fertilizer` table
+ CREATE OR REPLACE FUNCTION update_fertilizer_timestamp()
+ RETURNS TRIGGER AS $$
+ BEGIN
+ NEW.update_at = CURRENT_TIMESTAMP;
+ RETURN NEW;
+ END;
+ $$ LANGUAGE plpgsql;
+
+ -- Trigger for the `fertilizer` table
+ CREATE TRIGGER fertilizer_update_before
+ BEFORE UPDATE ON "fertiscan_0.1.1".fertilizer
+ FOR EACH ROW
+ EXECUTE FUNCTION update_fertilizer_timestamp();
+
+ -- Trigger function for the `organization` table
+ CREATE OR REPLACE FUNCTION update_organization_timestamp()
+ RETURNS TRIGGER AS $$
+ BEGIN
+ NEW.updated_at = CURRENT_TIMESTAMP;
+ RETURN NEW;
+ END;
+ $$ LANGUAGE plpgsql;
+
+ -- Trigger for the `organization` table
+ CREATE TRIGGER organization_update_before
+ BEFORE UPDATE ON "fertiscan_0.1.1".organization
+ FOR EACH ROW
+ EXECUTE FUNCTION update_organization_timestamp();
+
+ -- Trigger function for the `inspection` table
+ CREATE OR REPLACE FUNCTION update_inspection_original_dataset_protection()
+ RETURNS TRIGGER AS $$
+ BEGIN
+ IF (TG_OP = 'UPDATE') AND (OLD.original_dataset IS NULL) THEN
+ RETURN NEW;
+ ELSIF (TG_OP = 'UPDATE') AND (OLD.original_dataset IS NOT NULL) THEN
+ -- Protect the original dataset from being updated
+ NEW.original_dataset = OLD.original_dataset;
+ RETURN NEW;
+ END IF;
+ END;
+ $$ LANGUAGE plpgsql;
+
+ -- Trigger for the `inspection` table
+ CREATE TRIGGER inspection_update_protect_original_dataset
+ BEFORE UPDATE ON "fertiscan_0.1.1".inspection_factual
+ FOR EACH ROW
+ EXECUTE FUNCTION update_inspection_original_dataset_protection();
+
+ -- Insert the default types : [instruction, caution,first_aid, warranty]
+ INSERT INTO "fertiscan_0.1.1".sub_type(type_fr,type_en) VALUES
+ ('instructions','instructions'),
+ ('mises_en_garde','cautions');
+ -- ('premier_soin','first_aid'), -- We are not using this anymore
+ -- ('garanties','warranties'); -- we are not using this anymore
diff --git a/fertiscan/db/bytebase/update_inspection/update_registration_number.sql b/fertiscan/db/bytebase/update_inspection/update_registration_number.sql
index ff184794..2ef9ffc3 100644
--- a/fertiscan/db/bytebase/update_inspection/update_registration_number.sql
+++ b/fertiscan/db/bytebase/update_inspection/update_registration_number.sql
@@ -1,7 +1,7 @@
-drop FUNCTION IF EXISTS "fertiscan_0.0.18".update_registration_number;
+drop FUNCTION IF EXISTS "fertiscan_0.1.1".update_registration_number;
-- Function to update guaranteed analysis: delete old and insert new
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".update_registration_number(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".update_registration_number(
p_label_id uuid,
new_registration_numbers jsonb
)
diff --git a/fertiscan/db/bytebase/update_inspection/update_sub_label.sql b/fertiscan/db/bytebase/update_inspection/update_sub_label.sql
index 67606a0e..57b6db7a 100644
--- a/fertiscan/db/bytebase/update_inspection/update_sub_label.sql
+++ b/fertiscan/db/bytebase/update_inspection/update_sub_label.sql
@@ -1,7 +1,7 @@
-- Function to update sub labels: delete old and insert new
-Drop FUNCTION IF EXISTS "fertiscan_0.0.18".update_sub_labels(uuid, jsonb);
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".update_sub_labels(
+Drop FUNCTION IF EXISTS "fertiscan_0.1.1".update_sub_labels(uuid, jsonb);
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".update_sub_labels(
p_label_id uuid,
new_sub_labels jsonb
)
diff --git a/fertiscan/db/bytebase/update_inspection/upsert_organization.sql b/fertiscan/db/bytebase/update_inspection/upsert_organization.sql
index 5c737fbc..884abf88 100644
--- a/fertiscan/db/bytebase/update_inspection/upsert_organization.sql
+++ b/fertiscan/db/bytebase/update_inspection/upsert_organization.sql
@@ -1,6 +1,6 @@
-DROP FUNCTION IF EXISTS "fertiscan_0.0.18".upsert_organization();
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".upsert_organization(org_info_id uuid)
+DROP FUNCTION IF EXISTS "fertiscan_0.1.1".upsert_organization();
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".upsert_organization(org_info_id uuid)
RETURNS uuid
LANGUAGE plpgsql
AS $function$
diff --git a/fertiscan/db/bytebase/update_inspection/upsert_organization_info.sql b/fertiscan/db/bytebase/update_inspection/upsert_organization_info.sql
index fb941dea..abcb68d6 100644
--- a/fertiscan/db/bytebase/update_inspection/upsert_organization_info.sql
+++ b/fertiscan/db/bytebase/update_inspection/upsert_organization_info.sql
@@ -1,6 +1,6 @@
-- Function to upsert organization information
-DROP FUNCTION IF EXISTS "fertiscan_0.0.18".upsert_organization_info(jsonb, uuid);
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".upsert_organization_info(input_org_info jsonb, label_info_id uuid)
+DROP FUNCTION IF EXISTS "fertiscan_0.1.1".upsert_organization_info(jsonb, uuid);
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".upsert_organization_info(input_org_info jsonb, label_info_id uuid)
RETURNS jsonb AS $$
DECLARE
record jsonb;
diff --git a/fertiscan/db/bytebase/update_inspection_function.sql b/fertiscan/db/bytebase/update_inspection_function.sql
index 786eaad4..cbaf134c 100644
--- a/fertiscan/db/bytebase/update_inspection_function.sql
+++ b/fertiscan/db/bytebase/update_inspection_function.sql
@@ -1,7 +1,7 @@
-SET search_path TO "fertiscan_0.0.18";
+SET search_path TO "fertiscan_0.1.1";
-- Function to upsert location information based on location_id and address
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".upsert_location(location_id uuid, address text)
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".upsert_location(location_id uuid, address text)
RETURNS uuid AS $$
DECLARE
new_location_id uuid;
@@ -23,7 +23,7 @@ $$ LANGUAGE plpgsql;
-- Function to update metrics: delete old and insert new
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".update_metrics(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".update_metrics(
p_label_id uuid,
metrics jsonb
)
@@ -98,7 +98,7 @@ $$ LANGUAGE plpgsql;
-- Function to update specifications: delete old and insert new
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".update_specifications(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".update_specifications(
p_label_id uuid,
new_specifications jsonb
)
@@ -144,7 +144,7 @@ $$ LANGUAGE plpgsql;
-- Function to update ingredients: delete old and insert new
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".update_ingredients(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".update_ingredients(
p_label_id uuid,
new_ingredients jsonb
)
@@ -192,7 +192,7 @@ $$ LANGUAGE plpgsql;
-- Function to update micronutrients: delete old and insert new
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".update_micronutrients(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".update_micronutrients(
p_label_id uuid,
new_micronutrients jsonb
)
@@ -236,9 +236,9 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-drop FUNCTION IF EXISTS "fertiscan_0.0.18".update_guaranteed;
+drop FUNCTION IF EXISTS "fertiscan_0.1.1".update_guaranteed;
-- Function to update guaranteed analysis: delete old and insert new
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".update_guaranteed(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".update_guaranteed(
p_label_id uuid,
new_guaranteed jsonb
)
@@ -252,7 +252,7 @@ BEGIN
DELETE FROM guaranteed WHERE label_id = p_label_id;
-- Loop through each language ('en' and 'fr')
- FOR guaranteed_analysis_language IN SELECT unnest(enum_range(NULL::"fertiscan_0.0.18".LANGUAGE))
+ FOR guaranteed_analysis_language IN SELECT unnest(enum_range(NULL::"fertiscan_0.1.1".LANGUAGE))
LOOP
FOR guaranteed_record IN SELECT * FROM jsonb_array_elements(new_guaranteed->guaranteed_analysis_language)
LOOP
@@ -285,7 +285,7 @@ $$ LANGUAGE plpgsql;
-- Function to check if both text_content_fr and text_content_en are NULL or empty, and skip insertion if true
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".check_null_or_empty_sub_label()
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".check_null_or_empty_sub_label()
RETURNS TRIGGER AS $$
BEGIN
-- Check if both text_content_fr and text_content_en are NULL or empty
@@ -312,15 +312,15 @@ $$ LANGUAGE plpgsql;
-- Trigger to call check_null_or_empty_sub_label() before inserting into sub_label
-DROP TRIGGER IF EXISTS before_insert_sub_label ON "fertiscan_0.0.18".sub_label;
+DROP TRIGGER IF EXISTS before_insert_sub_label ON "fertiscan_0.1.1".sub_label;
CREATE TRIGGER before_insert_sub_label
-BEFORE INSERT ON "fertiscan_0.0.18".sub_label
+BEFORE INSERT ON "fertiscan_0.1.1".sub_label
FOR EACH ROW
-EXECUTE FUNCTION "fertiscan_0.0.18".check_null_or_empty_sub_label();
+EXECUTE FUNCTION "fertiscan_0.1.1".check_null_or_empty_sub_label();
-Drop FUNCTION IF EXISTS "fertiscan_0.0.18".upsert_inspection;
+Drop FUNCTION IF EXISTS "fertiscan_0.1.1".upsert_inspection;
-- Function to upsert inspection information
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".upsert_inspection(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".upsert_inspection(
p_inspection_id uuid,
p_label_info_id uuid,
p_inspector_id uuid,
@@ -370,7 +370,7 @@ $$ LANGUAGE plpgsql;
-- Function to upsert fertilizer information based on unique fertilizer name
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".upsert_fertilizer(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".upsert_fertilizer(
p_name text,
p_registration_number text,
p_owner_id uuid,
@@ -404,9 +404,9 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
-drop FUNCTION IF EXISTS "fertiscan_0.0.18".update_inspection;
+drop FUNCTION IF EXISTS "fertiscan_0.1.1".update_inspection;
-- Function to update inspection data and related entities, returning an updated JSON
-CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".update_inspection(
+CREATE OR REPLACE FUNCTION "fertiscan_0.1.1".update_inspection(
p_inspection_id uuid,
p_inspector_id uuid,
p_input_json jsonb
@@ -536,7 +536,7 @@ BEGIN
SELEct id into org_info_id from organization_information where label_id = label_info_id_value;
else
org_info_id := NULL;
- for org_record in select * from "fertiscan_0.0.18".organization_information where label_id = label_info_id_value
+ for org_record in select * from "fertiscan_0.1.1".organization_information where label_id = label_info_id_value
loop
if org_record.is_main_contact then
org_info_id := org_record.id;
diff --git a/fertiscan/db/metadata/inspection/__init__.py b/fertiscan/db/metadata/inspection/__init__.py
index 3b6dbccd..5b9a0cad 100644
--- a/fertiscan/db/metadata/inspection/__init__.py
+++ b/fertiscan/db/metadata/inspection/__init__.py
@@ -6,6 +6,7 @@
from datetime import datetime
from typing import List, Optional
+from uuid import UUID
from pydantic import UUID4, BaseModel, ValidationError, model_validator
@@ -37,7 +38,7 @@ def handle_none(cls, values):
class OrganizationInformation(ValidatedModel):
- id: Optional[str] = None
+ id: Optional[UUID4] = None
name: Optional[str] = None
address: Optional[str] = None
website: Optional[str] = None
@@ -95,7 +96,7 @@ class RegistrationNumber(ValidatedModel):
class ProductInformation(ValidatedModel):
name: str | None = None
- label_id: str | None = None
+ label_id: UUID4 | None = None
lot_number: str | None = None
metrics: Metrics | None = Metrics()
npk: str | None = None
@@ -135,8 +136,8 @@ class DBInspection(ValidatedModel):
class Inspection(ValidatedModel):
- inspection_id: Optional[str] = None
- inspector_id: Optional[str] = None
+ inspection_id: Optional[UUID4] = None
+ inspector_id: Optional[UUID4] = None
inspection_comment: Optional[str] = None
verified: Optional[bool] = False
organizations: Optional[List[OrganizationInformation]] = []
@@ -145,9 +146,14 @@ class Inspection(ValidatedModel):
instructions: SubLabel
guaranteed_analysis: GuaranteedAnalysis
ingredients: ValuesObjects
+ folder_id: UUID4
+ container_id: UUID4
+ upload_date: Optional[datetime] = None
+ updated_at: Optional[datetime] = None
+
-def build_inspection_import(analysis_form: dict, user_id) -> str:
+def build_inspection_import(analysis_form: dict, user_id:UUID,folder_id:UUID,container_id:UUID) -> Inspection:
"""
This funtion build an inspection json object from the pipeline of digitalization analysis.
This serves as the metadata for the inspection object in the database.
@@ -349,9 +355,13 @@ def build_inspection_import(analysis_form: dict, user_id) -> str:
guaranteed_analysis=guaranteed,
registration_numbers=reg_numbers,
ingredients=ingredients,
+ folder_id=folder_id,
+ container_id=container_id,
+ inspection_comment= None,
+ upload_date=None,
+ updated_at=None,
)
- Inspection(**inspection_formatted.model_dump())
- return inspection_formatted.model_dump_json()
+ return inspection_formatted
except MetadataError:
raise
except ValidationError as e:
@@ -360,7 +370,7 @@ def build_inspection_import(analysis_form: dict, user_id) -> str:
raise BuildInspectionImportError(f"Unexpected error: {e}") from e
-def build_inspection_export(cursor, inspection_id) -> str:
+def build_inspection_export(cursor, inspection_id) -> Inspection:
"""
This funtion build an inspection json object from the database.
"""
@@ -416,6 +426,12 @@ def build_inspection_export(cursor, inspection_id) -> str:
# Get the inspection information
db_inspection = inspection.get_inspection_dict(cursor, inspection_id)
db_inspection = DBInspection.model_validate(db_inspection)
+
+ inspection_fk = inspection.get_inspection_fk(
+ cursor=cursor,
+ inspection_id=inspection_id)
+ container_id = inspection_fk[3]
+ folder_id = inspection_fk[2]
inspection_formatted = Inspection(
inspection_id=str(inspection_id),
@@ -428,9 +444,12 @@ def build_inspection_export(cursor, inspection_id) -> str:
product=product_info,
verified=db_inspection.verified,
ingredients=ingredients,
+ folder_id=folder_id,
+ container_id=container_id,
+ upload_date=db_inspection.upload_date,
+ updated_at=db_inspection.updated_at,
)
-
- return inspection_formatted.model_dump_json()
+ return inspection_formatted
except QueryError as e:
raise BuildInspectionExportError(f"Error fetching data: {e}") from e
except Exception as e:
diff --git a/fertiscan/db/queries/errors.py b/fertiscan/db/queries/errors.py
index 392438a0..1225ae4e 100644
--- a/fertiscan/db/queries/errors.py
+++ b/fertiscan/db/queries/errors.py
@@ -3,6 +3,7 @@
Exception
|__QueryError
+ |__FertilizerQueryError
|__InspectionQueryError
|__LabelInformationQueryError
|__LabelDimensionQueryError
@@ -33,6 +34,16 @@ class QueryError(Exception):
pass
+class FertilizerQueryError(QueryError):
+ """Base exception for all fertilizer-related query errors."""
+
+ pass
+
+class FertilizerUpsertError(FertilizerQueryError):
+ """Raised when an error occurs during the upserting of a Fertilizer."""
+
+ pass
+
class InspectionQueryError(QueryError):
"""Base exception for all inspection-related query errors."""
@@ -605,6 +616,32 @@ class RegistrationNumberNotFoundError(RegistrationNumberQueryError):
pass
+class IngredientQueryError(QueryError):
+ """Base exception for all Ingredients related query error"""
+
+ pass
+
+class IngredientCreationError(IngredientQueryError):
+ """Raised when an error occurs during the creation of an Ingredient."""
+
+ pass
+
+class IngredientRetrievalError(IngredientQueryError):
+ """Raised when an error occurs during the retrieval of an Ingredient."""
+
+ pass
+
+class IngredientNotFoundError(IngredientQueryError):
+ """Raised when an Ingredient was not found."""
+
+ pass
+
+class IngredientDeleteError(IngredientQueryError):
+ """Raised when an error occurs during the delete of an Ingredient"""
+
+ pass
+
+
def handle_query_errors(error_cls=QueryError):
"""Decorator for handling query errors."""
diff --git a/fertiscan/db/queries/fertilizer/__init__.py b/fertiscan/db/queries/fertilizer/__init__.py
new file mode 100644
index 00000000..13e8f734
--- /dev/null
+++ b/fertiscan/db/queries/fertilizer/__init__.py
@@ -0,0 +1,178 @@
+
+
+from uuid import UUID
+from psycopg import Cursor
+from psycopg.rows import dict_row
+from psycopg.sql import SQL
+
+from datetime import date as Date
+
+from fertiscan.db.queries.errors import (
+ FertilizerUpsertError,
+ FertilizerQueryError,
+ handle_query_errors,
+)
+
+handle_query_errors(FertilizerUpsertError)
+def upsert_fertilizer(cursor: Cursor, name: str, reg_number:str, org_owner_id:UUID,latest_inspection_id: UUID):
+ """
+ This function Inserts data for a Fertilizer based on its name.
+ If a Fertilizer is already named as such we update the latest inspection FK.
+
+ Parameters:
+ cursor (Cursor):
+ name (str):
+ reg_number (str):
+ org_owner_id (UUID):
+ latest_inspection_id (UUID):
+
+ Returns:
+ - Fertilizer id (uuid)
+ """
+ query = """
+ INSERT INTO
+ fertilizer (
+ name,
+ registration_number,
+ upload_date,
+ update_at,
+ main_contact_id,
+ latest_inspection_id)
+ VALUES (
+ %s,
+ %s,
+ CURRENT_TIMESTAMP, -- Set upload date to current timestamp
+ CURRENT_TIMESTAMP, -- Set update date to current timestamp
+ %s,
+ %s
+ )
+ ON CONFLICT (name) DO UPDATE
+ SET
+ registration_number = EXCLUDED.registration_number,
+ update_at = CURRENT_TIMESTAMP, -- Update the update_at timestamp
+ main_contact_id = EXCLUDED.main_contact_id,
+ latest_inspection_id = EXCLUDED.latest_inspection_id
+ RETURNING id;
+ """
+ cursor.execute(query,(name,reg_number,org_owner_id,latest_inspection_id,))
+ return cursor.fetchone()[0]
+
+
+def search_fertilizer(cursor: Cursor, fertilizer_name:str, registration_number: str, lower_bound_date: Date, upper_bound_date: Date, lot_number:str, org_ids:list[UUID]):
+ """
+ Find all inspections where the organization is listed as main contact.
+
+ Parameters:
+ - cursor (Cursor): Database cursor
+ - org_ids (list[UUID]): List of organization IDs to search for
+
+ Returns:
+ - list: List of tuples containing inspection data
+ """
+ query = """
+ SELECT
+ i.id as inspection_id,
+ i.verified as verified,
+ i.upload_date as upload_date,
+ i.updated_at as last_updated_at,
+ i.inspector_id as inspector_id,
+ i.label_info_id as label_info_id,
+ i.container_id as container_id,
+ i.picture_set_id as foldeer_id,
+ i.inspection_comment as inspection_comment,
+ i.verified_date as verified_date,
+ f.id as fertilizer_id,
+ f.name as fertilizer_name,
+ f.registration_number as registration_number,
+ f.main_contact_id as organization,
+ o.name as organization_name,
+ o.phone_number as organization_phone_number,
+ o.address as organization_email,
+ l.lot_number as lot_number,
+ l.title_is_minimal as is_minimal_guaranteed_analysis,
+ l.record_keeping as is_record_keeping
+ FROM
+ fertilizer f
+ JOIN
+ inspection i ON f.latest_inspection_id = i.id
+ LEFT JOIN
+ organization o ON f.main_contact_id = o.id
+ LEFT JOIN
+ label_information l ON i.label_info_id = l.id
+ """
+ first = True
+ # check if all parameters are not none
+ if ((org_ids is None or len(org_ids) < 1) and
+ (fertilizer_name is None or fertilizer_name.strip() == "") and
+ (registration_number is None or registration_number.strip() == "") and
+ (lower_bound_date is None) and
+ (upper_bound_date is None) and
+ (lot_number is None or lot_number.strip() == "")
+ ):
+ raise FertilizerQueryError("No search parameters provided, please provide at least one search parameter.")
+ if org_ids is not None and len(org_ids) > 0:
+ query += "WHERE o.id = ANY(%s)"
+ if first:
+ first = False
+ if fertilizer_name is not None and fertilizer_name.strip() != "":
+ if first:
+ query += "WHERE "
+ else:
+ query += "AND "
+ query += "f.name = %s"
+ first = False
+ if registration_number is not None and registration_number.strip() != "":
+ if first:
+ query += "WHERE "
+ else:
+ query += "AND "
+ query += "f.registration_number = %s"
+ first = False
+ if lower_bound_date is not None:
+ if first:
+ query += "WHERE "
+ else:
+ query += "AND "
+ query += "DATE(i.upload_date) >= DATE(%s)"
+ first = False
+ if upper_bound_date is not None:
+ if first:
+ query += "WHERE "
+ else:
+ query += "AND "
+ query += "DATE(i.upload_date) <= DATE(%s)"
+ first = False
+ if lot_number is not None and lot_number.strip() != "":
+ if first:
+ query += "WHERE "
+ else:
+ query += "AND "
+ query += "l.lot_number = %s"
+ first = False
+
+ # Aggregate the Registration Numbers
+ query += """
+ GROUP BY
+ i.id,
+ i.verified,
+ i.upload_date,
+ i.updated_at,
+ i.inspector_id,
+ i.label_info_id,
+ i.container_id,
+ i.picture_set_id,
+ i.inspection_comment,
+ i.verified_date,
+ l.product_name,
+ o.id,
+ o.name,
+ o.phone_number,
+ o.address,
+ l.lot_number,
+ l.title_is_minimal,
+ l.record_keeping
+ """
+ query += ";"
+
+ cursor.execute(query, (org_ids,))
+ return cursor.fetchall()
diff --git a/fertiscan/db/queries/ingredient/__init__.py b/fertiscan/db/queries/ingredient/__init__.py
index 964cab4b..452b9a3a 100644
--- a/fertiscan/db/queries/ingredient/__init__.py
+++ b/fertiscan/db/queries/ingredient/__init__.py
@@ -1,22 +1,19 @@
from psycopg import Cursor, Error
+from uuid import UUID
"""
This module represent the function for the Ingredient table
"""
+from fertiscan.db.queries.errors import (
+ IngredientNotFoundError,
+ IngredientCreationError,
+ IngredientDeleteError,
+ IngredientQueryError,
+ handle_query_errors
+)
-class IngredientQueryError(Exception):
- pass
-
-
-class IngredientCreationError(IngredientQueryError):
- pass
-
-
-class IngredientRetrievalError(IngredientQueryError):
- pass
-
-
+handle_query_errors(IngredientCreationError)
def new_ingredient(
cursor: Cursor,
name: str,
@@ -31,41 +28,88 @@ def new_ingredient(
"""
This function creates a new ingredient in the database.
"""
- try:
- if language not in ["en", "fr"]:
- raise IngredientCreationError("Error: language must be either 'en' or 'fr'")
- query = """
- SELECT new_ingredient(%s, %s, %s, %s, %s, %s, %s, %s);
- """
- cursor.execute(
- query, (name, value, read_unit, label_id, language, organic, active, edited)
- )
- return cursor.fetchone()[0]
- except IngredientCreationError:
- raise
- except Error as db_error:
- raise IngredientCreationError(f"Database error: {db_error}") from db_error
- except Exception as e:
- raise IngredientCreationError(f"Unexpected error: {e}") from e
-
+ if language not in ["en", "fr"]:
+ raise IngredientCreationError("Error: language must be either 'en' or 'fr'")
+ if name is None and value is None and read_unit is None:
+ raise IngredientCreationError("Error: All minimal inputs [name,value,read_unit] are Null")
+ query = """
+ SELECT new_ingredient(%s, %s, %s, %s, %s, %s, %s, %s);
+ """
+ cursor.execute(
+ query, (name, value, read_unit, label_id, language, organic, active, edited)
+ )
+ return cursor.fetchone()[0]
+handle_query_errors(IngredientNotFoundError)
def get_ingredient_json(cursor: Cursor, label_id) -> dict:
"""
This function gets the ingredient JSON from the database.
"""
- try:
- query = """
- SELECT get_ingredients_json(%s);
- """
- cursor.execute(query, (label_id,))
- result = cursor.fetchone()
- if result is None:
- raise IngredientRetrievalError("Error: ingredient not found")
- return result[0]
+ query = """
+ SELECT get_ingredients_json(%s);
+ """
+ cursor.execute(query, (label_id,))
+ result = cursor.fetchone()
+ if result is None:
+ raise IngredientNotFoundError("Error: ingredient not found")
+ return result[0]
+
+handle_query_errors(IngredientNotFoundError)
+def get_ingredient_label(cursor:Cursor,label_id:UUID):
+ """
+ This function gets the ingredient JSON from the database.
+ """
+ query = """
+ SELECT
+ id,
+ name,
+ value,
+ unit,
+ edited,
+ organic,
+ active,
+ language
+ FROM
+ ingredient
+ WHERE
+ label_id = %s;
+ """
+ cursor.execute(query, (label_id,))
+ result = cursor.fetchall()
+ return result
+
+handle_query_errors(IngredientDeleteError)
+def delete_ingredient_label(cursor:Cursor, label_id:UUID):
+ query = """
+ DELETE FROM ingredient
+ WHERE label_id = %s
+ RETURNING id;
+ """
+ cursor.execute(query, (label_id,))
+ return cursor.rowcount
- except IngredientRetrievalError:
- raise
- except Error as db_error:
- raise IngredientCreationError(f"Database error: {db_error}") from db_error
- except Exception as e:
- raise IngredientCreationError(f"Unexpected error: {e}") from e
+handle_query_errors(IngredientQueryError)
+def upsert_ingredient(cursor: Cursor,label_id:UUID,ingredients:dict):
+ delete_ingredient_label(cursor=cursor,label_id=label_id)
+ for ingredient_en in ingredients["en"]:
+ new_ingredient(
+ cursor=cursor,
+ name=ingredient_en["name"],
+ value=ingredient_en["value"],
+ read_unit=ingredient_en["unit"],
+ label_id=label_id,
+ language="en",
+ organic=None,
+ active=None,
+ edited=True)
+ for ingredient_fr in ingredients["fr"]:
+ new_ingredient(
+ cursor=cursor,
+ name=ingredient_fr["name"],
+ value=ingredient_fr["value"],
+ read_unit=ingredient_fr["unit"],
+ label_id=label_id,
+ language="fr",
+ organic=None,
+ active=None,
+ edited=True)
diff --git a/fertiscan/db/queries/inspection/__init__.py b/fertiscan/db/queries/inspection/__init__.py
index 9527a723..6f400b61 100644
--- a/fertiscan/db/queries/inspection/__init__.py
+++ b/fertiscan/db/queries/inspection/__init__.py
@@ -5,6 +5,7 @@
import json
from uuid import UUID
+from datetime import datetime
from psycopg import Cursor
from psycopg.rows import dict_row
@@ -22,7 +23,9 @@
@handle_query_errors(InspectionCreationError)
-def new_inspection(cursor: Cursor, user_id, picture_set_id, verified=False):
+def new_inspection(
+ cursor: Cursor, user_id, picture_set_id, label_id, container_id, verified=False
+) -> tuple[UUID, datetime]:
"""
This function uploads a new inspection to the database.
@@ -40,19 +43,33 @@ def new_inspection(cursor: Cursor, user_id, picture_set_id, verified=False):
INSERT INTO inspection (
inspector_id,
picture_set_id,
- verified
+ verified,
+ label_info_id,
+ container_id
)
VALUES
- (%s, %s, %s)
+ (%s, %s, %s,%s,%s)
RETURNING
- id
+ id, upload_date;
"""
- cursor.execute(query, (user_id, picture_set_id, verified))
+ cursor.execute(query, (user_id, picture_set_id, verified, label_id, container_id))
if result := cursor.fetchone():
- return result[0]
+ return result
raise InspectionCreationError("Failed to create inspection. No data returned.")
+def save_inspection_original_dataset(cursor: Cursor, inspection_id: UUID, og_data):
+ query = """
+ UPDATE
+ "fertiscan_0.1.1".inspection_factual
+ SET
+ original_dataset = %s
+ WHERE
+ inspection_factual."inspection_id" = %s;
+ """
+ cursor.execute(query, (og_data, inspection_id))
+
+
@handle_query_errors(InspectionCreationError)
def new_inspection_with_label_info(cursor: Cursor, user_id, picture_set_id, label_json):
"""
@@ -234,8 +251,7 @@ def get_inspection_fk(cursor: Cursor, inspection_id):
label_info_id,
inspector_id,
picture_set_id,
- company_info_id,
- manufacturer_info_id,
+ container_id,
fertilizer_id,
sample_id
]
@@ -246,14 +262,11 @@ def get_inspection_fk(cursor: Cursor, inspection_id):
inspection.label_info_id,
inspection.inspector_id,
inspection.picture_set_id,
+ inspection.container_id,
inspection.fertilizer_id,
inspection.sample_id
FROM
inspection
- LEFT JOIN
- label_information as label_info
- ON
- inspection.label_info_id = label_info.id
WHERE
inspection.id = %s
"""
@@ -369,12 +382,43 @@ def get_all_organization_inspection(cursor: Cursor, org_id):
return cursor.fetchall()
-@handle_query_errors(InspectionUpdateError)
def update_inspection(
- cursor: Cursor,
- inspection_id: str | UUID,
- user_id: str | UUID,
- updated_data_dict: dict,
+ cursor: Cursor, inspection_id: str | UUID, verified: bool, inspection_comment: str
+) -> datetime:
+ if verified:
+ query = """
+ UPDATE
+ inspection
+ SET
+ verified = %s,
+ updated_at = CURRENT_TIMESTAMP,
+ inspection_comment = %s,
+ verified_date = CURRENT_TIMESTAMP
+ WHERE
+ id = %s
+ RETURNING
+ updated_at;
+ """
+ else:
+ query = """
+ UPDATE
+ inspection
+ SET
+ verified = %s,
+ updated_at = CURRENT_TIMESTAMP,
+ inspection_comment = %s
+ WHERE
+ id = %s
+ RETURNING
+ updated_at;
+ """
+ cursor.execute(query, (verified, inspection_comment, inspection_id))
+ return cursor.fetchone()[0]
+
+
+@handle_query_errors(InspectionUpdateError)
+def update_inspection_function(
+ cursor: Cursor, inspection_id: str | UUID, user_id: str | UUID, updated_data_dict
) -> dict:
"""
Update inspection data in the database.
@@ -393,7 +437,7 @@ def update_inspection(
"""
# Prepare and execute the SQL function call
query = SQL("SELECT update_inspection(%s, %s, %s)")
- cursor.execute(query, (inspection_id, user_id, json.dumps(updated_data_dict)))
+ cursor.execute(query, (inspection_id, user_id, updated_data_dict))
if result := cursor.fetchone():
return result[0]
@@ -459,3 +503,145 @@ def get_inspection_factual(cursor: Cursor, inspection_id):
"""
cursor.execute(query, (inspection_id,))
return cursor.fetchone()
+
+
+def search_inspection(
+ cursor: Cursor,
+ fertilizer_name: str,
+ lower_bound_date: Date,
+ upper_bound_date: Date,
+ lot_number: str,
+ label_ids: list[UUID],
+) -> list:
+ """
+ Find all inspections where the organization is listed as main contact.
+
+ Parameters:
+ - cursor (Cursor): Database cursor
+ - fertilizer_name (str): The name of the fertilizer
+ - lower_bound_date (Date): The lower bound date of the inspection
+ - upper_bound_date (Date): The upper bound date of the inspection
+ - lot_number (str): The lot number of the fertilizer
+ - label_ids (list[UUID]): The list of label IDs to search also search for regarless of other parameters
+
+ Returns:
+ - list: List of tuples containing inspection data
+ """
+ query = """
+ SELECT
+ i.id as inspection_id,
+ i.verified as verified,
+ i.upload_date as upload_date,
+ i.updated_at as last_updated_at,
+ i.inspector_id as inspector_id,
+ i.label_info_id as label_info_id,
+ i.container_id as container_id,
+ i.picture_set_id as folder_id,
+ i.inspection_comment as inspection_comment,
+ i.verified_date as verified_date,
+ l.product_name as fertilizer_name,
+ o.id as organization_info_id,
+ o.name as organization_name,
+ o.phone_number as organization_phone_number,
+ o.address as organization_address,
+ l.lot_number as lot_number,
+ l.title_is_minimal as is_minimal_guaranteed_analysis,
+ l.record_keeping as is_record_keeping,
+ array_agg(r.identifier) as registration_numbers
+ FROM
+ inspection i
+ JOIN
+ label_information l ON i.label_info_id = l.id
+ LEFT JOIN
+ organization_information o ON l.id = o.label_id AND o.is_main_contact = TRUE
+ LEFT JOIN
+ registration_number_information r ON l.id = r.label_id
+ """
+ first = True
+ params = ()
+ # check if all parameters are not none
+ if (
+ (fertilizer_name is None or fertilizer_name.strip() == "")
+ and (lower_bound_date is None)
+ and (upper_bound_date is None)
+ and (lot_number is None or lot_number.strip() == "")
+ and (label_ids is None or len(label_ids) < 1)
+ ):
+ raise InspectionQueryError(
+ "No search parameters provided, please provide at least one search parameter."
+ )
+ # Check if the dates are valid
+ if lower_bound_date is not None and upper_bound_date is not None:
+ if lower_bound_date > upper_bound_date:
+ raise InspectionQueryError(
+ "The lower bound date is greater than the upper bound date."
+ )
+
+ if fertilizer_name is not None and fertilizer_name.strip() != "":
+ if first:
+ query += "WHERE "
+ else:
+ query += "AND "
+ query += "l.product_name = %s "
+ first = False
+ params += (fertilizer_name,)
+ if lower_bound_date is not None:
+ if first:
+ query += "WHERE "
+ else:
+ query += "AND "
+ query += "DATE(i.upload_date) >= DATE(%s) "
+ first = False
+ params += (lower_bound_date,)
+ if upper_bound_date is not None:
+ if first:
+ query += "WHERE "
+ else:
+ query += "AND "
+ query += "DATE(i.upload_date) <= DATE(%s) "
+ first = False
+ # Make sure upper_bound_date time is 23:59:59 to include the whole day
+ upper_bound_date = upper_bound_date.replace(hour=23, minute=59, second=59)
+ params += (upper_bound_date,)
+ if lot_number is not None and lot_number.strip() != "":
+ if first:
+ query += "WHERE "
+ else:
+ query += "AND "
+ query += "l.lot_number = %s "
+ first = False
+ params += (lot_number,)
+ if label_ids is not None and len(label_ids) > 0:
+ if first:
+ query += "WHERE " # This is a list for previous conditions that were met
+ else:
+ query += "OR "
+ query += "l.id = ANY(%s) "
+ first = False
+ params += (label_ids,)
+
+ # Aggregate the Registration Numbers
+ query += """
+ GROUP BY
+ i.id,
+ i.verified,
+ i.upload_date,
+ i.updated_at,
+ i.inspector_id,
+ i.label_info_id,
+ i.container_id,
+ i.picture_set_id,
+ i.inspection_comment,
+ i.verified_date,
+ l.product_name,
+ o.id,
+ o.name,
+ o.phone_number,
+ o.address,
+ l.lot_number,
+ l.title_is_minimal,
+ l.record_keeping
+ """
+ query += ";"
+ cursor.execute(query, params)
+ return cursor.fetchall()
diff --git a/fertiscan/db/queries/label/__init__.py b/fertiscan/db/queries/label/__init__.py
index 8d872927..06234f2f 100644
--- a/fertiscan/db/queries/label/__init__.py
+++ b/fertiscan/db/queries/label/__init__.py
@@ -4,6 +4,8 @@
from psycopg import Cursor
+from uuid import UUID
+
from fertiscan.db.queries.errors import (
LabelDimensionNotFoundError,
LabelDimensionQueryError,
@@ -47,7 +49,31 @@ def new_label_information(
- str: The UUID of the label_information
"""
query = """
- SELECT new_label_information(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);
+ INSERT INTO
+ label_information (
+ product_name,
+ lot_number,
+ npk,
+ n,
+ p,
+ k,
+ guaranteed_title_en,
+ guaranteed_title_fr,
+ title_is_minimal,
+ record_keeping
+ ) VALUES (
+ %s,
+ %s,
+ %s,
+ %s,
+ %s,
+ %s,
+ %s,
+ %s,
+ %s,
+ %s
+ )
+ RETURNING id;
"""
cursor.execute(
query,
@@ -71,11 +97,61 @@ def new_label_information(
)
-def new_label_information_complete(
- cursor, lot_number, npk, registration_number, n, p, k, weight, density, volume
+@handle_query_errors(LabelInformationCreationError)
+def new_label_information_function(
+ cursor,
+ name: str,
+ lot_number: str,
+ npk: str,
+ n: float,
+ p: float,
+ k: float,
+ title_en: str,
+ title_fr: str,
+ is_minimal: bool,
+ record_keeping: bool,
):
- ##TODO: Implement this function
- return None
+ """
+ This function create a new label_information in the database.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - lot_number (str): The lot number of the label_information.
+ - npk (str): The npk of the label_information.
+ - n (float): The n of the label_information.
+ - p (float): The p of the label_information.
+ - k (float): The k of the label_information.
+ - title_en (str): The english title of the guaranteed analysis.
+ - title_fr (str): The french title of the guaranteed analysis.
+ - is_minimal (bool): if the tital is minimal for the guaranteed analysis.
+ - record_keeping (bool): if the label is a record keeping.
+
+ Returns:
+ - str: The UUID of the label_information
+ """
+ query = """
+ SELECT new_label_information(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);
+ """
+ cursor.execute(
+ query,
+ (
+ name,
+ lot_number,
+ npk,
+ n,
+ p,
+ k,
+ title_en,
+ title_fr,
+ is_minimal,
+ record_keeping,
+ ),
+ )
+ if result := cursor.fetchone():
+ return result[0]
+ raise LabelInformationCreationError(
+ "Failed to create label information. No data returned."
+ )
@handle_query_errors(LabelInformationRetrievalError)
@@ -196,3 +272,75 @@ def delete_label_info(cursor: Cursor, label_id: str):
"""
cursor.execute(query, (label_id,))
return cursor.rowcount
+
+
+@handle_query_errors(LabelInformationCreationError)
+def update_label_info(
+ cursor: Cursor,
+ label_id: str,
+ name: str | None = None,
+ lot_number: str | None = None,
+ npk: str | None = None,
+ n: float | None = None,
+ p: float | None = None,
+ k: float | None = None,
+ title_en: str | None = None,
+ title_fr: str | None = None,
+ is_minimal: bool | None = None,
+ record_keeping: bool | None = None,
+) -> dict:
+ """
+ Updates an existing label_information record in the database.
+
+ Parameters:
+ - cursor (Cursor): The database cursor
+ - label_id (str): UUID of the label to update
+ - name (str, optional): Product name
+ - lot_number (str, optional): Lot number
+ - npk (str, optional): NPK value
+ - n (float, optional): Nitrogen value
+ - p (float, optional): Phosphorus value
+ - k (float, optional): Potassium value
+ - title_en (str, optional): English title
+ - title_fr (str, optional): French title
+ - is_minimal (bool, optional): Minimal title flag
+ - record_keeping (bool, optional): Record keeping flag
+
+ Returns:
+ - dict: Updated label information
+
+ Raises:
+ - LabelInformationCreationError: If update fails
+ """
+ query = """
+ UPDATE
+ label_information
+ SET
+ product_name = %s,
+ lot_number = %s,
+ npk = %s,
+ n = %s,
+ p = %s,
+ k = %s,
+ guaranteed_title_en = %s,
+ guaranteed_title_fr = %s,
+ title_is_minimal = %s,
+ record_keeping = %s
+ WHERE id = %s;
+ """
+ cursor.execute(
+ query,
+ (
+ name,
+ lot_number,
+ npk,
+ n,
+ p,
+ k,
+ title_en,
+ title_fr,
+ is_minimal,
+ record_keeping,
+ label_id,
+ ),
+ )
diff --git a/fertiscan/db/queries/metric/__init__.py b/fertiscan/db/queries/metric/__init__.py
index e951e0a6..112dcb1b 100644
--- a/fertiscan/db/queries/metric/__init__.py
+++ b/fertiscan/db/queries/metric/__init__.py
@@ -4,11 +4,14 @@
"""
from psycopg import Cursor
+from uuid import UUID
from fertiscan.db.queries.errors import (
MetricCreationError,
MetricQueryError,
MetricRetrievalError,
+ MetricUpdateError,
+ MetricDeleteError,
UnitCreationError,
UnitQueryError,
handle_query_errors,
@@ -285,3 +288,82 @@ def get_unit_id(cursor: Cursor, unit):
if result := cursor.fetchone():
return result[0]
raise UnitQueryError("Failed to retrieve unit id. No data returned.")
+
+@handle_query_errors(MetricDeleteError)
+def delete_metric_by_type(cursor:Cursor, label_id:UUID, metric_type:str)->int:
+ """
+ This function deletes a metric from the database based on label_id and metric_type.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - label_id (UUID): The UUID of the label.
+ - metric_type (str): The type of the metric.
+
+ Returns:
+ - number of deleted rows. (int)
+ """
+ query = """
+ DELETE FROM
+ metric
+ WHERE
+ label_id = %s AND
+ metric_type = %s
+ RETURNING ID;
+ """
+ cursor.execute(query, (label_id, metric_type))
+ return cursor.rowcount
+
+@handle_query_errors(MetricDeleteError)
+def delete_metric(cursor:Cursor, label_id:UUID)->int:
+ """
+ This function deletes a metric from the database based on label_id and metric_type.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - label_id (UUID): The UUID of the label.
+
+ Returns:
+ - number of deleted rows. (int)
+ """
+ rowcount=0
+ for type in ["density", "weight", "volume"]:
+ rowcount += delete_metric_by_type(
+ cursor=cursor,
+ label_id=label_id,
+ metric_type=type
+ )
+ return rowcount
+
+@handle_query_errors(MetricUpdateError)
+def upsert_metric(cursor: Cursor, label_id:UUID,metrics:dict):
+ delete_metric(cursor=cursor,label_id=label_id)
+
+ # Weight
+ for record in metrics["weight"]:
+ new_metric(
+ cursor=cursor,
+ value= record["value"],
+ read_unit=record["unit"],
+ label_id=label_id,
+ metric_type='weight',
+ edited=record["edited"]
+ )
+ # Density
+ new_metric(
+ cursor=cursor,
+ value= metrics["density"]["value"],
+ read_unit=metrics["density"]["unit"],
+ label_id=label_id,
+ metric_type='density',
+ edited=metrics["density"]["edited"]
+ )
+ # Volume
+ new_metric(
+ cursor=cursor,
+ value= metrics["volume"]["value"],
+ read_unit=metrics["volume"]["unit"],
+ label_id=label_id,
+ metric_type='volume',
+ edited=metrics["volume"]["edited"]
+ )
+
diff --git a/fertiscan/db/queries/nutrients/__init__.py b/fertiscan/db/queries/nutrients/__init__.py
index 723d6b84..64dea36a 100644
--- a/fertiscan/db/queries/nutrients/__init__.py
+++ b/fertiscan/db/queries/nutrients/__init__.py
@@ -4,6 +4,7 @@
"""
from psycopg import Cursor
+from uuid import UUID
from fertiscan.db.queries.errors import (
ElementCompoundCreationError,
@@ -11,6 +12,8 @@
ElementCompoundQueryError,
GuaranteedAnalysisCreationError,
GuaranteedAnalysisRetrievalError,
+ GuaranteedAnalysisDeleteError,
+ GuaranteedAnalysisUpdateError,
MicronutrientCreationError,
MicronutrientRetrievalError,
handle_query_errors,
@@ -288,9 +291,70 @@ def get_all_micronutrients(cursor: Cursor, label_id):
cursor.execute(query, (label_id,))
return cursor.fetchall()
+def new_guaranteed_analysis(
+ cursor: Cursor,
+ read_name,
+ value,
+ unit,
+ label_id,
+ language: str,
+ element_id: int = None,
+ edited: bool = False,
+):
+ """
+ This function add a new guaranteed in the database.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - read_name (str): The name of the guaranteed.
+ - value (float): The value of the guaranteed.
+ - unit (str): The unit of the guaranteed.
+ - element_id (int): The element of the guaranteed.
+ - label_id (str): The label of the guaranteed.
+
+ Returns:
+ - str: The UUID of the guaranteed.
+ """
+ if language.lower() not in ["fr", "en"]:
+ raise GuaranteedAnalysisCreationError("Language not supported")
+ if (
+ (read_name is None or read_name == "")
+ and (value is None or value == "")
+ and (unit is None or unit == "")
+ ):
+ raise GuaranteedAnalysisCreationError("Read name and value cannot be empty")
+ query = """
+ INSERT INTO guaranteed (
+ read_name,
+ value,
+ unit,
+ edited,
+ label_id,
+ element_id,
+ language)
+ VALUES (
+ %s,
+ %s,
+ %s,
+ %s,
+ %s,
+ %s,
+ %s
+ )
+ RETURNING id;
+ """
+ cursor.execute(
+ query, (read_name, value, unit, edited,label_id, element_id, language)
+ )
+ if result := cursor.fetchone():
+ return result[0]
+ raise GuaranteedAnalysisCreationError(
+ "Failed to create guaranteed analysis. No data returned."
+ )
+
@handle_query_errors(GuaranteedAnalysisCreationError)
-def new_guaranteed_analysis(
+def new_guaranteed_analysis_function(
cursor: Cursor,
read_name,
value,
@@ -392,6 +456,64 @@ def get_guaranteed_analysis_json(cursor: Cursor, label_id) -> dict:
"Failed to retrieve guaranteed analysis json. No data returned for: "
+ str(label_id)
)
+@handle_query_errors(GuaranteedAnalysisDeleteError)
+def delete_guaranteed_analysis(cursor:Cursor, label_id:UUID):
+ """
+ This function deletes guaranteed analysis records from the database.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - label_id (UUID): The UUID of the label.
+
+ Returns:
+ - int: The number of rows deleted.
+ """
+ query = """
+ DELETE FROM guaranteed
+ WHERE label_id = %s
+ RETURNING id;
+ """
+ cursor.execute(query, (label_id,))
+ return cursor.rowcount
+
+@handle_query_errors(GuaranteedAnalysisUpdateError)
+def upsert_guaranteed_analysis(cursor:Cursor,label_id: UUID, GA:dict):
+ """
+ Replaces all entries for a label by deleting existing ones and inserting new ones.
+
+ Parameters:
+ - cursor: Database cursor
+ - label_id: UUID of the label to update
+ - GA: Dictionary containing the new values to insert
+ """
+ delete_guaranteed_analysis(
+ cursor=cursor,
+ label_id= label_id,
+ )
+
+ for record in GA["en"]:
+ new_guaranteed_analysis(
+ cursor=cursor,
+ read_name=record["name"],
+ value=record["value"],
+ unit = record["unit"],
+ label_id=label_id,
+ language="en",
+ element_id=None,
+ edited= True
+ )
+ for record in GA["fr"]:
+ new_guaranteed_analysis(
+ cursor=cursor,
+ read_name=record["name"],
+ value=record["value"],
+ unit = record["unit"],
+ label_id=label_id,
+ language="fr",
+ element_id=None,
+ edited= True
+ )
+
@handle_query_errors(GuaranteedAnalysisRetrievalError)
@@ -461,3 +583,32 @@ def get_all_guaranteeds(cursor: Cursor, label_id):
"""
cursor.execute(query, (label_id,))
return cursor.fetchall()
+
+@handle_query_errors(GuaranteedAnalysisRetrievalError)
+def get_guaranteed_by_label(cursor:Cursor,label_id:UUID):
+ """
+ This function get all the guaranteed in the database.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - label_id (str): The UUID of the label.
+
+ Returns:
+ - str: The UUID of the guaranteed.
+ """
+
+ query = """
+ SELECT
+ g.id,
+ g.read_name,
+ g.value,
+ g.unit,
+ g.edited,
+ CONCAT(CAST(g.read_name AS TEXT),' ',g.value,' ', g.unit) AS reading
+ FROM
+ guaranteed g
+ WHERE
+ g.label_id = %s;
+ """
+ cursor.execute(query, (label_id,))
+ return cursor.fetchall()
diff --git a/fertiscan/db/queries/organization/__init__.py b/fertiscan/db/queries/organization/__init__.py
index 60b5f63a..af72501d 100644
--- a/fertiscan/db/queries/organization/__init__.py
+++ b/fertiscan/db/queries/organization/__init__.py
@@ -61,8 +61,126 @@ def new_organization(cursor: Cursor, name, website, phone_number, address):
raise OrganizationCreationError("Failed to create Organization. No data returned.")
+def upsert_organization(cursor: Cursor, name:str, website:str, phone_number: str, address:str):
+ """
+ This function serves as an upsert when an organization is verified through an inspection
+ Therefor, we are looking for similar organizations with the same naming scheme to update their information or we insert a new Organization
+
+ Parameters:
+ - cursor (Cursor): The database cursor to execute queries.
+ - name (str): The name of the organization.
+ - website (str): The website of the organization.
+ - phone_number (str): The phone number of the organization.
+ - address (str): The address of the organization.
+ Returns:
+ - None
+
+ """
+ query ="""
+ Select
+ "id"
+ FROM
+ organization
+ WHERE
+ name
+ ILIKE %s;
+ """
+ cursor.execute(query, (name,))
+ res = cursor.fetchone()
+ if res is None or res[0] is None:
+ id =new_organization(
+ cursor=cursor,
+ name=name,
+ website=website,
+ phone_number=phone_number,
+ address=address,
+ )
+ else:
+ id = res[0]
+ query = """
+ UPDATE
+ organization
+ SET
+ "website" = %s,
+ "phone_number" = %s,
+ "address" = %s,
+ "main_location_id" = Null
+ WHERE id = %s;
+ """
+ cursor.execute(query,(website,phone_number,address,id))
+ return id
+
@handle_query_errors(OrganizationInformationCreationError)
def new_organization_information(
+
+ cursor: Cursor,
+ address: str,
+ name: str,
+ website: str,
+ phone_number: str,
+ label_id: UUID,
+ edited: bool = False,
+ is_main_contact: bool = False,
+):
+ """
+ This function create a new organization information in the database using function.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - name (str): The name of the organization.
+ - website (str): The website of the organization.
+ - phone_number (str): The phone number of the organization.
+ - label_id (str): The UUID of the label.
+ - edited (bool): The edited status of the organization information.
+ - is_main_contact (bool): The main contact status of the organization information.
+
+ Returns:
+ - str: The UUID of the organization information
+ """
+ if label_id is None:
+ raise OrganizationInformationCreationError(
+ "Label ID is required for organization information creation."
+ )
+ query = """
+ INSERT INTO
+ organization_information (
+ "name",
+ "address",
+ "website",
+ "phone_number",
+ "edited",
+ "label_id",
+ "is_main_contact"
+ )
+ VALUES (
+ %s,
+ %s,
+ %s,
+ %s,
+ %s,
+ %s,
+ %s
+ )
+ RETURNING id;
+ """
+ cursor.execute(
+ query,
+ (
+ name,
+ address,
+ website,
+ phone_number,
+ edited,
+ label_id,
+ is_main_contact,
+ ),
+ )
+ if result := cursor.fetchone():
+ return result[0]
+ raise OrganizationCreationError("Failed to create Organization. No data returned.")
+
+@handle_query_errors(OrganizationInformationCreationError)
+def new_organization_information_function(
cursor: Cursor,
address: str,
name: str,
@@ -232,7 +350,13 @@ def get_organization_json(cursor: Cursor, fertilizer_id: UUID) -> dict:
@handle_query_errors(OrganizationInformationUpdateError)
def update_organization_info(
- cursor: Cursor, information_id: UUID, name, website, phone_number
+ cursor: Cursor,
+ information_id: UUID,
+ name:str,
+ website:str,
+ phone_number:str,
+ address:str,
+ is_main_contact:bool
):
"""
This function update a organization information in the database.
@@ -253,7 +377,9 @@ def update_organization_info(
SET
name = COALESCE(%s,name),
website = COALESCE(%s,website),
- phone_number = COALESCE(%s,phone_number)
+ phone_number = COALESCE(%s,phone_number),
+ is_main_contact = COALESCE(%s,is_main_contact),
+ address = COALESCE(%s,address)
WHERE
id = %s
"""
@@ -263,6 +389,8 @@ def update_organization_info(
name,
website,
phone_number,
+ is_main_contact,
+ address,
str(information_id),
),
)
@@ -293,7 +421,7 @@ def upsert_organization_info(cursor: Cursor, organization_info, label_id: UUID):
return cursor.fetchone()[0]
-def upsert_organization(cursor: Cursor, organization_info_id: UUID):
+def upsert_organization_function(cursor: Cursor, organization_info_id: UUID):
"""
This function upserts an organization information in the database.
@@ -344,6 +472,30 @@ def get_organization(cursor: Cursor, organization_id: UUID):
)
+def delete_absent_organisation_information_from_label(cursor:Cursor,label_id:UUID,org_ids:list[UUID]):
+ """
+ Deletes organization information entries that have the specified label_id
+ but whose IDs are not in the provided org_ids list.
+
+ Parameters:
+ - cursor (Cursor): The database cursor
+ - label_id (UUID): The label ID to match
+ - org_ids (list[UUID]): List of organization IDs to keep
+
+ Returns:
+ - int: Number of rows deleted
+ """
+ query = """
+ DELETE FROM
+ organization_information
+ WHERE
+ label_id = %s
+ AND id != ALL(%s)
+ """
+ cursor.execute(query, (label_id, org_ids))
+ return cursor.rowcount
+
+
@handle_query_errors(OrganizationRetrievalError)
def get_full_organization(cursor: Cursor, org_id):
"""
@@ -394,6 +546,124 @@ def get_full_organization(cursor: Cursor, org_id):
cursor.execute(query, (org_id,))
return cursor.fetchone()
+def search_organization_information(cursor: Cursor, name:str,website:str,phone_number:str,address:str):
+ """
+ This function search for an organization information in the database.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - name (str): The name of the organization.
+
+ Returns:
+ - dict: The organization information
+ """
+ query = """
+ SELECT
+ id,
+ label_id,
+ name,
+ website,
+ phone_number,
+ address
+ FROM
+ organization_information
+ WHERE
+ """
+ first = True
+ # Make sure all parameters are not empty
+ if name is None and address is None and phone_number is None and website is None and name.strip() == "" and address.strip() == "" and phone_number.strip() == "" and website.strip() == "":
+ raise OrganizationRetrievalError("No search parameters provided. Please provide at least one search parameter.")
+ parameters = ()
+ if name is not None and name.strip() != "":
+ first = False
+ query += "WHERE name ILIKE %s"
+ parameters += (name,)
+ if address is not None and address.strip() != "":
+ if not first:
+ query += " AND "
+ else:
+ query+="WHERE "
+ first = False
+ query += "address ILIKE %s"
+ parameters += (address,)
+ if phone_number is not None and phone_number.strip() != "":
+ if not first:
+ query += " AND "
+ else:
+ query+="WHERE "
+ first = False
+ query += "phone_number ILIKE %s"
+ parameters += (phone_number,)
+ if website is not None and website.strip() != "":
+ if not first:
+ query += " AND "
+ else:
+ query+="WHERE "
+ first = False
+ query += "website ILIKE %s"
+ parameters += (website,)
+ query += ";"
+ cursor.execute(query, parameters)
+ return cursor.fetchall()
+
+def search_organization(cursor: Cursor, name:str,address:str,phone_number:str,website:str):
+ """
+ This function search for an organization in the database.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - name (str): The name of the organization.
+
+ Returns:
+ - dict: The organization
+ """
+ query = """
+ SELECT
+ id,
+ name,
+ website,
+ phone_number,
+ address
+ FROM
+ organization
+ """
+ first = True
+ # Make sure all parameters are not empty
+ if name is None and address is None and phone_number is None and website is None and name.strip() == "" and address.strip() == "" and phone_number.strip() == "" and website.strip() == "":
+ raise OrganizationRetrievalError("No search parameters provided. Please provide at least one search parameter.")
+ parameters = ()
+ if name is not None and name.strip() != "":
+ first = False
+ query += "WHERE name ILIKE %s"
+ parameters += (name,)
+ if address is not None and address.strip() != "":
+ if not first:
+ query += " AND "
+ else:
+ query+="WHERE "
+ first = False
+ query += "address ILIKE %s"
+ parameters += (address,)
+ if phone_number is not None and phone_number.strip() != "":
+ if not first:
+ query += " AND "
+ else:
+ query+="WHERE "
+ first = False
+ query += "phone_number ILIKE %s"
+ parameters += (phone_number,)
+ if website is not None and website.strip() != "":
+ if not first:
+ query += " AND "
+ else:
+ query+="WHERE "
+ first = False
+ query += "website ILIKE %s"
+ parameters += (website,)
+ query += ";"
+ cursor.execute(query, parameters)
+ return cursor.fetchall()
+
@handle_query_errors(LocationCreationError)
def new_location(cursor: Cursor, name, address, region_id, org_id=None):
diff --git a/fertiscan/db/queries/registration_number/__init__.py b/fertiscan/db/queries/registration_number/__init__.py
index 28da77ae..e531f2e2 100644
--- a/fertiscan/db/queries/registration_number/__init__.py
+++ b/fertiscan/db/queries/registration_number/__init__.py
@@ -23,6 +23,54 @@ def new_registration_number(
is_an_ingredient: bool,
read_name: str = None,
edited=False,
+):
+ """
+ This function creates a new registration_number in the database.
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - registration_number (str): The registration number of the product.
+ - label_id (uuid): The UUID of the label_information.
+ - is_an_ingredient (bool): The status of the registration number.
+ - edited (bool): The edited status of the registration number.
+ Returns:
+ - The UUID of the new registration number.
+ """
+ query = sql.SQL(
+ """
+ INSERT INTO registration_number_information (
+ "identifier",
+ "label_id",
+ "is_an_ingredient",
+ "name",
+ "edited"
+ )
+ VALUES (
+ %s,
+ %s,
+ %s,
+ %s,
+ %s
+ )
+ RETURNING id;
+ """
+ )
+ cursor.execute(
+ query, (registration_number, label_id, is_an_ingredient, read_name, edited)
+ )
+ if result := cursor.fetchone():
+ return result[0]
+ raise RegistrationNumberCreationError(
+ "Failed to create Registration Number. No data returned."
+ )
+
+@handle_query_errors(RegistrationNumberCreationError)
+def new_registration_number_function(
+ cursor: Cursor,
+ registration_number,
+ label_id: UUID,
+ is_an_ingredient: bool,
+ read_name: str = None,
+ edited=False,
):
"""
This function creates a new registration_number in the database.
@@ -71,10 +119,30 @@ def get_registration_numbers_json(cursor: Cursor, label_id: UUID):
raise RegistrationNumberRetrievalError(
"Failed to get Registration Numbers with the given label_id. No data returned."
)
+
+handle_query_errors(RegistrationNumberQueryError)
+def update_registration_number(
+ cursor:Cursor,
+ label_id :UUID,
+ registration_numbers:list[dict] | None,
+ ):
+ delete_registration_numbers(cursor=cursor,label_id=label_id)
+
+ if registration_numbers is not None:
+ for reg_number in registration_numbers:
+ new_registration_number(
+ cursor=cursor,
+ registration_number=reg_number["registration_number"],
+ is_an_ingredient=reg_number["is_an_ingredient"],
+ label_id=label_id,
+ read_name=None,
+ edited=True,
+ )
+
@handle_query_errors(RegistrationNumberQueryError)
-def update_registration_number(
+def update_registration_number_function(
cursor: Cursor,
registration_numbers,
label_id: UUID,
@@ -130,9 +198,81 @@ def get_registration_numbers_from_label(cursor: Cursor, label_id: UUID):
"""
)
cursor.execute(query, (label_id,))
- result = cursor.fetchall()
- if result:
+ return cursor.fetchall()
+
+def search_registration_number(cursor: Cursor, registration_number: str):
+ """
+ This function searches for the registration numbers in the
+ database.
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - registration_number (str): The registration number of the product.
+
+ Returns:
+ - The registration numbers of the product.
+ """
+ if registration_number is None or registration_number.strip() == "":
+ raise RegistrationNumberNotFoundError(
+ "No parameters provided for search. Please provide at least one search parameter."
+ )
+ query = sql.SQL(
+ """
+ SELECT
+ id,
+ identifier,
+ label_id,
+ is_an_ingredient,
+ name,
+ edited
+ FROM registration_number_information
+ WHERE identifier = %s;
+ """
+ )
+ cursor.execute(query, (registration_number,))
+ if result := cursor.fetchall():
return result
raise RegistrationNumberNotFoundError(
- f"Failed to get Registration Numbers with the given label_id {label_id}. No data returned."
+ f"Failed to find Registration Number with the given registration number {registration_number}. No data returned."
+ )
+
+def delete_registration_numbers(cursor: Cursor, label_id : UUID):
+ """
+ This function deletes the registration numbers from the database.
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - label_id (uuid): The UUID of the label_information.
+ """
+ query = sql.SQL(
+ """
+ DELETE FROM registration_number_information
+ WHERE label_id = %s;
+ """
)
+ cursor.execute(query, (label_id,))
+ if cursor.rowcount == 0:
+ raise RegistrationNumberQueryError(
+ f"Failed to delete Registration Numbers with the given label_id {label_id}. No rows affected."
+ )
+ else:
+ return cursor.rowcount
+
+def upsert_registration_numbers(cursor: Cursor, label_id: UUID, reg_numbers:dict):
+ """
+ Replaces all entries for a label by deleting existing ones and inserting new ones.
+
+ Parameters:
+ - cursor: Database cursor
+ - label_id: UUID of the label to update
+ - reg_numbers: Dictionary containing the new values to insert
+ """
+ delete_registration_numbers(cursor=cursor,label_id=label_id)
+
+ for record in reg_numbers:
+ new_registration_number(
+ cursor=cursor,
+ registration_number=record.registration_number,
+ label_id=label_id,
+ is_an_ingredient=record.is_an_ingredient,
+ read_name=None,
+ edited=True
+ )
diff --git a/fertiscan/db/queries/sub_label/__init__.py b/fertiscan/db/queries/sub_label/__init__.py
index 0e3ad385..7f309c3e 100644
--- a/fertiscan/db/queries/sub_label/__init__.py
+++ b/fertiscan/db/queries/sub_label/__init__.py
@@ -4,19 +4,20 @@
"""
from psycopg import Cursor
+from uuid import UUID
from fertiscan.db.queries.errors import (
SubLabelCreationError,
SubLabelNotFoundError,
SubLabelQueryError,
SubLabelRetrievalError,
+ SubLabelDeleteError,
SubLabelUpdateError,
SubTypeCreationError,
SubTypeQueryError,
handle_query_errors,
)
-
@handle_query_errors(SubLabelCreationError)
def new_sub_label(
cursor: Cursor, text_fr, text_en, label_id, sub_type_id, edited=False
@@ -32,6 +33,47 @@ def new_sub_label(
- sub_type_id (uuid): The UUID of the sub_type.
- edited (bool): The edited status of the sub label.
+ Returns:
+ - The UUID of the new sub label.
+ """
+ query = """
+ INSERT INTO sub_label (
+ text_content_fr,
+ text_content_en,
+ label_id,
+ edited,
+ sub_type_id
+ )
+ VALUES (
+ %s,
+ %s,
+ %s,
+ %s,
+ %s
+ )
+ RETURNING id;
+ """
+ cursor.execute(query, (text_fr, text_en, label_id, edited, sub_type_id))
+ if result := cursor.fetchone():
+ return result[0]
+ raise SubLabelCreationError("Failed to create SubLabel. No data returned.")
+
+
+@handle_query_errors(SubLabelCreationError)
+def new_sub_label_function(
+ cursor: Cursor, text_fr, text_en, label_id, sub_type_id, edited=False
+):
+ """
+ This function creates a new sub label in the database.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+ - text_fr (str): The text in french.
+ - text_en (str): The text in english.
+ - label_id (uuid): The UUID of the label_information.
+ - sub_type_id (uuid): The UUID of the sub_type.
+ - edited (bool): The edited status of the sub label.
+
Returns:
- The UUID of the new sub label.
"""
@@ -225,24 +267,70 @@ def update_sub_label(cursor: Cursor, sub_label_id, text_fr, text_en, edited=True
"""
cursor.execute(query, (text_fr, text_en, edited, sub_label_id))
-def update_sub_label_function(cursor: Cursor, sub_label_id, text_fr, text_en, edited=True):
+handle_query_errors(SubLabelUpdateError)
+def upsert_sub_label(cursor: Cursor, label_id: UUID, inspection_dict: dict):
"""
- This function updates the sub label in the database.
+ Replaces all entries for a label by deleting existing ones and inserting new ones.
+
+ Parameters:
+ - cursor: Database cursor
+ - label_id: UUID of the label to update
+ - inspection_dict: Dictionary containing the new values to insert
+ """
+ # get the all the active sub_types
+ sub_types = get_sub_types(cursor=cursor)
+
+ delete_sub_label(cursor=cursor, label_id=label_id)
+
+ for id, sub_type in sub_types:
+ if not inspection_dict.__contains__(sub_type):
+ continue
+ inspection_dict.__contains__(sub_type)
+ sub_label = inspection_dict[sub_type]
+ fr_list = sub_label["fr"]
+ en_list = sub_label["en"]
+ max_length = max(len(fr_list), len(en_list))
+ for i in range(0, max_length):
+ if i >= len(fr_list):
+ fr = None
+ en = en_list[i]
+ elif i >= len(en_list):
+ fr = fr_list[i]
+ en = None
+ else:
+ fr = fr_list[i]
+ en = en_list[i]
+ new_sub_label(
+ cursor=cursor,
+ text_fr=fr,
+ text_en=en,
+ label_id=label_id,
+ sub_type_id=id,
+ edited=True,
+ )
+
+
+handle_query_errors(SubLabelDeleteError)
+def delete_sub_label(cursor: Cursor, label_id: UUID):
+ """
+ This function deletes all sub labels associated with a given label_id.
Parameters:
- cursor (cursor): The cursor of the database.
- - sub_label_id (uuid): The UUID of the sub label.
- - text_fr (str): The text in french.
- - text_en (str): The text in english.
- - edited (bool): The edited status of the sub label.
+ - label_id (uuid): The UUID of the label_information.
Returns:
- None
"""
query = """
- SELECT update_sub_label(%s, %s, %s, %s);
+ DELETE FROM
+ sub_label
+ WHERE
+ label_id = %s
+ RETURNING ID;
"""
- cursor.execute(query, (sub_label_id, text_fr, text_en, edited))
+ cursor.execute(query, (label_id,))
+ return cursor.rowcount
@handle_query_errors(SubTypeCreationError)
@@ -302,3 +390,23 @@ def get_sub_type_id(cursor: Cursor, type_name):
if result := cursor.fetchone():
return result[0]
raise SubTypeQueryError("Failed to get the sub type id. No data returned.")
+
+
+def get_sub_types(cursor: Cursor) -> list:
+ """
+ This function fetches all sub types names from the database.
+
+ Parameters:
+ - cursor (cursor): The cursor of the database.
+
+ Returns:
+ - A list of Tuple of sub type names and ids (id,name_en).
+ """
+ query = """
+ SELECT
+ id, type_en
+ FROM
+ sub_type
+ """
+ cursor.execute(query)
+ return cursor.fetchall()
diff --git a/fertiscan/doc/inspection-view.md b/fertiscan/doc/inspection-view.md
index f4270994..97033595 100644
--- a/fertiscan/doc/inspection-view.md
+++ b/fertiscan/doc/inspection-view.md
@@ -8,6 +8,8 @@ object representing it.
```JSON
{
"inspection_id": "inspection uuid",
+ "container_id": "container_uuid",
+ "folder_id": "folder_uuid",
"owner_id": "Organization uuid",
"organizations": [
{
diff --git a/fertiscan/doc/new-inspection.md b/fertiscan/doc/new-inspection.md
index 412ccf3b..ed6c89e8 100644
--- a/fertiscan/doc/new-inspection.md
+++ b/fertiscan/doc/new-inspection.md
@@ -226,25 +226,20 @@ sequenceDiagram
title FertiScan Submit Form
actor C as Client
participant FE as Frontend
- participant BE as FertiScan
- participant DS as DataStore
+ participant BE as Backend
+ participant FS as FertiScan.Inspection_Controller
+ participant DS as DataStore.Container_Controller
participant DB as Database
participant blob as BLOB Storage
C ->> FE: Upload pictures
FE ->> BE: Analysis label (user_id,[pictures])
BE ->> BE: Digitalize label(pictures)
- BE ->> DS: register_analysis(cursor,user_id,pictures,form.json)
+ BE ->> DS: Save images
+ DS ->> blob: Upload images in new folder
+ DS --> BE: folder_id UUID
- DS ->> DB: new_picture_set(user_id)
- activate DS
- DB --> DS: picture_set_id
- DS ->>blob: new_folder(picture_set_id)
- DS ->> DS: upload_pictures(user_id,pictures,picture_set_id,container_client)
- DS ->> DB: register all pictures
- DB --> DS: picture_ids
- DS ->> blob: container_client.upload_pictures(pictures,picture_set_id)
- deactivate DS
+ BE ->> FS: register analysis
DS ->> DS: formatted_form = build_inspection_import(form)
DS ->> DB: new_inspection(user_id,picture_set_id,formatted_form.json)
DB --> DS: formatted_form_with_ids.json
diff --git a/fertiscan/doc/search-inspection.md b/fertiscan/doc/search-inspection.md
new file mode 100644
index 00000000..313c9dba
--- /dev/null
+++ b/fertiscan/doc/search-inspection.md
@@ -0,0 +1,153 @@
+# Search Inspection Documentation
+
+## Context
+
+The User wants to be able to search within the datasets of existing inspection
+based on the following parameters:
+
+- Fertilizer Name
+- Registration number
+- Lot number
+- A timeframe (lower and upper bounds dates)
+- Organization information (the entity responsable for the product)
+ - Name
+ - Phone number
+ - Address
+
+## Rules
+
+We need to establish rules regarding our search.
+
+### String matching
+
+- The search must allow for a case insensitive search, meaning the
+ capitalisation of words must not be considered. Meaning if you search "ABC in
+ the following dataset
+
+**Dataset** | ID | Name | |-----|------| | 1 | ABC | | 2 | abc |
+
+**Results** | ID | Name | |-----|------| | 1 | ABC | | 2 | abc |
+
+- The results must be an exact match to the parameter given, meaning if you
+ search "**ABC**" in the following dataset
+
+**Dataset** | ID | Name | |-----|------| | 1 | **ABC** | | 2 | **ABC**D |
+| 3 | **AB** | | 4 | abc |
+
+**Results** | ID | Name | |-----|------| | 1 | **ABC** | | 4 | abc |
+
+### Multiple Parameters
+
+- For an entry with multiple parameters being evaluated, all parameters are
+ evaluated using a logical "**AND**" therefor they mist all be a match for the
+ entry to be returned as a result. Meaning if you search (**ABC**,**XYZ**) in
+ the following dataset
+
+**Dataset** | ID | first name | Last name | |-----|------|----| | 1 |
+**ABC** | **XYZ** | | 2 | **ABC** | IJK | | 3 | DEF | **XYZ** | | 4 |
+DEF | IJK |
+
+**Results** | ID | first name | Last name | |-----|------|----| | 1 |
+**ABC** | **XYZ** |
+
+## Entity Used
+
+``` mermaid
+
+---
+title: FertiScan DB Structure
+---
+%%{init: {
+ "theme": "default",
+ "themeCSS": [
+ ".er.relationshipLabel { fill: black; }",
+ ".er.relationshipLabelBox { fill: white; }",
+ ".er.entityBox { fill: lightgray; }",
+ "[id^=entity-] .er.entityBox { fill: lightgreen;}",
+ "[id^=entity-timedimension] .er.entityBox { fill: pink;} ",
+ "[id^=entity-labeldimension] .er.entityBox { fill: pink;} ",
+ "[id^=entity-inspectionfactual] .er.entityBox { fill: pink;} "
+ ]
+}}%%
+erDiagram
+ inspection {
+ uuid id PK
+ boolean verified
+ TIMESTAMP upload_date
+ TIMESTAMP updated_at
+ uuid inspector_id FK
+ uuid label_info_id Fk
+ uuid fertilizer_id FK
+ uuid picture_set_id FK
+ }
+ organization_information{
+ uuid id PK
+ string name
+ string website
+ string phone_number
+ string address
+ }
+ label_information{
+ uuid id PK
+ string name
+ string lot_number
+ }
+
+ registration_number_information{
+ uuid id PK
+ string identifier
+ }
+
+ inspection ||--|| label_information : defines
+ label_information ||--o| organization_information: company
+ label_information ||--o|registration_number_information: defines
+
+```
+
+## Datastore Signature
+
+``` python
+
+def search_inspection(
+ cursor:Cursor,
+ fertilizer_name:str,
+ reg_number:str,
+ lot_number:str,
+ inspector_name:str,
+ date_of_inspection:str,
+ organization_name:str,
+ organization_address:str,
+ organization_phone:str,
+):
+```
+
+## Sequence of searching
+
+```mermaid
+sequenceDiagram
+ title FertiScan Submit Form
+ Actor User
+ participant FS as FertiScan-Datastore
+ participant Q as Query module
+ participant DB as Database
+
+ User ->> FS: search_inspection()
+ FS ->> Q: search_organisation(
organization_name,
organization_address,
organization_phone)
+ Q --) Q: build query with parameters
+ Q->>DB: fetch query results
+ Q -->>FS: list of organisation information
+ FS --)FS: append list of label_ids to fetch
+
+ FS ->> Q: search_registration_number(
registration_number)
+ Q --) Q: build query with parameters
+ Q->>DB: fetch query results
+ Q -->>FS: list of registration number information
+ FS --)FS: append list of label_ids to fetch
+
+ FS ->> Q: search_inspection(
fertilizer_name,
lower_bound_date,
upper_bound_date,
lot_number,
label_ids)
+ Q --) Q: build query with parameters
+ Q->>DB: fetch query results
+ Q ->>FS: list of inspection resume
+ FS-->User: list of inspection resume
+
+```
diff --git a/tests/fertiscan/db/__init__.py b/tests/fertiscan/db/__init__.py
index fba0404a..e69de29b 100644
--- a/tests/fertiscan/db/__init__.py
+++ b/tests/fertiscan/db/__init__.py
@@ -1,4 +0,0 @@
-import unittest
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/tests/fertiscan/db/test_guaranteed_analysis.py b/tests/fertiscan/db/test_guaranteed_analysis.py
index 20a310a4..e8b21100 100644
--- a/tests/fertiscan/db/test_guaranteed_analysis.py
+++ b/tests/fertiscan/db/test_guaranteed_analysis.py
@@ -316,3 +316,79 @@ def test_get_all_guaranteed_analysis(self):
self.assertIn(guaranteed_analysis_id_2, guaranteed_analysis_dict)
guaranteed_item = guaranteed_analysis_dict[guaranteed_analysis_id_2]
self.assertEqual(guaranteed_item[1], other_name)
+
+ def test_delete_guaranteed_analysis(self):
+ guaranteed_analysis_id = nutrients.new_guaranteed_analysis(
+ self.cursor,
+ self.guaranteed_analysis_name,
+ self.guaranteed_analysis_value,
+ self.guaranteed_analysis_unit,
+ self.label_information_id,
+ self.language,
+ self.element_id,
+ False,
+ )
+ self.assertTrue(validator.is_valid_uuid(guaranteed_analysis_id))
+ guaranteeds = nutrients.get_all_guaranteeds(cursor=self.cursor,label_id=self.label_information_id)
+ self.assertEqual(len(guaranteeds),1)
+
+ nutrients.delete_guaranteed_analysis(cursor=self.cursor,label_id=self.label_information_id)
+
+ guaranteeds = nutrients.get_all_guaranteeds(cursor=self.cursor,label_id=self.label_information_id)
+ self.assertEqual(len(guaranteeds),0)
+
+ def test_upsert_guaranteed_analysis(self):
+ default_value = metadata.Value(
+ value=self.guaranteed_analysis_value,
+ unit=self.guaranteed_analysis_unit,
+ name=self.guaranteed_analysis_name,
+ edited=False
+ )
+
+ en = [default_value]
+ fr = [default_value]
+ og_model = metadata.GuaranteedAnalysis(
+ title=None,
+ is_minimal=None,
+ en = en,
+ fr = fr
+ )
+
+ guaranteed_analysis_id = nutrients.new_guaranteed_analysis(
+ self.cursor,
+ self.guaranteed_analysis_name,
+ self.guaranteed_analysis_value,
+ self.guaranteed_analysis_unit,
+ self.label_information_id,
+ "en",
+ self.element_id,
+ False,
+ )
+ guaranteed_analysis_id = nutrients.new_guaranteed_analysis(
+ self.cursor,
+ self.guaranteed_analysis_name,
+ self.guaranteed_analysis_value,
+ self.guaranteed_analysis_unit,
+ self.label_information_id,
+ "fr",
+ self.element_id,
+ False,
+ )
+
+ get_ga = nutrients.get_all_guaranteeds(cursor=self.cursor,label_id=self.label_information_id)
+ self.assertEqual(len(get_ga),2)
+
+ en.append(default_value)
+ fr.append(default_value)
+
+ updated_ga = metadata.GuaranteedAnalysis(
+ title=None,
+ is_minimal=None,
+ en = en,
+ fr = fr
+ )
+
+ nutrients.upsert_guaranteed_analysis(self.cursor,label_id=self.label_information_id,GA=updated_ga.model_dump())
+ updated_ga = nutrients.get_guaranteed_by_label(cursor=self.cursor,label_id=self.label_information_id)
+ self.assertEqual(len(updated_ga),len(en)+len(fr))
+ self.assertNotEqual(len(get_ga),updated_ga)
diff --git a/tests/fertiscan/db/test_ingredient.py b/tests/fertiscan/db/test_ingredient.py
index 72202880..2b210c37 100644
--- a/tests/fertiscan/db/test_ingredient.py
+++ b/tests/fertiscan/db/test_ingredient.py
@@ -8,6 +8,7 @@
import datastore.db as db
from datastore.db.metadata import validator
+import fertiscan.db.metadata.inspection as metadata
from fertiscan.db.queries import ingredient, label
DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL")
@@ -170,3 +171,108 @@ def test_get_ingredient_json_record_keeping(self):
self.assertEqual(len(ingredient_obj.get("ingredients").get("fr")),1)
# make sure that the record keeping label does not display any ingredients
self.assertEqual(len(ingredient_empty.get("ingredients").get("fr")),0)
+
+ def test_get_ingredient_label(self):
+ ingredient_id = ingredient.new_ingredient(
+ self.cursor,
+ self.ingredient_name,
+ self.value,
+ self.unit,
+ self.label_id,
+ self.language,
+ False,
+ False,
+ False,
+ )
+ self.assertTrue(validator.is_valid_uuid(ingredient_id))
+
+ get_ingredient = ingredient.get_ingredient_label(cursor=self.cursor,label_id=self.label_id)
+ self.assertEqual(len(get_ingredient),1)
+ self.assertEqual(get_ingredient[0][0],ingredient_id)
+
+ def test_delete_ingredient_label(self):
+ ingredient_id = ingredient.new_ingredient(
+ self.cursor,
+ self.ingredient_name,
+ self.value,
+ self.unit,
+ self.label_id,
+ self.language,
+ False,
+ False,
+ False,
+ )
+ self.assertTrue(validator.is_valid_uuid(ingredient_id))
+
+ og_ingredient = ingredient.get_ingredient_label(
+ cursor=self.cursor,
+ label_id=self.label_id,
+ )
+ self.assertEqual(len(og_ingredient),1)
+ self.assertEqual(og_ingredient[0][0],ingredient_id)
+
+ nb_row = ingredient.delete_ingredient_label(
+ cursor=self.cursor,
+ label_id=self.label_id
+ )
+ self.assertEqual(nb_row,len(og_ingredient))
+ deleted_ingredient = ingredient.get_ingredient_label(
+ cursor=self.cursor,
+ label_id=self.label_id,
+ )
+ self.assertEqual(len(deleted_ingredient),0)
+ self.assertEqual(og_ingredient[0][0],ingredient_id)
+
+ def test_upsert_ingredient_label(self):
+ ingredient_id1 = ingredient.new_ingredient(
+ self.cursor,
+ self.ingredient_name,
+ self.value,
+ self.unit,
+ self.label_id,
+ "fr",
+ False,
+ False,
+ False,
+ )
+ ingredient_id2 = ingredient.new_ingredient(
+ self.cursor,
+ self.ingredient_name,
+ self.value,
+ self.unit,
+ self.label_id,
+ "en",
+ False,
+ False,
+ False,
+ )
+ og_ingredient = ingredient.get_ingredient_label(
+ cursor=self.cursor,
+ label_id=self.label_id,
+ )
+ self.assertEqual(len(og_ingredient),2)
+
+ # Creating the structure for the upsert
+ default_ingredient = metadata.Value(
+ value=self.value,
+ unit=self.unit,
+ name=self.ingredient_name,
+ edited=True
+ )
+ en = [default_ingredient,default_ingredient]
+ fr = [default_ingredient,default_ingredient]
+ ingredient_dict = metadata.ValuesObjects(en=en,fr=fr)
+ ingredient.upsert_ingredient(
+ cursor=self.cursor,
+ label_id=self.label_id,
+ ingredients=ingredient_dict.model_dump()
+ )
+ # Validating the data has been correctly deleted and reinserted
+ updated_ingredients = ingredient.get_ingredient_label(
+ cursor=self.cursor,
+ label_id=self.label_id,
+ )
+ self.assertEqual(len(updated_ingredients),len(en)+len(fr))
+ for record in updated_ingredients:
+ self.assertNotEqual(record[0],ingredient_id1)
+ self.assertNotEqual(record[0],ingredient_id2)
diff --git a/tests/fertiscan/db/test_inspection.py b/tests/fertiscan/db/test_inspection.py
index d4bcbf7e..8bbe712e 100644
--- a/tests/fertiscan/db/test_inspection.py
+++ b/tests/fertiscan/db/test_inspection.py
@@ -1,15 +1,19 @@
"""
This is a test script for the database packages.
-It tests the functions in the inspection.
+It tests the functions in the inspection module.
"""
import os
import unittest
+from datetime import datetime
+from time import sleep
+
import datastore.db as db
+from datastore import Role
from datastore.db.metadata import picture_set, validator
-from datastore.db.queries import picture, user
-from fertiscan.db.queries import inspection
+from datastore.db.queries import picture, user, container
+from fertiscan.db.queries import inspection, label, organization
DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL")
if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "":
@@ -27,11 +31,21 @@ def setUp(self):
db.create_search_path(self.con, self.cursor, DB_SCHEMA)
self.user_email = "testessr@email"
- self.user_id = user.register_user(self.cursor, self.user_email)
+ self.user_id = user.register_user(
+ self.cursor, self.user_email, Role.INSPECTOR.value
+ )
self.folder_name = "test-folder"
self.picture_set = picture_set.build_picture_set_metadata(self.user_id, 1)
+ self.container_id = container.create_container(
+ self.cursor, "test-container", self.user_id, False, "test-fertiscan-user"
+ )
self.picture_set_id = picture.new_picture_set(
- self.cursor, self.picture_set, self.user_id, self.folder_name
+ self.cursor,
+ self.picture_set,
+ self.user_id,
+ self.folder_name,
+ container_id=self.container_id,
+ parent_id=None,
)
def tearDown(self):
@@ -39,25 +53,46 @@ def tearDown(self):
db.end_query(self.con, self.cursor)
def test_new_inspection(self):
- inspection_id = inspection.new_inspection(
- self.cursor, self.user_id, self.picture_set_id, False
+ inspection_id, upload_date = inspection.new_inspection(
+ cursor=self.cursor,
+ user_id=self.user_id,
+ picture_set_id=self.picture_set_id,
+ label_id=None,
+ container_id=self.container_id,
+ verified=False,
)
self.assertTrue(validator.is_valid_uuid(inspection_id))
+ self.assertIsInstance(upload_date, datetime)
def test_is_inspection_verified(self):
inspection_id = inspection.new_inspection(
- self.cursor, self.user_id, self.picture_set_id, False
- )
+ cursor=self.cursor,
+ user_id=self.user_id,
+ picture_set_id=self.picture_set_id,
+ label_id=None,
+ container_id=self.container_id,
+ verified=False,
+ )[0]
inspection_id2 = inspection.new_inspection(
- self.cursor, self.user_id, self.picture_set_id, True
- )
+ cursor=self.cursor,
+ user_id=self.user_id,
+ picture_set_id=self.picture_set_id,
+ label_id=None,
+ container_id=self.container_id,
+ verified=True,
+ )[0]
self.assertFalse(inspection.is_inspection_verified(self.cursor, inspection_id))
self.assertTrue(inspection.is_inspection_verified(self.cursor, inspection_id2))
def test_get_inspection(self):
inspection_id = inspection.new_inspection(
- self.cursor, self.user_id, self.picture_set_id, False
- )
+ cursor=self.cursor,
+ user_id=self.user_id,
+ picture_set_id=self.picture_set_id,
+ label_id=None,
+ container_id=self.container_id,
+ verified=False,
+ )[0]
inspection_data = inspection.get_inspection(self.cursor, inspection_id)
self.assertEqual(inspection_data[0], False)
self.assertEqual(inspection_data[3], self.user_id)
@@ -65,11 +100,21 @@ def test_get_inspection(self):
def test_get_all_user_inspection(self):
inspection_id = inspection.new_inspection(
- self.cursor, self.user_id, self.picture_set_id, False
- )
+ cursor=self.cursor,
+ user_id=self.user_id,
+ picture_set_id=self.picture_set_id,
+ label_id=None,
+ container_id=self.container_id,
+ verified=False,
+ )[0]
inspection_id2 = inspection.new_inspection(
- self.cursor, self.user_id, self.picture_set_id, True
- )
+ cursor=self.cursor,
+ user_id=self.user_id,
+ picture_set_id=self.picture_set_id,
+ label_id=None,
+ container_id=self.container_id,
+ verified=False,
+ )[0]
inspection_data = inspection.get_all_user_inspection(self.cursor, self.user_id)
self.assertEqual(len(inspection_data), 2)
self.assertEqual(inspection_data[0][0], inspection_id)
@@ -77,11 +122,21 @@ def test_get_all_user_inspection(self):
def test_get_all_user_inspection_filter_verified(self):
inspection_id = inspection.new_inspection(
- self.cursor, self.user_id, self.picture_set_id, False
- )
+ cursor=self.cursor,
+ user_id=self.user_id,
+ picture_set_id=self.picture_set_id,
+ label_id=None,
+ container_id=self.container_id,
+ verified=False,
+ )[0]
inspection_id2 = inspection.new_inspection(
- self.cursor, self.user_id, self.picture_set_id, True
- )
+ cursor=self.cursor,
+ user_id=self.user_id,
+ picture_set_id=self.picture_set_id,
+ label_id=None,
+ container_id=self.container_id,
+ verified=True,
+ )[0]
inspection_data = inspection.get_all_user_inspection_filter_verified(
self.cursor, self.user_id, True
)
@@ -112,3 +167,31 @@ def test_get_all_user_inspection_filter_verified(self):
# self.assertEqual(len(inspection_data), 2)
# self.assertEqual(inspection_data[0][0], inspection_id)
# self.assertEqual(inspection_data[1][0], inspection_id2)
+
+ def test_update_inspection(self):
+ inspection_id, upload_date = inspection.new_inspection(
+ cursor=self.cursor,
+ user_id=self.user_id,
+ picture_set_id=self.picture_set_id,
+ label_id=None,
+ container_id=self.container_id,
+ verified=False,
+ )
+ self.con.commit() # need to commit to get the time change
+ sleep(2)
+ updated_at = inspection.update_inspection(
+ cursor=self.cursor,
+ inspection_id=inspection_id,
+ verified=True,
+ inspection_comment="Test comment",
+ )
+ inspection_data = inspection.get_inspection(self.cursor, inspection_id)
+ inspection.delete_inspection(self.cursor, inspection_id, self.user_id)
+ picture.delete_picture_set(self.cursor, self.picture_set_id)
+ container.delete_container(self.cursor, self.container_id)
+ user.delete_user(self.cursor, self.user_id)
+ self.con.commit()
+
+ self.assertTrue(inspection_data[0])
+ self.assertNotEqual(updated_at, upload_date)
+ self.assertEqual(updated_at, inspection_data[2])
diff --git a/tests/fertiscan/db/test_label.py b/tests/fertiscan/db/test_label.py
index d92ef205..232941e7 100644
--- a/tests/fertiscan/db/test_label.py
+++ b/tests/fertiscan/db/test_label.py
@@ -31,6 +31,7 @@ def setUp(self):
self.guaranteed_analysis_title_en = "guaranteed_analysis"
self.guaranteed_analysis_title_fr = "analyse_garantie"
self.guaranteed_is_minimal = False
+ self.record_keeping = False
def tearDown(self):
self.con.rollback()
@@ -106,3 +107,54 @@ def test_get_label_information_json(self):
def test_get_label_information_json_wrong_label_id(self):
with self.assertRaises(label.LabelInformationNotFoundError):
label.get_label_information_json(self.cursor, str(uuid.uuid4()))
+
+ def test_update_sub_label(self):
+ label_information_id = label.new_label_information(
+ self.cursor,
+ self.product_name,
+ self.lot_number,
+ self.npk,
+ self.n,
+ self.p,
+ self.k,
+ self.guaranteed_analysis_title_en,
+ self.guaranteed_analysis_title_fr,
+ self.guaranteed_is_minimal,
+ self.record_keeping,
+ )
+ self.assertTrue(validator.is_valid_uuid(label_information_id))
+ label_data = label.get_label_information(self.cursor, label_information_id)
+ new_name = "new_name"
+ new_lot_number = "new lot number"
+ new_npk = "new npk"
+ new_npk_numerical_val = 17
+ new_english_title = "new title"
+
+ label.update_label_info(
+ cursor=self.cursor,
+ label_id=label_information_id,
+ name=new_name,
+ lot_number=new_lot_number,
+ npk=new_npk,
+ n=new_npk_numerical_val,
+ p=new_npk_numerical_val,
+ k=self.k,
+ title_en=new_english_title,
+ title_fr=self.guaranteed_analysis_title_fr,
+ is_minimal=not self.guaranteed_is_minimal,
+ record_keeping=not self.record_keeping,
+ )
+
+ updated_label = label.get_label_information(self.cursor, label_information_id)
+
+ self.assertEqual(updated_label[0], label_data[0])
+ self.assertEqual(updated_label[1], new_name)
+ self.assertEqual(updated_label[2], new_lot_number)
+ self.assertEqual(updated_label[3], new_npk)
+ self.assertEqual(updated_label[4], new_npk_numerical_val)
+ self.assertEqual(updated_label[5], new_npk_numerical_val)
+ self.assertEqual(updated_label[6], self.k) # We did not change this one
+ self.assertEqual(updated_label[7], new_english_title)
+ self.assertEqual(updated_label[8], self.guaranteed_analysis_title_fr)
+ self.assertEqual(updated_label[9], not self.guaranteed_is_minimal)
+ self.assertEqual(updated_label[10], not self.record_keeping)
diff --git a/tests/fertiscan/db/test_metric.py b/tests/fertiscan/db/test_metric.py
index 1707b0ee..9090b194 100644
--- a/tests/fertiscan/db/test_metric.py
+++ b/tests/fertiscan/db/test_metric.py
@@ -216,3 +216,100 @@ def test_get_full_metric(self):
self.assertEqual(metric_data[3], self.unit_to_si_unit)
self.assertEqual(metric_data[4], self.metric_edited)
self.assertEqual(metric_data[5], self.metric_type)
+
+ def test_delete_metric_by_type(self):
+ volume_unit = "ml"
+ weight_unit_imperial = "lb"
+ weight_unit_metric = "kg"
+ density_unit = "lb/ml"
+ metric.new_metric(
+ self.cursor,
+ self.metric_value,
+ volume_unit,
+ self.label_id,
+ "volume",
+ self.metric_edited,
+ )
+ metric.new_metric(
+ self.cursor,
+ self.metric_value,
+ weight_unit_imperial,
+ self.label_id,
+ "weight",
+ self.metric_edited,
+ )
+ metric.new_metric(
+ self.cursor,
+ self.metric_value,
+ weight_unit_metric,
+ self.label_id,
+ "weight",
+ self.metric_edited,
+ )
+ metric.new_metric(
+ self.cursor,
+ self.metric_value,
+ density_unit,
+ self.label_id,
+ "density",
+ self.metric_edited,
+ )
+ og_metrics = metric.get_metric_by_label(cursor=self.cursor,label_id=self.label_id)
+
+ self.assertEqual(len(og_metrics),4)
+ # delete the 2 weights
+ metric.delete_metric_by_type(
+ cursor=self.cursor,
+ label_id=self.label_id,
+ metric_type="weight"
+ )
+ deleted_metric = metric.get_metric_by_label(cursor=self.cursor,label_id=self.label_id)
+ self.assertEqual(len(deleted_metric),len(og_metrics)-2)
+
+ def test_delete_metric(self):
+ volume_unit = "ml"
+ weight_unit_imperial = "lb"
+ weight_unit_metric = "kg"
+ density_unit = "lb/ml"
+ metric.new_metric(
+ self.cursor,
+ self.metric_value,
+ volume_unit,
+ self.label_id,
+ "volume",
+ self.metric_edited,
+ )
+ metric.new_metric(
+ self.cursor,
+ self.metric_value,
+ weight_unit_imperial,
+ self.label_id,
+ "weight",
+ self.metric_edited,
+ )
+ metric.new_metric(
+ self.cursor,
+ self.metric_value,
+ weight_unit_metric,
+ self.label_id,
+ "weight",
+ self.metric_edited,
+ )
+ metric.new_metric(
+ self.cursor,
+ self.metric_value,
+ density_unit,
+ self.label_id,
+ "density",
+ self.metric_edited,
+ )
+ og_metrics = metric.get_metric_by_label(cursor=self.cursor,label_id=self.label_id)
+ self.assertEqual(len(og_metrics),4)
+
+ metric.delete_metric(
+ cursor=self.cursor,
+ label_id=self.label_id
+ )
+ # Verify there are no metrics left
+ deleted_metrics = metric.get_metric_by_label(cursor=self.cursor,label_id=self.label_id)
+ self.assertEqual(len(deleted_metrics),0)
diff --git a/tests/fertiscan/db/test_organization.py b/tests/fertiscan/db/test_organization.py
index e113999e..33689191 100644
--- a/tests/fertiscan/db/test_organization.py
+++ b/tests/fertiscan/db/test_organization.py
@@ -290,6 +290,8 @@ def test_update_organization_info(self):
new_name = "new-name"
new_website = "www.new.com"
new_phone = "987654321"
+ is_main_contact = False
+ updated_address = "1223 street"
id = organization.new_organization_information(
self.cursor,
self.address,
@@ -298,20 +300,29 @@ def test_update_organization_info(self):
self.phone,
self.label_information_id,
False,
- True,
+ is_main_contact,
)
old_data = organization.get_organization_info(self.cursor, id)
self.assertEqual(old_data[0], self.name)
self.assertEqual(old_data[1], self.website)
self.assertEqual(old_data[2], self.phone)
self.assertEqual(old_data[3], self.address)
+ self.assertEqual(old_data[6], is_main_contact)
organization.update_organization_info(
- self.cursor, id, new_name, new_website, new_phone
+ cursor=self.cursor,
+ information_id=id,
+ name=new_name,
+ website=new_website,
+ phone_number=new_phone,
+ is_main_contact=not is_main_contact,
+ address=updated_address,
)
data = organization.get_organization_info(self.cursor, id)
self.assertEqual(data[0], new_name)
self.assertEqual(data[1], new_website)
self.assertEqual(data[2], new_phone)
+ self.assertEqual(data[3], updated_address)
+ self.assertEqual(data[6], not is_main_contact)
def test_new_organization_information(self):
id = organization.new_organization_information(
@@ -526,12 +537,38 @@ def test_new_organization_no_location(self):
)
self.assertTrue(validator.is_valid_uuid(organization_id))
- def test_upsert_organization(self):
+ def test_upsert_organization_function(self):
organization_id = organization.new_organization(
self.cursor, self.name, "wrong-website", "wrong-phone", "wrong-address"
)
- update_id = organization.upsert_organization(self.cursor, str(self.org_info_id))
+ update_id = organization.upsert_organization_function(
+ self.cursor, str(self.org_info_id)
+ )
+ self.assertEqual(organization_id, update_id)
+ organization_data = organization.get_organization(
+ self.cursor, str(organization_id)
+ )
+ self.assertEqual(organization_data[0], self.name)
+ self.assertEqual(organization_data[1], self.website)
+ self.assertEqual(organization_data[2], self.phone)
+ self.assertEqual(organization_data[3], self.address)
+
+ def test_upsert_organization(self):
+ organization_id = organization.new_organization(
+ cursor=self.cursor,
+ name=self.name,
+ website="wrong-website",
+ phone_number="wrong-phone",
+ address="wrong-address",
+ )
+ update_id = organization.upsert_organization(
+ cursor=self.cursor,
+ name=self.name,
+ website=self.website,
+ phone_number=self.phone,
+ address=self.address,
+ )
self.assertEqual(organization_id, update_id)
organization_data = organization.get_organization(
self.cursor, str(organization_id)
@@ -554,3 +591,112 @@ def test_get_organization(self):
def test_get_organization_not_found(self):
with self.assertRaises(organization.OrganizationNotFoundError):
organization.get_organization(self.cursor, str(uuid.uuid4()))
+
+ def test_search_organization(self):
+ organization_id = organization.new_organization(
+ cursor=self.cursor,
+ name=self.name,
+ website=self.website,
+ phone_number=self.phone,
+ address=self.address,
+ )
+ organization.new_organization(
+ cursor=self.cursor,
+ name="other-name",
+ website="other-website",
+ phone_number="other-phone",
+ address="other-address",
+ )
+ organization.new_organization(
+ cursor=self.cursor,
+ name="partial-name",
+ website="partial-website",
+ phone_number="partial-phone",
+ address=self.address,
+ )
+ # test search by name
+ data = organization.search_organization(
+ cursor=self.cursor,
+ name=self.name,
+ address=None,
+ phone_number=None,
+ website=None,
+ )
+ self.assertEqual(len(data), 1)
+ self.assertEqual(data[0][0], organization_id)
+ self.assertEqual(data[0][1], self.name)
+ self.assertEqual(data[0][2], self.website)
+ self.assertEqual(data[0][3], self.phone)
+ self.assertEqual(data[0][4], self.address)
+ # test search Wrong name
+ data = organization.search_organization(
+ cursor=self.cursor,
+ name="wrong name",
+ address=None,
+ phone_number=None,
+ website=None,
+ )
+ self.assertEqual(len(data), 0)
+ # test search by address
+ data = organization.search_organization(
+ cursor=self.cursor,
+ name=None,
+ address=self.address,
+ phone_number=None,
+ website=None,
+ )
+ self.assertEqual(len(data), 2)
+ # test search by phone
+ data = organization.search_organization(
+ cursor=self.cursor,
+ name=None,
+ address=None,
+ phone_number=self.phone,
+ website=None,
+ )
+ self.assertEqual(len(data), 1)
+ # test search by website
+ data = organization.search_organization(
+ cursor=self.cursor,
+ name=None,
+ address=None,
+ phone_number=None,
+ website=self.website,
+ )
+ self.assertEqual(len(data), 1)
+ # test search by multiple fields
+ data = organization.search_organization(
+ cursor=self.cursor,
+ name=self.name,
+ address=self.address,
+ phone_number=self.phone,
+ website=self.website,
+ )
+ self.assertEqual(len(data), 1)
+ self.assertEqual(data[0][0], organization_id)
+ # test search by multiple fields but one wrong
+ data = organization.search_organization(
+ cursor=self.cursor,
+ name=self.name,
+ address=self.address,
+ phone_number=self.phone,
+ website="wrong-website",
+ )
+ self.assertEqual(len(data), 0)
+ # testing partial matching search (2 rows have the same address, but the rest is different)
+ data = organization.search_organization(
+ cursor=self.cursor,
+ name=None,
+ address=self.address,
+ phone_number=None,
+ website=None,
+ )
+ self.assertEqual(len(data), 2)
+ data = organization.search_organization(
+ cursor=self.cursor,
+ name=self.name,
+ address=self.address,
+ phone_number=None,
+ website=None,
+ )
+ self.assertEqual(len(data), 1)
diff --git a/tests/fertiscan/db/test_registration_number.py b/tests/fertiscan/db/test_registration_number.py
index 88ffc312..7d08a65f 100644
--- a/tests/fertiscan/db/test_registration_number.py
+++ b/tests/fertiscan/db/test_registration_number.py
@@ -92,7 +92,6 @@ def test_get_registration_numbers_json_empty(self):
self.cursor, self.label_id
)
RegistrationNumber.model_validate(registration_numbers)
- print(registration_numbers)
self.assertEqual(len(registration_numbers["registration_numbers"]), 0)
def test_update_registration_number(self):
@@ -107,27 +106,77 @@ def test_update_registration_number(self):
old_data = registration_number.get_registration_numbers_json(
self.cursor, self.label_id
)
+ reg_number_model = RegistrationNumber.model_validate(old_data["registration_numbers"][0])
self.assertEqual(
- old_data["registration_numbers"][0]["registration_number"],
+ reg_number_model.registration_number,
self.registration_number,
)
new_reg_number = "654321"
- new_dict = old_data["registration_numbers"]
- new_dict[0]["registration_number"] = new_reg_number
-
+ reg_number_model.registration_number = new_reg_number
+ reg_number_model.edited = True
+ reg_number_model.is_an_ingredient = not self.is_an_ingredient
+
+
registration_number.update_registration_number(
- self.cursor,
- json.dumps(new_dict),
- self.label_id,
+ cursor=self.cursor,
+ registration_numbers=[reg_number_model.model_dump()],
+ label_id=self.label_id,
)
- new_data = registration_number.get_registration_numbers_json(
+ new_data = registration_number.get_registration_numbers_from_label(
self.cursor, self.label_id
+ )[0]
+
+ self.assertEqual(new_data[0],new_reg_number)
+ self.assertNotEqual(new_data[0],self.registration_number)
+ self.assertTrue(new_data[3])
+ self.assertEqual(new_data[1],not self.is_an_ingredient)
+
+ def test_delete_registration_numbers(self):
+ registration_number.new_registration_number(
+ self.cursor,
+ self.registration_number,
+ self.label_id,
+ self.is_an_ingredient,
+ self.read_name,
+ self.edited,
)
+
+ og_data = registration_number.get_registration_numbers_from_label(self.cursor,self.label_id)
- self.assertEqual(
- new_data["registration_numbers"][0]["registration_number"], new_reg_number
- )
- self.assertNotEqual(
- new_data["registration_numbers"][0]["registration_number"],
+ self.assertEqual(len(og_data),1)
+
+ affected_row = registration_number.delete_registration_numbers(cursor=self.cursor,label_id=self.label_id)
+ self.assertEqual(len(og_data),affected_row)
+ deleted_data = registration_number.get_registration_numbers_from_label(self.cursor,self.label_id)
+
+ self.assertEqual(len(deleted_data),0)
+
+ def test_search_registration_number(self):
+ reg_nb_id = registration_number.new_registration_number(
+ self.cursor,
self.registration_number,
+ self.label_id,
+ self.is_an_ingredient,
+ self.read_name,
+ self.edited,
+ )
+ other_reg_nb = "654321"
+ other_reg_nb_id = registration_number.new_registration_number(
+ self.cursor,
+ other_reg_nb,
+ self.label_id,
+ self.is_an_ingredient,
+ self.read_name,
+ self.edited,
+ )
+ data = registration_number.search_registration_number(
+ cursor=self.cursor,
+ registration_number=self.registration_number,
)
+ self.assertEqual(len(data),1)
+ self.assertEqual(data[0][0],reg_nb_id)
+ self.assertEqual(data[0][1],self.registration_number)
+ self.assertEqual(data[0][2],self.label_id)
+ self.assertEqual(data[0][3],self.is_an_ingredient)
+ self.assertEqual(data[0][4],self.read_name)
+ self.assertEqual(data[0][5],self.edited)
diff --git a/tests/fertiscan/db/test_sub_label.py b/tests/fertiscan/db/test_sub_label.py
index 21958fae..cfa7220c 100644
--- a/tests/fertiscan/db/test_sub_label.py
+++ b/tests/fertiscan/db/test_sub_label.py
@@ -317,3 +317,44 @@ def test_sub_label_insertion_raises_exception_for_null_or_empty_texts(self):
self.sub_type_id,
False,
)
+
+ def test_upsert_sub_label(self):
+ sub_label.new_sub_label(
+ self.cursor,
+ self.text_fr,
+ self.text_en,
+ self.label_id,
+ self.sub_type_id,
+ False,
+ )
+ od_data = sub_label.get_all_sub_label(cursor=self.cursor,label_id=self.label_id)
+ self.assertEqual(len(od_data),1)
+ data = {
+ self.type_en: {
+ "en": [
+ "1. Dissolve 50g in 10L of water.",
+ "2. Apply every 2 weeks.",
+ "3. Store in a cool, dry place."
+ ],
+ "fr": [
+ "1. Dissoudre 50g dans 10L d'eau.",
+ "2. Appliquer toutes les 2 semaines.",
+ "3. Conserver dans un endroit frais et sec."
+ ]
+ },
+ self.type_2_en: {
+ "en": [
+ "Keep out of reach of children.",
+ "Avoid contact with skin and eyes."
+ ],
+ "fr": [
+ "Tenir hors de port\u00e9e des enfants.",
+ "\u00c9viter le contact avec la peau et les yeux."
+ ]
+ },
+ }
+
+ sub_label.upsert_sub_label(self.cursor,self.label_id,data)
+
+ updated = sub_label.get_all_sub_label(cursor=self.cursor,label_id=self.label_id)
+ self.assertEqual(len(updated),5)
diff --git a/tests/fertiscan/test_datastore.py b/tests/fertiscan/test_datastore.py
index bedf00c2..db79e8c1 100644
--- a/tests/fertiscan/test_datastore.py
+++ b/tests/fertiscan/test_datastore.py
@@ -8,14 +8,17 @@
import json
import os
import unittest
+from uuid import UUID
from PIL import Image
+from datetime import datetime
import datastore
import datastore.db as db
import datastore.db.metadata.validator as validator
import fertiscan
import fertiscan.db.metadata.inspection as metadata
+from datastore.db.queries import container
from datastore.db.queries import picture
from fertiscan.db.queries import (
ingredient,
@@ -25,6 +28,7 @@
nutrients,
organization,
sub_label,
+ errors,
)
BLOB_CONNECTION_STRING = os.environ["FERTISCAN_STORAGE_URL"]
@@ -60,6 +64,8 @@ def loop_into_empty_dict(dict_data):
continue
else:
passing = False
+ elif isinstance(value, datetime):
+ continue
elif isinstance(value, bool):
if not value:
continue
@@ -86,20 +92,35 @@ def setUp(self):
db.create_search_path(self.con, self.cursor, DB_SCHEMA)
self.user_email = "testesss@email"
self.tier = "test-user"
+ self.user_role = datastore.Role.INSPECTOR
self.user = asyncio.run(
datastore.new_user(
- self.cursor, self.user_email, BLOB_CONNECTION_STRING, self.tier
- )
- )
- self.container_client = asyncio.run(
- datastore.get_user_container_client(
- self.user.id,
+ self.cursor,
+ self.user_email,
BLOB_CONNECTION_STRING,
- BLOB_ACCOUNT,
- BLOB_KEY,
self.tier,
+ self.user_role,
+ )
+ )
+ self.container_model = next(iter(self.user.model.containers.values()))
+ self.container_controller = asyncio.run(
+ datastore.get_container_controller(
+ self.cursor, self.container_model.id, BLOB_CONNECTION_STRING, None
+ )
+ )
+ self.container_client = self.container_controller.container_client
+ # Assure the user Storage space exists
+ self.assertTrue(self.container_client.exists())
+ self.folder: datastore.Folder = asyncio.run(
+ self.container_controller.create_folder(
+ cursor=self.cursor,
+ performed_by=self.user.id,
+ folder_name="test-folder-fertiscan",
+ nb_pictures=0,
+ parent_folder_id=None,
)
)
+ self.folder_id = self.folder.id
self.image = Image.new("RGB", (1980, 1080), "blue")
self.image_byte_array = io.BytesIO()
@@ -159,27 +180,31 @@ def tearDown(self):
except Exception as e:
print(e)
- def test_register_analysis(self):
- # print(self.user.id)
- self.assertTrue(self.container_client.exists())
- analysis = asyncio.run(
- fertiscan.register_analysis(
+ def test_new_inspection(self):
+
+ inspection_controller: fertiscan.InspectionController = (
+ fertiscan.new_inspection(
self.cursor,
- self.container_client,
self.user.id,
- [self.pic_encoded, self.pic_encoded],
self.analysis_json,
+ self.container_controller.id,
+ folder_id=self.folder_id,
)
)
- self.assertIsNotNone(analysis)
- self.assertTrue(validator.is_valid_uuid(analysis["inspection_id"]))
- inspection_id = analysis["inspection_id"]
-
- self.assertTrue(validator.is_valid_uuid(analysis["product"]["label_id"]))
- label_id = analysis["product"]["label_id"]
+ self.assertIsNotNone(inspection_controller)
+ self.assertIsInstance(inspection_controller, fertiscan.InspectionController)
+ analysis = inspection_controller.model
+ self.assertTrue(validator.is_valid_uuid(inspection_controller.id))
+ self.assertIsInstance(analysis, fertiscan.data_inspection.Inspection)
+ analysis = fertiscan.data_inspection.Inspection.model_validate(analysis)
+ inspection_id = analysis.inspection_id
+ self.assertEqual(inspection_id, inspection_controller.id)
+
+ self.assertTrue(validator.is_valid_uuid(analysis.product.label_id))
+ label_id = analysis.product.label_id
metrics = metric.get_metric_by_label(
- self.cursor, str(analysis["product"]["label_id"])
+ self.cursor, str(analysis.product.label_id)
)
self.assertIsNotNone(metrics)
@@ -188,11 +213,9 @@ def test_register_analysis(self):
) # There are 4 metrics in the analysis_json (1 volume, 1 density, 2 weight )
ingredients = ingredient.get_ingredient_json(
- self.cursor, str(analysis["product"]["label_id"])
+ self.cursor, str(analysis.product.label_id)
)
self.assertIsNotNone(ingredients)
- # print(ingredients)
-
# specifications = specification.get_all_specifications(
# cursor=self.cursor, label_id=str(analysis["product"]["label_id"])
# )
@@ -210,7 +233,7 @@ def test_register_analysis(self):
# len(nutrients_data), self.nb_micronutrients
# ) # There are 2 nutrients in the analysis_json
sub_labels = sub_label.get_sub_label_json(
- self.cursor, str(analysis["product"]["label_id"])
+ self.cursor, str(analysis.product.label_id)
)
self.assertIsNotNone(sub_labels)
@@ -222,6 +245,12 @@ def test_register_analysis(self):
self.maxDiff = None
# self.assertDictEqual(analysis, original_dataset)
+ inspection_fk = inspection.get_inspection_fk(
+ cursor=self.cursor, inspection_id=inspection_id
+ )
+ self.assertEqual(self.user.id, inspection_fk[1])
+ self.assertEqual(self.folder_id, inspection_fk[2])
+ self.assertEqual(self.container_model.id, inspection_fk[3])
# Verify OLAP Layer
query = "SELECT EXISTS (SELECT 1 FROM inspection_factual WHERE inspection_factual.inspection_id = %s)"
@@ -238,12 +267,11 @@ def test_register_analysis(self):
label_dimension = label.get_label_dimension(self.cursor, label_id)
- self.assertEqual(
- str(label_dimension[1][0]), str(analysis["organizations"][0]["id"])
- )
- self.assertEqual(
- str(label_dimension[1][1]), str(analysis["organizations"][1]["id"])
- )
+ company_info_id = str(label_dimension[1])
+ manufacturer_info_id = str(label_dimension[3])
+
+ self.assertEqual(str(label_dimension[1][0]), str(analysis.organizations[0].id))
+ self.assertEqual(str(label_dimension[1][1]), str(analysis.organizations[1].id))
self.assertEqual(len(label_dimension[2]), self.nb_instructions)
@@ -258,7 +286,7 @@ def test_register_analysis(self):
self.assertEqual(len(label_dimension[11]), 1)
self.assertEqual(len(label_dimension[12]), 1)
- def test_register_analysis_empty(self):
+ def test_new_inspection_empty(self):
empty_analysis = {
"organizations": [],
"fertiliser_name": None,
@@ -272,22 +300,33 @@ def test_register_analysis_empty(self):
"instructions_en": [],
"cautions_fr": [],
"instructions_fr": [],
- "guaranteed_analysis_en": {"title": None, "is_minimal": False, "nutrients": []},
- "guaranteed_analysis_fr": {"title": None, "is_minimal": False, "nutrients": []},
+ "guaranteed_analysis_en": {
+ "title": None,
+ "is_minimal": False,
+ "nutrients": [],
+ },
+ "guaranteed_analysis_fr": {
+ "title": None,
+ "is_minimal": False,
+ "nutrients": [],
+ },
}
formatted_analysis = metadata.build_inspection_import(
- empty_analysis, self.user.id
- )
- picture_set_id = picture.new_picture_set(
- self.cursor, json.dumps({}), self.user.id
+ empty_analysis, self.user.id, self.folder_id, self.container_model.id
)
inspection_dict = inspection.new_inspection_with_label_info(
- self.cursor, self.user.id, picture_set_id, formatted_analysis
+ self.cursor,
+ self.user.id,
+ self.folder_id,
+ formatted_analysis.model_dump_json(),
+ )
+ inspection_model = fertiscan.data_inspection.Inspection.model_validate(
+ inspection_dict
)
- inspection_id = inspection_dict["inspection_id"]
- label_id = inspection_dict["product"]["label_id"]
+ inspection_id = inspection_model.inspection_id
+ label_id = inspection_model.product.label_id
self.assertTrue(validator.is_valid_uuid(inspection_id))
# Verify the data
@@ -297,152 +336,147 @@ def test_register_analysis_empty(self):
# Verify getters
inspection_data = metadata.build_inspection_export(self.cursor, inspection_id)
- inspection_data = json.loads(inspection_data)
- # TODO: investigate if this should pass and why it doesn't
+ inspection_data = metadata.Inspection.model_validate(inspection_data)
# Make sure the inspection data is either a empty array or None
- # self.assertTrue(loop_into_empty_dict(inspection_data))
+ self.assertTrue(loop_into_empty_dict(inspection_data.model_dump()))
def test_register_analysis_invalid_user(self):
with self.assertRaises(Exception):
- asyncio.run(
- fertiscan.register_analysis(
- self.cursor,
- self.container_client,
- "invalid_user_id",
- [self.pic_encoded, self.pic_encoded],
- self.analysis_json,
- )
+ fertiscan.new_inspection(
+ self.cursor,
+ "invalid_user_id",
+ self.analysis_json,
+ self.container_model.id,
+ self.folder_id,
)
def test_register_analysy_missing_key(self):
- self.analysis_json.pop("specification_en", None)
+ self.analysis_json.pop("instructions_en", None)
with self.assertRaises(fertiscan.data_inspection.BuildInspectionImportError):
- asyncio.run(
- fertiscan.register_analysis(
- self.cursor,
- self.container_client,
- self.user.id,
- [self.pic_encoded, self.pic_encoded],
- {},
- )
+ fertiscan.new_inspection(
+ self.cursor,
+ self.user.id,
+ self.analysis_json,
+ self.container_model.id,
+ self.folder_id,
)
- def test_get_full_inspection_json(self):
- formatted_analysis = metadata.build_inspection_import(
- self.analysis_json, self.user.id
+ def test_get_inspection(self):
+ inspection_controller = fertiscan.new_inspection(
+ self.cursor,
+ self.user.id,
+ self.analysis_json,
+ self.container_controller.id,
+ folder_id=self.folder_id,
)
- picture_set_id = picture.new_picture_set(
- self.cursor, json.dumps({}), self.user.id
+ inspection_dict = inspection_controller.model
+ inspection_model = fertiscan.data_inspection.Inspection.model_validate(
+ inspection_dict
)
- inspection_dict = inspection.new_inspection_with_label_info(
- self.cursor, self.user.id, picture_set_id, formatted_analysis
+ inspection_id = inspection_model.inspection_id
+ inspection_controller = fertiscan.get_inspection(
+ cursor=self.cursor, inspection_id=inspection_id
+ )
+ get_inspection_model = metadata.Inspection.model_validate(
+ inspection_controller.model
)
- inspection_id = inspection_dict["inspection_id"]
- data = asyncio.run(
- fertiscan.get_full_inspection_json(self.cursor, inspection_id)
+ self.assertEqual(str(get_inspection_model.inspection_id), str(inspection_id))
+ self.assertEqual(str(get_inspection_model.inspector_id), str(self.user.id))
+ self.maxDiff = None
+ self.assertDictEqual(
+ get_inspection_model.model_dump(), inspection_model.model_dump()
)
- data = json.loads(data)
- self.assertEqual(data["inspection_id"], str(inspection_id))
- self.assertEqual(data["inspector_id"], str(self.user.id))
def test_delete_inspection(self):
# Create a new inspection to delete later
- with open(TEST_INSPECTION_JSON_PATH, "r") as file:
- input_json = json.load(file)
-
- picture_set_id = asyncio.run(
- datastore.create_picture_set(
- self.cursor, self.container_client, 0, self.user.id
- )
+ inspection_controller = fertiscan.new_inspection(
+ self.cursor,
+ self.user.id,
+ self.analysis_json,
+ self.container_model.id,
+ self.folder_id,
)
- inspection_dict = inspection.new_inspection_with_label_info(
- self.cursor, self.user.id, picture_set_id, json.dumps(input_json)
- )
- inspection_id = inspection_dict["inspection_id"]
+ inspection_dict = inspection_controller.model
+ inspection_id = inspection_dict.inspection_id
+ self.assertEqual(inspection_controller.id, inspection_id)
# Verify the inspection was created by directly querying the database
- self.cursor.execute(
- "SELECT id FROM inspection WHERE id = %s;",
- (inspection_id,),
- )
- fetched_inspection_id = self.cursor.fetchone()
- self.assertIsNotNone(
- fetched_inspection_id, "The inspection should exist before deletion."
+ self.assertTrue(
+ inspection.is_a_inspection_id(
+ cursor=self.cursor, inspection_id=inspection_id
+ )
)
# Perform the delete operation
+ self.assertTrue(
+ container.is_a_container(
+ self.cursor, inspection_controller.model.container_id
+ )
+ )
deleted_inspection = asyncio.run(
- fertiscan.delete_inspection(
- self.cursor, inspection_id, self.user.id, self.container_client
+ inspection_controller.delete_inspection(
+ cursor=self.cursor,
+ user_id=self.user.id,
)
)
# Verify that the inspection ID matches the one we deleted
self.assertIsInstance(deleted_inspection, metadata.DBInspection)
- self.assertEqual(str(deleted_inspection.id), inspection_id)
+ self.assertEqual(deleted_inspection.id, inspection_id)
# Ensure that the inspection no longer exists in the database
- self.cursor.execute(
- "SELECT EXISTS(SELECT 1 FROM inspection WHERE id = %s);",
- (inspection_id,),
- )
- inspection_exists = self.cursor.fetchone()[0]
- self.assertFalse(
- inspection_exists, "The inspection should be deleted from the database."
- )
+ self.assertFalse(inspection.is_a_inspection_id(self.cursor, inspection_id))
# Verify that the picture set associated with the inspection was also deleted
- self.cursor.execute(
- "SELECT EXISTS(SELECT 1 FROM picture_set WHERE id = %s);",
- (picture_set_id,),
- )
- picture_set_exists = self.cursor.fetchone()[0]
- self.assertFalse(
- picture_set_exists,
- "The picture set should be deleted from the database.",
- )
+ self.assertFalse(picture.is_a_picture_set_id(self.cursor, self.folder_id))
# Verify that no blobs associated with the picture set ID remain in the container
blobs_after = [blob.name for blob in self.container_client.list_blobs()]
self.assertFalse(
- any(str(picture_set_id) in blob_name for blob_name in blobs_after),
+ any(str(self.folder_id) in blob_name for blob_name in blobs_after),
"The folder associated with the picture set ID should be deleted from the container.",
)
def test_update_inspection(self):
- self.assertTrue(self.container_client.exists())
- analysis = asyncio.run(
- fertiscan.register_analysis(
- self.cursor,
- self.container_client,
- self.user.id,
- [self.pic_encoded, self.pic_encoded],
- self.analysis_json,
- )
+ inspection_controller = fertiscan.new_inspection(
+ self.cursor,
+ self.user.id,
+ self.analysis_json,
+ self.container_model.id,
+ self.folder_id,
)
- self.assertIsNotNone(analysis)
- inspection_id = analysis["inspection_id"]
- label_id = analysis["product"]["label_id"]
+ self.assertIsInstance(inspection_controller, fertiscan.InspectionController)
+ inspection_id = inspection_controller.id
+ label_id = inspection_controller.model.product.label_id
self.assertTrue(validator.is_valid_uuid(inspection_id))
+
+ og_inspection_data = inspection.get_inspection(self.cursor, inspection_id)
+ # Check the updated_at is the same as the the upload date
+ self.assertEqual(og_inspection_data[1], og_inspection_data[2])
+ self.assertEqual(
+ inspection_controller.model.upload_date,
+ inspection_controller.model.updated_at,
+ )
+ self.assertEqual(og_inspection_data[1], inspection_controller.model.updated_at)
# new values
new_product_name = "New Product Name"
- untouched_weight = analysis["product"]["metrics"]["weight"][1]["value"]
+ untouched_weight = inspection_controller.model.product.metrics.weight[1].value
new_weight = 1000.0
- untouched_volume = analysis["product"]["metrics"]["volume"]["value"]
+ untouched_volume = inspection_controller.model.product.metrics.volume.value
new_density = 10.0
- old_npk = analysis["product"]["npk"]
+ old_npk = inspection_controller.model.product.npk
new_npk = "10-10-10"
new_instruction_en = ["3. of", "2. set"]
new_instruction_fr = ["3. de", "2. ensemble"]
new_instruction_nb = (len(new_instruction_en) + len(new_instruction_fr)) / 2
new_value = 100.0
- old_value = analysis["guaranteed_analysis"]["fr"][0]["value"]
+ old_value = inspection_controller.model.guaranteed_analysis.fr[0].value
new_title = "Nouveau titre"
- old_title = analysis["guaranteed_analysis"]["title"]["fr"]
- old_name = analysis["guaranteed_analysis"]["fr"][0]["name"]
+ old_title = inspection_controller.model.guaranteed_analysis.title.fr
+ old_name = inspection_controller.model.guaranteed_analysis.fr[0].name
new_name = "Nouveau nom"
user_feedback = "This is a feedback"
new_record_keeping = True
@@ -487,40 +521,46 @@ def test_update_inspection(self):
new_guaranteed_nb = 2
- old_organizations = analysis["organizations"]
+ old_organizations = inspection_controller.model.organizations
new_organizations = [
{
"name": "New Organization",
"address": "New Address",
- "phone": "New Phone",
+ "phone_number": "New Phone",
"email": "New Email",
"website": "New Website",
+ "is_main_contact": True,
}
]
# update the dataset
- analysis["product"]["name"] = new_product_name
- analysis["product"]["metrics"]["weight"][0]["value"] = new_weight
- analysis["product"]["metrics"]["weight"][0]["edited"] = True
- analysis["product"]["metrics"]["density"]["value"] = new_density
- analysis["product"]["metrics"]["density"]["edited"] = True
- analysis["product"]["record_keeping"] = new_record_keeping
- analysis["product"]["npk"] = new_npk
- analysis["instructions"]["en"] = new_instruction_en
- analysis["instructions"]["fr"] = new_instruction_fr
+ to_update = inspection_controller.model.model_copy().model_dump()
+ to_update["product"]["name"] = new_product_name
+ to_update["product"]["metrics"]["weight"][0]["value"] = new_weight
+ to_update["product"]["metrics"]["weight"][0]["edited"] = True
+ to_update["product"]["metrics"]["density"]["value"] = new_density
+ to_update["product"]["metrics"]["density"]["edited"] = True
+ to_update["product"]["record_keeping"] = new_record_keeping
+ to_update["product"]["npk"] = new_npk
+ to_update["instructions"]["en"] = new_instruction_en
+ to_update["instructions"]["fr"] = new_instruction_fr
# analysis["specifications"]["en"] = new_specification_en
- analysis["cautions"]["en"] = new_cautions_en
- analysis["cautions"]["fr"] = new_cautions_fr
- analysis["guaranteed_analysis"] = new_guaranteed_analysis
- analysis["organizations"] = new_organizations
- analysis["inspection_comment"] = user_feedback
+ to_update["cautions"]["en"] = new_cautions_en
+ to_update["cautions"]["fr"] = new_cautions_fr
+ to_update["guaranteed_analysis"] = new_guaranteed_analysis
+ to_update["organizations"] = new_organizations
+ to_update["inspection_comment"] = user_feedback
old_label_dimension = label.get_label_dimension(self.cursor, label_id)
- asyncio.run(
- fertiscan.update_inspection(
- self.cursor, inspection_id, self.user.id, analysis
- )
+ inspection_to_update = metadata.Inspection.model_validate(to_update)
+ updated_inspection = inspection_controller.update_inspection(
+ self.cursor,
+ self.user.id,
+ inspection_to_update,
)
+ updated_inspection = metadata.Inspection.model_validate(updated_inspection)
+ # check if the updated_at is updated in the model
+ # self.assertNotEqual(updated_inspection.updated_at,updated_inspection.upload_date) # This is not passing since you need to commit the cursor to get a different timestamp
# check if specifications are updated
# specifications = specification.get_all_specifications(self.cursor, label_id)
@@ -565,11 +605,14 @@ def test_update_inspection(self):
inspection_data = inspection.get_inspection(self.cursor, inspection_id)
self.assertEqual(inspection_data[8], user_feedback)
+ # Verify updated_at is updated in the db
+ # This is not passing since you need to commit the cursor to get a different timestamp
+ # self.assertNotEqual(inspection_data[1], og_inspection_data[1])
+ # self.assertNotEqual(inspection_data[1], inspection_data[2])
+
# Verify organizations are saved
orgs = organization.get_organizations_info_label(self.cursor, label_id)
-
- self.assertEqual(len(orgs), 3) # 2 default + 1 new
- self.assertEqual(len(orgs), len(old_organizations) + 1)
+ self.assertEqual(len(orgs), 1) # There is only 1 new
# VERIFY OLAP
new_label_dimension = label.get_label_dimension(self.cursor, label_id)
@@ -646,11 +689,11 @@ def test_update_inspection(self):
}
old_guaranteed_nb = new_guaranteed_nb
new_guaranteed_nb = 8
- analysis["guaranteed_analysis"] = new_guaranteed_analysis
- asyncio.run(
- fertiscan.update_inspection(
- self.cursor, inspection_id, self.user.id, analysis
- )
+ to_update = updated_inspection.model_copy().model_dump()
+ to_update["guaranteed_analysis"] = new_guaranteed_analysis
+ inspection_to_update = metadata.Inspection.model_validate(to_update)
+ inspection_controller.update_inspection(
+ self.cursor, self.user.id, inspection_to_update
)
new_label_dimension = label.get_label_dimension(self.cursor, label_id)
@@ -659,3 +702,46 @@ def test_update_inspection(self):
self.assertEqual(len(new_label_dimension[9]), new_guaranteed_nb)
self.assertNotEqual(len(new_label_dimension[9]), len(old_label_dimension[12]))
self.assertNotEqual(len(new_label_dimension[9]), old_guaranteed_nb)
+
+ def test_update_inspection_already_verified(self):
+ inspection_controller: fertiscan.InspectionController = (
+ fertiscan.new_inspection(
+ self.cursor,
+ self.user.id,
+ self.analysis_json,
+ self.container_controller.id,
+ folder_id=self.folder_id,
+ )
+ )
+ inspection_to_update = inspection_controller.model.model_copy()
+ self.assertFalse(inspection_to_update.verified)
+ inspection_to_update.verified = True
+ self.assertTrue(inspection_to_update.verified)
+ inspection_to_update.product.name = "verified_product"
+ updated_inspection = inspection_controller.update_inspection(
+ self.cursor,
+ self.user.id,
+ inspection_to_update,
+ )
+ self.assertTrue(updated_inspection.verified)
+ updated_inspection.product.name = "blocked to be updated"
+ with self.assertRaises(inspection.InspectionUpdateError):
+ inspection_controller.update_inspection(
+ self.cursor,
+ self.user.id,
+ updated_inspection,
+ ),
+ inspection.InspectionUpdateError,
+ )
+
+ def test_search_inspection(self):
+ """
+ The seach inspection function only uses the query modules
+ and doesn't modify the parameters nor the results from the query modules
+
+ All the module function used to search have been tested individually.
+ Therefor, we decided there are no gains from testing the global search function
+
+ We are still leaving this in case there are some things to be tested in the future.
+ """
+ self.assertTrue(True)