diff --git a/.gitignore b/.gitignore index 9bf0207a..d693a8be 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ ml_structure.json .DS_Store .venv venv +.vscode/extensions.json diff --git a/db-creation.py b/db-creation.py index 0f728bcf..d15891da 100644 --- a/db-creation.py +++ b/db-creation.py @@ -2,7 +2,7 @@ import datastore.db as db from psycopg import sql -DB_URL = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_URL = os.environ.get("FERTISCAN_DB_URL") SCHEMA = os.environ.get("FERTISCAN_SCHEMA_TESTING") def create_db(DB_URL, SCHEMA : str): @@ -63,4 +63,5 @@ def execute_sql_file(cursor,sql_file): if __name__ == "__main__": print("Creating the database for schema: ", SCHEMA) + print("Database URL: ", DB_URL) create_db(DB_URL=DB_URL, SCHEMA=SCHEMA) diff --git a/fertiscan/db/bytebase/OLAP/inspection_triggers.sql b/fertiscan/db/bytebase/OLAP/inspection_triggers.sql index c62e67cd..9519ac75 100644 --- a/fertiscan/db/bytebase/OLAP/inspection_triggers.sql +++ b/fertiscan/db/bytebase/OLAP/inspection_triggers.sql @@ -17,15 +17,13 @@ BEGIN ) RETURNING id INTO time_id; -- Create the Inspection_factual entry INSERT INTO "fertiscan_0.0.18".inspection_factual ( - inspection_id, inspector_id, label_info_id, time_id, sample_id, company_id, manufacturer_id, picture_set_id, original_dataset + inspection_id, inspector_id, label_info_id, time_id, sample_id, picture_set_id, original_dataset ) VALUES ( NEW.id, NEW.inspector_id, NEW.label_info_id, time_id, NULL, -- NOT handled yet - NULL, -- IS not defined yet - NULL, -- IS not defined yet NEW.picture_set_id, NULL ); diff --git a/fertiscan/db/bytebase/delete_inspection_function.sql b/fertiscan/db/bytebase/delete_inspection_function.sql index a433e0ee..0fdfefe1 100644 --- a/fertiscan/db/bytebase/delete_inspection_function.sql +++ b/fertiscan/db/bytebase/delete_inspection_function.sql @@ -2,17 +2,19 @@ SET search_path TO "fertiscan_0.0.18"; -- Trigger function to handle after organization_information delete for location deletion -CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".after_org_info_delete_location_trig() +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() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN - IF OLD.location_id IS NOT NULL THEN + IF OLD.main_location_id IS NOT NULL THEN BEGIN DELETE FROM "fertiscan_0.0.18".location - WHERE id = OLD.location_id; + 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.location_id; + RAISE NOTICE 'Location % is still referenced by another record and cannot be deleted.', OLD.main_location_id; END; END IF; @@ -21,11 +23,10 @@ END; $$; -- Trigger definition on organization_information table for location deletion -DROP TRIGGER IF EXISTS after_organization_information_delete_location ON "fertiscan_0.0.18".organization_information; -CREATE TRIGGER after_organization_information_delete_location -AFTER DELETE ON "fertiscan_0.0.18".organization_information +CREATE TRIGGER after_organization_delete_main_location +AFTER DELETE ON "fertiscan_0.0.18".organization FOR EACH ROW -EXECUTE FUNCTION "fertiscan_0.0.18".after_org_info_delete_location_trig(); +EXECUTE FUNCTION "fertiscan_0.0.18".after_org_delete_location_trig(); -- Function to delete an inspection and related data CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".delete_inspection( @@ -96,6 +97,7 @@ BEGIN --This was the only inspection for the fertilizer so we delete it DELETE FROM "fertiscan_0.0.18".fertilizer WHERE id = OLD.fertilizer_id; + end if; END IF; RETURN NULL; diff --git a/fertiscan/db/bytebase/get_inspection/get_organizations_json.sql b/fertiscan/db/bytebase/get_inspection/get_organizations_json.sql index 5d3a2e11..19276845 100644 --- a/fertiscan/db/bytebase/get_inspection/get_organizations_json.sql +++ b/fertiscan/db/bytebase/get_inspection/get_organizations_json.sql @@ -1,35 +1,37 @@ --Unverified organization data -DROP IF EXISTS FUNCTION "fertiscan_0.0.18".get_organizations_information_json(label_id uuid); +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( -label_id uuid) +label_id_value uuid) RETURNS jsonb LANGUAGE plpgsql AS $function$ DECLARE result_json jsonb; BEGIN - SELECT jsonb_agg(jsonb_build_object( + SELECT jsonb_build_object( 'organizations', - jsonb_build_object( - 'id', COALESCE(org.id, Null), - 'name', COALESCE(org.name, Null), - 'address', COALESCE(org.address, Null), - 'phone_number', COALESCE(org.phone_number, Null), - 'website', COALESCE(org.website, Null), - 'edited', COALESCE(org.edited, Null), - 'is_main_contact', COALESCE(org.is_main_contact, Null) - ) - )) + COALESCE(jsonb_agg( + jsonb_build_object( + 'id', COALESCE(org.id, Null), + 'name', COALESCE(org.name, Null), + 'address', COALESCE(org.address, Null), + 'phone_number', COALESCE(org.phone_number, Null), + 'website', COALESCE(org.website, Null), + 'edited', COALESCE(org.edited, Null), + 'is_main_contact', COALESCE(org.is_main_contact, Null) + ) + ), '[]'::jsonb) + ) INTO result_json FROM organization_information as org - WHERE org.label_id = label_id; + WHERE org.label_id = label_id_value; RETURN result_json; END; $function$; -- verified organization -DROP IF EXISTS FUNCTION "fertiscan_0.0.18".get_organizations_json(); +DROP FUNCTION IF EXISTS "fertiscan_0.0.18".get_organizations_json(); CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".get_organizations_json() RETURNS jsonb LANGUAGE plpgsql @@ -37,18 +39,20 @@ AS $function$ DECLARE result_json jsonb; BEGIN - SELECT jsonb_agg(jsonb_build_object( + SELECT jsonb_build_object( 'organizations', - jsonb_build_object( + jsonb_agg(jsonb_build_object( 'id', COALESCE(org.id, Null), 'name', COALESCE(org.name, Null), 'address', COALESCE(org.address, Null), 'phone_number', COALESCE(org.phone_number, Null), 'website', COALESCE(org.website, Null), - 'updated_at', COALESCE(org.updated_at, Null), + 'updated_at', COALESCE(org.updated_at, Null) ) )) INTO result_json FROM organization_information as org; RETURN result_json; END; +$function$; + diff --git a/fertiscan/db/bytebase/new_inspection_function.sql b/fertiscan/db/bytebase/new_inspection_function.sql index c19b6f7f..e92144e0 100644 --- a/fertiscan/db/bytebase/new_inspection_function.sql +++ b/fertiscan/db/bytebase/new_inspection_function.sql @@ -40,6 +40,8 @@ DECLARE fr_value text; en_value text; flag boolean; + counter int; + orgs_ids uuid[]; BEGIN -- COMPANY @@ -351,6 +353,7 @@ BEGIN -- ORGANIZATIONS INFO flag := TRUE; + counter := 0; FOR record in SELECT * FROM jsonb_array_elements(input_json->'organizations') LOOP -- Check if any of the fields are not null @@ -372,8 +375,15 @@ BEGIN ); -- The flag is used to mark the first Org as the main contact if flag THEN + -- Update the first organization as the main contact in the form + input_json := jsonb_set(input_json,ARRAY['organizations',counter::text,'is_main_contact'],to_jsonb(TRUE)); flag := FALSE; END IF; + --array_append(orgs_ids,organization_id) + if organization_id is not null then + input_json := jsonb_set(input_json,ARRAY['organizations',counter::text,'id'],to_jsonb(organization_id)); + end if; + counter := counter + 1; END IF; END LOOP; -- ORGANIZATIONS INFO END diff --git a/fertiscan/db/bytebase/schema_0.0.18.sql b/fertiscan/db/bytebase/schema_0.0.18.sql index 62fc58d2..3a62400d 100644 --- a/fertiscan/db/bytebase/schema_0.0.18.sql +++ b/fertiscan/db/bytebase/schema_0.0.18.sql @@ -136,8 +136,8 @@ create schema "fertiscan_0.0.18"; "name" text, "address" text NOT NULL, "address_number" text, - "city" text NOT NULL, - "postal_code" text NOT NULL, + "city" text, + "postal_code" text, "region_id" uuid REFERENCES "fertiscan_0.0.18".region(id) ); @@ -271,7 +271,7 @@ create schema "fertiscan_0.0.18"; "upload_date" timestamp DEFAULT CURRENT_TIMESTAMP, "update_at" timestamp DEFAULT CURRENT_TIMESTAMP, "latest_inspection_id" uuid REFERENCES "fertiscan_0.0.18".inspection(id) ON DELETE SET NULL, - "main_contact" uuid REFERENCES "fertiscan_0.0.18".organization(id) ON DELETE SET NULL + "main_contact_id" uuid REFERENCES "fertiscan_0.0.18".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.0.18".inspection ADD "fertilizer_id" uuid REFERENCES "fertiscan_0.0.18".fertilizer(id); diff --git a/fertiscan/db/bytebase/update_inspection/update_sub_label.sql b/fertiscan/db/bytebase/update_inspection/update_sub_label.sql new file mode 100644 index 00000000..fc7c9096 --- /dev/null +++ b/fertiscan/db/bytebase/update_inspection/update_sub_label.sql @@ -0,0 +1,61 @@ + +-- 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( + p_label_id uuid, + new_sub_labels jsonb +) +RETURNS void AS $$ +DECLARE + sub_type_rec RECORD; + fr_values jsonb; + en_values jsonb; + i int; + max_length int; + fr_value text; + en_value text; +BEGIN + -- Delete existing sub labels for the given label_id + DELETE FROM sub_label WHERE label_id = p_label_id; + + -- Loop through each sub_type + FOR sub_type_rec IN SELECT id, type_en FROM sub_type + LOOP + -- Extract the French and English arrays for the current sub_type + fr_values := COALESCE(new_sub_labels->sub_type_rec.type_en->'fr', '[]'::jsonb); + en_values := COALESCE(new_sub_labels->sub_type_rec.type_en->'en', '[]'::jsonb); + + -- Determine the maximum length of the arrays + max_length := GREATEST( + jsonb_array_length(fr_values), + jsonb_array_length(en_values) + ); + + -- Check if lengths are not equal, and raise a notice + IF jsonb_array_length(en_values) != jsonb_array_length(fr_values) THEN + RAISE NOTICE 'Array length mismatch for sub_type: %, EN length: %, FR length: %', + sub_type_rec.type_en, jsonb_array_length(en_values), jsonb_array_length(fr_values); + END IF; + + -- Loop through the indices up to the maximum length + FOR i IN 0..(max_length - 1) + LOOP + -- Extract values or set to empty string if not present + fr_value := fr_values->>i; + en_value := en_values->>i; + + -- Insert sub label record + INSERT INTO sub_label ( + text_content_fr, text_content_en, label_id, edited, sub_type_id + ) + VALUES ( + fr_value, + en_value, + p_label_id, + NULL, -- not handled + sub_type_rec.id + ); + END LOOP; + END LOOP; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/fertiscan/db/bytebase/update_inspection/upsert_organization.sql b/fertiscan/db/bytebase/update_inspection/upsert_organization.sql index 49497ab9..2377a3d2 100644 --- a/fertiscan/db/bytebase/update_inspection/upsert_organization.sql +++ b/fertiscan/db/bytebase/update_inspection/upsert_organization.sql @@ -1,36 +1,40 @@ -DROP IF EXISTS FUNCTION "fertiscan_0.0.18".upsert_organization(); +DROP FUNCTION IF EXISTS "fertiscan_0.0.18".upsert_organization(); CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".upsert_organization(org_info_id uuid) -RETURNS id AS $$ +RETURNS uuid +LANGUAGE plpgsql +AS $function$ DECLARE record record; address_str TEXT; org_id uuid; BEGIN -- Select the row from the organization_information table -SELECT * INTO record FROM organization_information WHERE id = org_info_id; +SELECT * INTO record FROM organization_information WHERE "id" = org_info_id; -- Check if the organization exists -Select id INTO org_id FROM organization WHERE name ILIKE record.name; +Select "id" INTO org_id FROM organization WHERE name ILIKE record.name; -- UPSERT DATA INTO THE ORGANIZATION TABLE IF org_id IS NULL THEN - INSERT INTO organization ("website","phone_number","address","main_location_id") + INSERT INTO organization ("name","website","phone_number","address","main_location_id") VALUES ( + record.name, record.website, record.phone_number, record.address, Null -- Not re-implemented yet ) - RETURNING id INTO org_id; + RETURNING "id" INTO org_id; ELSE UPDATE organization SET "website" = record.website, "phone_number" = record.phone_number, "address" = record.address, "main_location_id" = Null -- Not re-implemented yet - WHERE id = org_id - RETURNING id INTO org_id; + WHERE id = org_id; END IF; RETURN org_id; END; +$function$; + diff --git a/fertiscan/db/bytebase/update_inspection/upsert_organization_info.sql b/fertiscan/db/bytebase/update_inspection/upsert_organization_info.sql index a7d94e91..fb941dea 100644 --- a/fertiscan/db/bytebase/update_inspection/upsert_organization_info.sql +++ b/fertiscan/db/bytebase/update_inspection/upsert_organization_info.sql @@ -1,19 +1,22 @@ - -- 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) -RETURNS void AS $$ +RETURNS jsonb AS $$ DECLARE record jsonb; address_str TEXT; location_id uuid; + new_id uuid; + index INT; + result jsonb; BEGIN - + index := 0; + result := input_org_info; -- loop each orgs in the input_org_info for record in SELECT * FROM jsonb_array_elements(input_org_info) loop if record->>'id' IS NULL THEN - PERFORM new_organization_info_located( + new_id := new_organization_information( record->>'name', record->>'address', record->>'website', @@ -22,6 +25,8 @@ BEGIN label_info_id, (record->>'is_main_contact')::boolean ); + -- add ids to the jsonb + result := jsonb_set(result, array[index::text,'id'], to_jsonb(new_id)); else -- UPDATE THE ORGANIZATION INFORMATION UPDATE organization_information SET @@ -31,8 +36,10 @@ BEGIN "address" = address_str, "edited" = (record->>'edited')::boolean, "is_main_contact" = (record->>'is_main_contact')::boolean - WHERE "id" = record->>'id'; + WHERE id = (record->>'id')::UUID; end if; + index := index + 1; END LOOP; +RETURN result; END; $$ LANGUAGE plpgsql; diff --git a/fertiscan/db/bytebase/update_inspection_function.sql b/fertiscan/db/bytebase/update_inspection_function.sql index cd030ada..7d38f5ef 100644 --- a/fertiscan/db/bytebase/update_inspection_function.sql +++ b/fertiscan/db/bytebase/update_inspection_function.sql @@ -318,67 +318,6 @@ BEFORE INSERT ON "fertiscan_0.0.18".sub_label FOR EACH ROW EXECUTE FUNCTION "fertiscan_0.0.18".check_null_or_empty_sub_label(); - --- Function to update sub labels: delete old and insert new -CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".update_sub_labels( - p_label_id uuid, - new_sub_labels jsonb -) -RETURNS void AS $$ -DECLARE - sub_type_rec RECORD; - fr_values jsonb; - en_values jsonb; - i int; - max_length int; - fr_value text; - en_value text; -BEGIN - -- Delete existing sub labels for the given label_id - DELETE FROM sub_label WHERE label_id = p_label_id; - - -- Loop through each sub_type - FOR sub_type_rec IN SELECT id, type_en FROM sub_type - LOOP - -- Extract the French and English arrays for the current sub_type - fr_values := COALESCE(new_sub_labels->sub_type_rec.type_en->'fr', '[]'::jsonb); - en_values := COALESCE(new_sub_labels->sub_type_rec.type_en->'en', '[]'::jsonb); - - -- Determine the maximum length of the arrays - max_length := GREATEST( - jsonb_array_length(fr_values), - jsonb_array_length(en_values) - ); - - -- Check if lengths are not equal, and raise a notice - IF jsonb_array_length(en_values) != jsonb_array_length(fr_values) THEN - RAISE NOTICE 'Array length mismatch for sub_type: %, EN length: %, FR length: %', - sub_type_rec.type_en, jsonb_array_length(en_values), jsonb_array_length(fr_values); - END IF; - - -- Loop through the indices up to the maximum length - FOR i IN 0..(max_length - 1) - LOOP - -- Extract values or set to empty string if not present - fr_value := fr_values->>i; - en_value := en_values->>i; - - -- Insert sub label record - INSERT INTO sub_label ( - text_content_fr, text_content_en, label_id, edited, sub_type_id - ) - VALUES ( - fr_value, - en_value, - p_label_id, - NULL, -- not handled - sub_type_rec.id - ); - END LOOP; - END LOOP; -END; -$$ LANGUAGE plpgsql; - Drop FUNCTION IF EXISTS "fertiscan_0.0.18".upsert_inspection; -- Function to upsert inspection information CREATE OR REPLACE FUNCTION "fertiscan_0.0.18".upsert_inspection( @@ -443,7 +382,7 @@ DECLARE BEGIN -- Upsert fertilizer information INSERT INTO fertilizer ( - name, registration_number, upload_date, update_at, owner_id, latest_inspection_id + name, registration_number, upload_date, update_at, main_contact_id, latest_inspection_id ) VALUES ( p_name, @@ -457,7 +396,7 @@ BEGIN SET registration_number = EXCLUDED.registration_number, update_at = CURRENT_TIMESTAMP, -- Update the update_at timestamp - owner_id = EXCLUDED.owner_id, + main_contact_id = EXCLUDED.main_contact_id, latest_inspection_id = EXCLUDED.latest_inspection_id RETURNING id INTO fertilizer_id; @@ -487,6 +426,8 @@ DECLARE registration_number text; verified_bool boolean; existing_inspector_id uuid; + registration_number_json jsonb; + organization_jsob jsonb; BEGIN -- Check if the provided inspection_id matches the one in the input JSON json_inspection_id := (p_input_json->>'inspection_id')::uuid; @@ -513,7 +454,6 @@ BEGIN -- update Label information UPDATE label_information SET - id = label_info_id_value, product_name = p_input_json->'product'->>'name', lot_number = p_input_json->'product'->>'lot_number', npk = p_input_json->'product'->>'npk', @@ -528,10 +468,12 @@ BEGIN WHERE id = label_info_id_value; updated_json := jsonb_set(updated_json, '{product,label_id}', to_jsonb(label_info_id_value)); - + -- Update ORGANIZATIONS information - PERFORM upsert_organization_info( p_input_json->'organizations', label_info_id_value); - + --PERFORM upsert_organization_info(p_input_json->'organizations', label_info_id_value); + organization_jsob := upsert_organization_info( p_input_json->'organizations', label_info_id_value); + updated_json := jsonb_set(updated_json, '{organizations}', organization_jsob); + -- Update metrics related to the label PERFORM update_metrics(label_info_id_value, p_input_json->'product'->'metrics'); @@ -552,11 +494,14 @@ BEGIN -- Update the inspection record verified_bool := (p_input_json->>'verified')::boolean; - + if verified_bool is null then + verified_bool := False; + p_input_json := jsonb_set(p_input_json,'{verified}',to_jsonb(False)); + END IF; + --raise exception 'test'; UPDATE inspection SET - id = inspection_id, label_info_id = label_info_id_value, inspector_id = p_inspector_id, sample_id = COALESCE(p_input_json->>'sample_id', NULL)::uuid, @@ -565,11 +510,11 @@ BEGIN updated_at = CURRENT_TIMESTAMP, -- Update timestamp on conflict inspection_comment = p_input_json->>'inspection_comment' WHERE - id = p_inspection_id; + id = inspection_id; -- Update the inspection ID in the output JSON - updated_json := jsonb_set(updated_json, '{inspection_id}', to_jsonb(inspection_id)); - + --updated_json := jsonb_set(updated_json, '{inspection_id}', to_jsonb(p_inspection_id)); + -- Check if the verified field is true, and upsert fertilizer if so IF verified_bool THEN fertilizer_name := p_input_json->'product'->>'name'; @@ -579,14 +524,13 @@ BEGIN if (Select count(*) from organization_information where label_id = label_info_id_value) = 0 then RAISE WARNING 'at least one Organization information is required for a verified inspection'; ELSIF (Select count(*) from organization_information where label_id = label_info_id_value) = 1 then - SELEct id,location_id into org_info_id,location_id_value from organization_information where label_id = label_info_id_value; + 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 loop if org_record.is_main_contact then org_info_id := org_record.id; - location_id_value := org_record.location_id; end if; end loop; end if; @@ -597,6 +541,7 @@ BEGIN organization_id := upsert_organization( org_info_id ); + --organizations_jsob := get_organizations_json(label_info_id_value); END IF; -- Upsert the fertilizer record diff --git a/fertiscan/db/metadata/inspection/__init__.py b/fertiscan/db/metadata/inspection/__init__.py index ce89153c..0e9c07db 100644 --- a/fertiscan/db/metadata/inspection/__init__.py +++ b/fertiscan/db/metadata/inspection/__init__.py @@ -393,7 +393,7 @@ def build_inspection_export(cursor, inspection_id) -> str: inspector_id=str(db_inspection.inspector_id), inspection_comment=db_inspection.inspection_comment, cautions=cautions, - organizations=orgs, + organizations=org_list, guaranteed_analysis=guaranteed_analysis, instructions=instructions, product=product_info, diff --git a/fertiscan/db/queries/label/__init__.py b/fertiscan/db/queries/label/__init__.py index a1cdc0ff..c534df66 100644 --- a/fertiscan/db/queries/label/__init__.py +++ b/fertiscan/db/queries/label/__init__.py @@ -158,10 +158,7 @@ def get_label_dimension(cursor, label_id): query = """ SELECT "label_id", - "company_info_id", - "company_location_id", - "manufacturer_info_id", - "manufacturer_location_id", + "organization_info_ids", "instructions_ids", "cautions_ids", "first_aid_ids", @@ -198,7 +195,7 @@ def delete_label_info(cursor:Cursor, label_id:str): - int: The number of rows affected by the query. (should be at least one) """ query = """ - DELETE FROM label_information WHERE id = %s CASCADE; + DELETE FROM label_information WHERE id = %s; """ cursor.execute(query, (label_id,)) return cursor.rowcount diff --git a/fertiscan/db/queries/organization/__init__.py b/fertiscan/db/queries/organization/__init__.py index 271017bf..327c3222 100644 --- a/fertiscan/db/queries/organization/__init__.py +++ b/fertiscan/db/queries/organization/__init__.py @@ -51,7 +51,7 @@ def new_organization(cursor: Cursor, name, website, phone_number, address): address ) VALUES - (%s, %s) + (%s, %s, %s, %s) RETURNING id """ @@ -83,7 +83,7 @@ def new_organization_information( if label_id is None: raise OrganizationInformationCreationError("Label ID is required for organization information creation.") query = """ - SELECT new_organization_info_located(%s, %s, %s, %s); + SELECT new_organization_information(%s, %s, %s, %s, %s, %s, %s); """ cursor.execute( query, @@ -118,7 +118,7 @@ def get_organization_info(cursor: Cursor, information_id): name, website, phone_number, - location_id, + address, label_id, edited, is_main_contact @@ -150,7 +150,7 @@ def get_organizations_info_label(cursor: Cursor, label_id: UUID): name, website, phone_number, - location_id, + address, edited, is_main_contact FROM @@ -158,11 +158,11 @@ def get_organizations_info_label(cursor: Cursor, label_id: UUID): WHERE label_id = %s """ - cursor.execute(query, (label_id,)) + cursor.execute(query, (str(label_id),)) if result := cursor.fetchall(): return result raise OrganizationInformationNotFoundError( - "Organization information not found with label_id: " + label_id + "Organization information not found with label_id: " + str(label_id) ) @@ -183,17 +183,11 @@ def get_organizations_info_json(cursor: Cursor, label_id: UUID) -> dict: """ cursor.execute(query, (str(label_id),)) - res = cursor.fetchone() - if res is None or res[0] is None: - # raise OrganizationNotFoundError - # There might not be any organization information - return {} - if len(res[0]) == 2: - return {**res[0][0], **res[0][1]} - elif len(res[0]) == 1: - return res[0][0] - else: - return {} + if res := cursor.fetchone(): + return res[0] + raise OrganizationInformationRetrievalError( + "Failed to get Registration Numbers with the given label_id. No data returned." + ) def get_organization_json(cursor: Cursor, fertilizer_id: UUID) -> dict: """ @@ -225,7 +219,7 @@ def get_organization_json(cursor: Cursor, fertilizer_id: UUID) -> dict: @handle_query_errors(OrganizationUpdateError) -def update_organization(cursor: Cursor, organization_id, information_id, location_id): +def upsert_organization(cursor: Cursor, information_id): """ This function update a organization in the database. @@ -241,28 +235,23 @@ def update_organization(cursor: Cursor, organization_id, information_id, locatio - str: The UUID of the organization """ query = """ - UPDATE - organization - SET - information_id = COALESCE(%s,information_id), - main_location_id = COALESCE(%s,main_location_id) - WHERE - id = %s + SELECT upsert_organization(%s) """ cursor.execute( query, ( information_id, - location_id, - organization_id, ), ) - return organization_id + if result := cursor.fetchone(): + return result[0] + raise OrganizationUpdateError("Failed to update Organization. No data returned.") + @handle_query_errors(OrganizationInformationUpdateError) def update_organization_info( - cursor: Cursor, information_id, name, website, phone_number + cursor: Cursor, information_id:UUID, name, website, phone_number ): """ This function update a organization information in the database. @@ -293,7 +282,7 @@ def update_organization_info( name, website, phone_number, - information_id, + str(information_id), ), ) return information_id @@ -307,12 +296,12 @@ def upsert_organization_info(cursor: Cursor, organization_info, label_id: UUID): - organization_info (JSON: string): The organization information in a json. Returns: - - str: The UUID of the organization information + - json: The array of the organization information """ query = """ SELECT upsert_organization_info(%s, %s); """ - cursor.execute(query, (organization_info, label_id,)) + cursor.execute(query, (organization_info, str(label_id),)) return cursor.fetchone()[0] def upsert_organization(cursor: Cursor, organization_info_id: UUID): @@ -327,14 +316,14 @@ def upsert_organization(cursor: Cursor, organization_info_id: UUID): - str: The UUID of the organization information """ query = """ - SELECT upsert_organization(%s, %s); + SELECT upsert_organization(%s); """ - cursor.execute(query, ( organization_info_id,)) + cursor.execute(query, ( str(organization_info_id),)) return cursor.fetchone()[0] @handle_query_errors(OrganizationRetrievalError) -def get_organization(cursor: Cursor, organization_id): +def get_organization(cursor: Cursor, organization_id:UUID): """ This function get a organization from the database. @@ -350,13 +339,13 @@ def get_organization(cursor: Cursor, organization_id): name, website, phone_number, - address, + address FROM organization WHERE id = %s """ - cursor.execute(query, (organization_id,)) + cursor.execute(query, (str(organization_id),)) if result := cursor.fetchone(): return result raise OrganizationNotFoundError( @@ -436,7 +425,7 @@ def new_location(cursor: Cursor, name, address, region_id, org_id=None): name, address, region_id, - owner_id + organization_id ) VALUES (%s, %s, %s, %s) @@ -474,7 +463,7 @@ def get_location(cursor: Cursor, location_id): name, address, region_id, - owner_id + organization_id FROM location WHERE diff --git a/fertiscan/db/queries/sub_label/__init__.py b/fertiscan/db/queries/sub_label/__init__.py index d5e4a572..52a04f27 100644 --- a/fertiscan/db/queries/sub_label/__init__.py +++ b/fertiscan/db/queries/sub_label/__init__.py @@ -225,6 +225,25 @@ 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, label_id): + """ + This function updates the sub label in the database. + + 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. + + Returns: + - None + """ + query = """ + SELECT update_sub_label(%s, %s, %s, %s); + """ + cursor.execute(query, (sub_label_id, text_fr, text_en, edited)) + @handle_query_errors(SubTypeCreationError) def new_sub_type(cursor: Cursor, type_fr, type_en): diff --git a/tests/fertiscan/analyse.json b/tests/fertiscan/analyse.json index 0fa387d7..f7cc8b58 100644 --- a/tests/fertiscan/analyse.json +++ b/tests/fertiscan/analyse.json @@ -1,5 +1,5 @@ { - "organization":[ + "organizations":[ { "name":"GreenGrow Fertilizers Inc.", "address":"123 Greenway Blvd, Springfield IL 62701 USA", diff --git a/tests/fertiscan/db/delete_inspection/test_delete_organization_info.py b/tests/fertiscan/db/archive/archived_test_delete_organization_info.py similarity index 98% rename from tests/fertiscan/db/delete_inspection/test_delete_organization_info.py rename to tests/fertiscan/db/archive/archived_test_delete_organization_info.py index 646e5d8b..b9ce46ab 100644 --- a/tests/fertiscan/db/delete_inspection/test_delete_organization_info.py +++ b/tests/fertiscan/db/archive/archived_test_delete_organization_info.py @@ -7,7 +7,7 @@ load_dotenv() # Database connection and schema settings -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if not DB_CONNECTION_STRING: raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/delete_inspection/test_delete_inspection.py b/tests/fertiscan/db/delete_inspection/test_delete_inspection.py index 711a6ac8..35df6c3a 100644 --- a/tests/fertiscan/db/delete_inspection/test_delete_inspection.py +++ b/tests/fertiscan/db/delete_inspection/test_delete_inspection.py @@ -8,7 +8,7 @@ load_dotenv() -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if not DB_CONNECTION_STRING: raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/delete_inspection/test_delete_inspection_python.py b/tests/fertiscan/db/delete_inspection/test_delete_inspection_python.py index 3fced05b..dab21482 100644 --- a/tests/fertiscan/db/delete_inspection/test_delete_inspection_python.py +++ b/tests/fertiscan/db/delete_inspection/test_delete_inspection_python.py @@ -14,7 +14,7 @@ load_dotenv() # Constants for test configuration -TEST_DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +TEST_DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if not TEST_DB_CONNECTION_STRING: raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/test_guaranteed_analysis.py b/tests/fertiscan/db/test_guaranteed_analysis.py index 397b767a..7df2c3ee 100644 --- a/tests/fertiscan/db/test_guaranteed_analysis.py +++ b/tests/fertiscan/db/test_guaranteed_analysis.py @@ -12,7 +12,7 @@ from fertiscan.db.queries import errors as e from fertiscan.db.queries import label, nutrients -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/test_ingredient.py b/tests/fertiscan/db/test_ingredient.py index 83bf22a2..2552d0fe 100644 --- a/tests/fertiscan/db/test_ingredient.py +++ b/tests/fertiscan/db/test_ingredient.py @@ -10,7 +10,7 @@ from datastore.db.metadata import validator from fertiscan.db.queries import ingredient, label -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/test_inspection.py b/tests/fertiscan/db/test_inspection.py index cf1dfaf1..6e8f0070 100644 --- a/tests/fertiscan/db/test_inspection.py +++ b/tests/fertiscan/db/test_inspection.py @@ -11,7 +11,7 @@ from datastore.db.queries import picture, user from fertiscan.db.queries import inspection -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/test_label.py b/tests/fertiscan/db/test_label.py index 80ddec9e..88108813 100644 --- a/tests/fertiscan/db/test_label.py +++ b/tests/fertiscan/db/test_label.py @@ -6,7 +6,7 @@ from datastore.db.metadata import validator from fertiscan.db.queries import label -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/test_metric.py b/tests/fertiscan/db/test_metric.py index 3e38beb1..5a0339d2 100644 --- a/tests/fertiscan/db/test_metric.py +++ b/tests/fertiscan/db/test_metric.py @@ -10,7 +10,7 @@ from datastore.db.metadata import validator from fertiscan.db.queries import label, metric -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/test_organization.py b/tests/fertiscan/db/test_organization.py index d9d41450..85171fa8 100644 --- a/tests/fertiscan/db/test_organization.py +++ b/tests/fertiscan/db/test_organization.py @@ -7,12 +7,13 @@ import unittest import uuid +import json import datastore.db as db from datastore.db.metadata import validator from fertiscan.db.metadata.inspection import OrganizationInformation from fertiscan.db.queries import label, organization -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") @@ -104,6 +105,8 @@ def setUp(self): self.cursor = self.con.cursor() db.create_search_path(self.con, self.cursor, DB_SCHEMA) + self.owner_id = organization.new_organization(cursor=self.cursor, name="test-owner", website="www.test.com", phone_number="123456789", address="test-address") + self.province_name = "test-province" self.region_name = "test-region" self.name = "test-location" @@ -119,34 +122,35 @@ def tearDown(self): def test_new_location(self): location_id = organization.new_location( - self.cursor, self.name, self.address, self.region_id + self.cursor, self.name, self.address, self.region_id,self.owner_id ) self.assertTrue(validator.is_valid_uuid(location_id)) def test_get_location(self): location_id = organization.new_location( - self.cursor, self.name, self.address, self.region_id + self.cursor, self.name, self.address, self.region_id,self.owner_id ) location_data = organization.get_location(self.cursor, location_id) self.assertEqual(location_data[0], self.name) + self.assertEqual(location_data[1], self.address) self.assertEqual(location_data[2], self.region_id) - self.assertIsNone(location_data[3]) + self.assertEqual(location_data[3], self.owner_id) def test_get_location_not_found(self): with self.assertRaises(organization.LocationNotFoundError): organization.get_location(self.cursor, str(uuid.uuid4())) - def test_get_full_location(self): - location_id = organization.new_location( - self.cursor, self.name, self.address, self.region_id - ) - location_data = organization.get_full_location(self.cursor, location_id) - self.assertEqual(location_data[0], location_id) - self.assertEqual(location_data[1], self.name) - self.assertEqual(location_data[2], self.address) - self.assertEqual(location_data[3], self.region_name) - self.assertEqual(location_data[4], self.province_name) + # def test_get_full_location(self): + # location_id = organization.new_location( + # self.cursor, self.name, self.address, self.region_id,self.owner_id + # ) + # location_data = organization.get_full_location(self.cursor, location_id) + # self.assertEqual(location_data[0], location_id) + # self.assertEqual(location_data[1], self.name) + # self.assertEqual(location_data[2], self.address) + # self.assertEqual(location_data[3], self.region_name) + # self.assertEqual(location_data[4], self.province_name) def get_location_by_region(self): location_id = organization.new_location( @@ -199,53 +203,42 @@ def setUp(self): self.record_keeping, ) + def tearDown(self): self.con.rollback() db.end_query(self.con, self.cursor) - def test_new_organization_information(self): - id = organization.new_organization_information( - self.cursor, self.address, self.name, self.website, self.phone, self.label_information_id, False, True - ) - self.assertTrue(validator.is_valid_uuid(id)) - - def test_new_organization_located(self): + def test_new_organization_information_with_address(self): id = organization.new_organization_information( self.cursor, self.address, self.name, self.website, self.phone, self.label_information_id, False, True ) self.assertTrue(validator.is_valid_uuid(id)) - def test_new_organization_info_no_location(self): + def test_new_organization_info_no_address(self): id = organization.new_organization_information( - self.cursor, self.name, self.website, self.phone, None, self.label_information_id, True + cursor=self.cursor, address=None, name=self.name, website=self.website, phone_number=self.phone, label_id=self.label_information_id, edited=False,is_main_contact=True ) self.assertTrue(validator.is_valid_uuid(id)) - def test_new_organization_located_empty(self): + def test_new_organization_empty(self): with self.assertRaises(organization.OrganizationInformationCreationError): - organization.new_organization_info_located( - self.cursor, None, None, None, None, None + organization.new_organization( + self.cursor, None, None, None, None ) - def test_new_organization_located_no_address(self): - org_id = organization.new_organization_info_located( - self.cursor, None, self.name, self.website, self.phone, self.label_information_id - ) - # Making sure that a location is not created - query = "SELECT location_id FROM organization_information WHERE id = %s" - self.cursor.execute(query, (org_id,)) - location_id = self.cursor.fetchone()[0] - self.assertIsNone(location_id) - def test_get_organization_info(self): id = organization.new_organization_information( - self.cursor, self.name, self.website, self.phone, self.location_id + self.cursor, self.address, self.name, self.website, self.phone, self.label_information_id, False, True ) data = organization.get_organization_info(self.cursor, id) self.assertEqual(data[0], self.name) self.assertEqual(data[1], self.website) self.assertEqual(data[2], self.phone) - self.assertEqual(data[3], self.location_id) + self.assertEqual(data[3], self.address) + self.assertEqual(data[4], self.label_information_id) + self.assertEqual(data[5], False) + self.assertEqual(data[6], True) + def test_get_organization_info_not_found(self): with self.assertRaises(organization.OrganizationInformationNotFoundError): @@ -253,26 +246,26 @@ def test_get_organization_info_not_found(self): def test_get_organization_info_label(self): organization.new_organization_information( - self.cursor, self.name, self.website, self.phone, label_id=self.label_information_id + self.cursor, self.address, self.name, self.website, self.phone, self.label_information_id, False, True ) - data = organization.get_organizations_info_label(self.cursor, self.label_id) - self.assertEqual(data[0], self.name) - self.assertEqual(data[1], self.website) - self.assertEqual(data[2], self.phone) - self.assertEqual(data[3], self.location_id) + data = organization.get_organizations_info_label(self.cursor, self.label_information_id) + self.assertEqual(data[0][0], self.name) + self.assertEqual(data[0][1], self.website) + self.assertEqual(data[0][2], self.phone) + self.assertEqual(data[0][3], self.address) def test_update_organization_info(self): new_name = "new-name" new_website = "www.new.com" new_phone = "987654321" id = organization.new_organization_information( - self.cursor, self.name, self.website, self.phone, self.label_information_id + self.cursor, self.address, self.name, self.website, self.phone, self.label_information_id, False, True ) 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.location_id) + self.assertEqual(old_data[3], self.address) organization.update_organization_info( self.cursor, id, new_name, new_website, new_phone ) @@ -281,11 +274,11 @@ def test_update_organization_info(self): self.assertEqual(data[1], new_website) self.assertEqual(data[2], new_phone) - def test_new_organization_info_located(self): - id = organization.new_organization_info_located( - self.cursor, - address=self.location_address, - name=self.location_name, + def test_new_organization_information(self): + id = organization.new_organization_information( + cursor=self.cursor, + address=self.address, + name=self.name, website=self.website, phone_number=self.phone, label_id=self.label_information_id @@ -293,30 +286,30 @@ def test_new_organization_info_located(self): self.assertTrue(validator.is_valid_uuid(id)) def test_get_organizations_info_json(self): - company_id = organization.new_organization_info_located( + company_id = organization.new_organization_information( self.cursor, - address=self.location_address, - name=self.location_name, + address=self.address, + name=self.name, website=self.website, phone_number=self.phone, label_id=self.label_information_id ) - manufacturer_id = organization.new_organization_info_located( + manufacturer_id = organization.new_organization_information( self.cursor, - address=self.location_address, - name=self.location_name, + address=self.address, + name=self.name, website=self.website, phone_number=self.phone, label_id=self.label_information_id ) data = organization.get_organizations_info_json(self.cursor, self.label_information_id) - self.assertEqual(len(data["organization"]), 2) - self.assertEqual(data["organization"][0]["id"], str(company_id)) - self.assertEqual(data["organization"][1]["id"], str(manufacturer_id)) + self.assertEqual(len(data["organizations"]), 2) + self.assertEqual(data["organizations"][0]["id"], str(company_id)) + self.assertEqual(data["organizations"][1]["id"], str(manufacturer_id)) def test_get_organizations_info_json_not_found(self): data = organization.get_organizations_info_json(self.cursor, self.label_information_id) - self.assertDictEqual(data, {"organization": []}) + self.assertDictEqual(data, {"organizations": []}) def test_upsert_organizations_info(self): new_name = "new-name" @@ -328,83 +321,59 @@ def test_upsert_organizations_info(self): name=self.name, website=self.website, phone_number=self.phone, - address=self.location_address + address=self.address, + edited=False, + is_main_contact=True ).model_dump_json() + old_org = json.dumps([old_org]) + + organizations_dict = {"organizations": [{"name": self.name, "website": self.website, "phone_number": self.phone, "address": self.address,"edited": True,"is_main_contact": True}]} + # Test inserting a new organization information - initial_data = organization.get_organizations_info_label(self.cursor, self.label_information_id) - self.assertIsNone(initial_data) - organization.upsert_organization_info(self.cursor, old_org, self.label_information_id) + self.assertRaises(organization.OrganizationInformationNotFoundError, organization.get_organizations_info_label, self.cursor, self.label_information_id) + received_data = organization.upsert_organization_info(self.cursor, json.dumps(organizations_dict["organizations"]), self.label_information_id) upserted_data = organization.get_organizations_info_label(self.cursor, self.label_information_id) self.assertIsNotNone(upserted_data) + self.assertIsNotNone(received_data[0]["name"]) + self.assertIsNotNone(received_data[0]["id"]) self.assertEqual(len(upserted_data), 1) - self.assertEqual(upserted_data[0], self.name) + self.assertEqual(upserted_data[0][0], self.name) # Test updating an existing organization information - old_org["name"] = new_name - old_org["website"] = new_website - old_org["phone_number"] = new_phone - old_org["address"] = new_address + received_data[0]["name"] = new_name + received_data[0]["website"] = new_website + received_data[0]["phone_number"] = new_phone + received_data[0]["address"] = new_address - organization.upsert_organization_info(self.cursor, old_org, self.label_information_id) + organization.upsert_organization_info(self.cursor, json.dumps(received_data), self.label_information_id) new_data = organization.get_organizations_info_label(self.cursor, self.label_information_id) self.assertIsNotNone(new_data) self.assertEqual(len(new_data), 1) - self.assertEqual(new_data[0], new_name) - self.assertEqual(new_data[1], new_website) - self.assertEqual(new_data[2], new_phone) - self.assertNotEqual(new_data[3], upserted_data[3]) # Address should be updated therefore the id must have changed + self.assertEqual(new_data[0][0], new_name) + self.assertEqual(new_data[0][1], new_website) + self.assertEqual(new_data[0][2], new_phone) + self.assertNotEqual(new_data[0][3], upserted_data[0][3]) # Address should be updated therefore the id must have changed - def test_delete_label_with_linked_manufacturer(self): + def test_delete_label_with_linked_organization_information(self): # create a organization information organization_id = organization.new_organization_information( - self.cursor, self.name, self.website, self.phone, self.label_information_id + self.cursor,self.address, self.name, self.website, self.phone, self.label_information_id,False,True ) - label_info = label.get_label_info_json(self.cursor, self.label_information_id) + label_info = label.get_label_information_json(self.cursor, self.label_information_id) # Attempt to delete the inspection, which should raise a notice but not fail - self.cursor.execute( - "SELECT delete_inspection(%s, %s);", - (self.inspection_id, self.inspector_id), - ) - - # Ensure that the inspection and label were deleted - self.cursor.execute( - "SELECT COUNT(*) FROM inspection WHERE id = %s;", - (self.inspection_id,), - ) - inspection_count = self.cursor.fetchone()[0] - self.assertEqual(inspection_count, 0, "Inspection should be deleted.") - - self.cursor.execute( - "SELECT COUNT(*) FROM label_information WHERE id = %s;", - (self.label_info_id,), - ) - label_count = self.cursor.fetchone()[0] - self.assertEqual(label_count, 0, "Label information should be deleted.") + deleted_rows = label.delete_label_info(self.cursor, self.label_information_id) + self.assertGreaterEqual(deleted_rows,1) - # Ensure that the manufacturer info was not deleted due to foreign key constraints self.cursor.execute( "SELECT COUNT(*) FROM organization_information WHERE id = %s;", - (self.manufacturer_info_id,), + (organization_id,), ) - manufacturer_count = self.cursor.fetchone()[0] + org_count = self.cursor.fetchone()[0] self.assertEqual( - manufacturer_count, - 1, - "Manufacturer info should not be deleted due to foreign key constraint.", - ) - - # Ensure that the company info related to the deleted inspection is deleted - self.cursor.execute( - "SELECT COUNT(*) FROM organization_information WHERE id = %s;", - (self.company_info_id,), - ) - company_count = self.cursor.fetchone()[0] - self.assertEqual( - company_count, + org_count, 0, - "Company info should be deleted since it's linked to the deleted inspection.", - ) + "Organization information should have been deleted when the label was deleted",) @@ -420,16 +389,40 @@ def setUp(self): self.website = "www.test.com" self.phone = "123456789" self.location_name = "test-location" - self.location_address = "test-address" - self.province_id = organization.new_province(self.cursor, self.province_name) - self.region_id = organization.new_region( - self.cursor, self.region_name, self.province_id - ) - self.location_id = organization.new_location( - self.cursor, self.location_name, self.location_address, self.region_id + self.address = "test-address" + + self.lot_number = "lot_number" + self.product_name = "product_name" + self.npk = "npk" + self.registration_number = "registration_number" + self.n = 10.0 + self.p = 20.0 + self.k = 30.0 + self.weight = None + self.density = None + self.volume = None + self.warranty = "warranty" + self.title_en = "title_en" + self.title_fr = "title_fr" + self.is_minimal = False + self.record_keeping = False + + 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.title_en, + self.title_fr, + self.is_minimal, + self.record_keeping, ) + self.org_info_id = organization.new_organization_information( - self.cursor, self.name, self.website, self.phone, self.location_id + self.cursor, self.address, self.name, self.website, self.phone, self.label_information_id, False, True ) def tearDown(self): @@ -438,49 +431,41 @@ def tearDown(self): def test_new_organization(self): organization_id = organization.new_organization( - self.cursor, self.org_info_id, self.location_id + self.cursor, self.name, self.website, self.phone, self.address ) self.assertTrue(validator.is_valid_uuid(organization_id)) def test_new_organization_no_location(self): - organization_id = organization.new_organization(self.cursor, self.org_info_id) + organization_id = organization.new_organization( + self.cursor, self.name, self.website, self.phone, None + ) self.assertTrue(validator.is_valid_uuid(organization_id)) - def test_update_organization(self): + def test_upsert_organization(self): + organization_id = organization.new_organization( - self.cursor, self.org_info_id, self.location_id - ) - new_location_id = organization.new_location( - self.cursor, "new-location", "new-address", self.region_id + self.cursor, self.name, "wrong-website", "wrong-phone", "wrong-address" ) - organization.update_organization( - self.cursor, organization_id, self.org_info_id, new_location_id + update_id = organization.upsert_organization( + self.cursor, str(self.org_info_id) ) - organization_data = organization.get_organization(self.cursor, organization_id) - self.assertEqual(organization_data[0], self.org_info_id) - self.assertEqual(organization_data[1], new_location_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_get_organization(self): organization_id = organization.new_organization( - self.cursor, self.org_info_id, self.location_id + self.cursor, self.name, self.website, self.phone, self.address ) organization_data = organization.get_organization(self.cursor, organization_id) - self.assertEqual(organization_data[0], self.org_info_id) - self.assertEqual(organization_data[1], self.location_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_get_organization_not_found(self): with self.assertRaises(organization.OrganizationNotFoundError): organization.get_organization(self.cursor, str(uuid.uuid4())) - - def test_get_full_organization(self): - organization_id = organization.new_organization( - self.cursor, self.org_info_id, self.location_id - ) - organization_data = organization.get_full_organization( - self.cursor, organization_id - ) - self.assertEqual(organization_data[0], organization_id) - self.assertEqual(organization_data[1], self.name) - self.assertEqual(organization_data[5], self.location_name) - self.assertEqual(organization_data[8], self.region_name) - self.assertEqual(organization_data[10], self.province_name) diff --git a/tests/fertiscan/db/test_registration_number.py b/tests/fertiscan/db/test_registration_number.py index 4e9ecc3c..88ffc312 100644 --- a/tests/fertiscan/db/test_registration_number.py +++ b/tests/fertiscan/db/test_registration_number.py @@ -12,7 +12,7 @@ from fertiscan.db.metadata.inspection import RegistrationNumber from fertiscan.db.queries import label, registration_number -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/test_sub_label.py b/tests/fertiscan/db/test_sub_label.py index 81d75c36..fbe04e40 100644 --- a/tests/fertiscan/db/test_sub_label.py +++ b/tests/fertiscan/db/test_sub_label.py @@ -11,7 +11,7 @@ from datastore.db.metadata import validator from fertiscan.db.queries import label, sub_label -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/update_inspection/test_upsert_location.py b/tests/fertiscan/db/update_inspection/archived_test_upsert_location.py similarity index 97% rename from tests/fertiscan/db/update_inspection/test_upsert_location.py rename to tests/fertiscan/db/update_inspection/archived_test_upsert_location.py index 0329d887..6fcdc9dd 100644 --- a/tests/fertiscan/db/update_inspection/test_upsert_location.py +++ b/tests/fertiscan/db/update_inspection/archived_test_upsert_location.py @@ -4,10 +4,12 @@ import psycopg from dotenv import load_dotenv +from fertiscan.db.queries import organization + load_dotenv() # Fetch database connection URL and schema from environment variables -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") diff --git a/tests/fertiscan/db/update_inspection/test_update_guaranteed.py b/tests/fertiscan/db/update_inspection/test_update_guaranteed.py index 732623b1..b0b7ed41 100644 --- a/tests/fertiscan/db/update_inspection/test_update_guaranteed.py +++ b/tests/fertiscan/db/update_inspection/test_update_guaranteed.py @@ -5,6 +5,7 @@ import psycopg from dotenv import load_dotenv +import datastore.db.__init__ as db import fertiscan.db.queries.label as label import fertiscan.db.queries.nutrients as guaranteed from fertiscan.db.metadata.inspection import GuaranteedAnalysis @@ -12,7 +13,7 @@ load_dotenv() # Fetch database connection URL and schema from environment variables -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") @@ -24,11 +25,22 @@ class TestUpdateGuaranteedFunction(unittest.TestCase): def setUp(self): # Connect to the PostgreSQL database with the specified schema - self.conn = psycopg.connect( - DB_CONNECTION_STRING, options=f"-c search_path={DB_SCHEMA},public" - ) - self.conn.autocommit = False # Ensure transaction is managed manually - self.cursor = self.conn.cursor() + self.conn = db.connect_db(DB_CONNECTION_STRING, DB_SCHEMA) + self.cursor = db.cursor(self.conn) + db.create_search_path(self.conn, self.cursor, DB_SCHEMA) + + self.label_id = label.new_label_information( + cursor=self.cursor, + name="test-label", + lot_number=None, + npk=None, + n=None, + p=None, + k=None, + title_en=None, + title_fr=None, + is_minimal=False, + record_keeping=False,) # Set up test data for guaranteed analysis with open("tests/fertiscan/inspection_export.json") as f: @@ -94,8 +106,7 @@ def setUp(self): def tearDown(self): # Rollback any changes to leave the database state as it was before the test self.conn.rollback() - self.cursor.close() - self.conn.close() + db.end_query(self.conn, self.cursor) def test_update_guaranteed(self): # Insert initial guaranteed analysis diff --git a/tests/fertiscan/db/update_inspection/test_update_ingredients.py b/tests/fertiscan/db/update_inspection/test_update_ingredients.py index 725291a5..540c0072 100644 --- a/tests/fertiscan/db/update_inspection/test_update_ingredients.py +++ b/tests/fertiscan/db/update_inspection/test_update_ingredients.py @@ -5,12 +5,13 @@ import psycopg from dotenv import load_dotenv +import datastore.db.__init__ as db import fertiscan.db.queries.label as label load_dotenv() # Fetch database connection URL and schema from environment variables -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") @@ -21,12 +22,23 @@ class TestUpdateIngredientsFunction(unittest.TestCase): def setUp(self): - # Connect to the PostgreSQL database with the specified schema - self.conn = psycopg.connect( - DB_CONNECTION_STRING, options=f"-c search_path={DB_SCHEMA},public" - ) - self.conn.autocommit = False # Ensure transaction is managed manually - self.cursor = self.conn.cursor() + # Connect to the PostgreSQL database with the specified schema + self.conn = db.connect_db(DB_CONNECTION_STRING, DB_SCHEMA) + self.cursor = db.cursor(self.conn) + db.create_search_path(self.conn, self.cursor, DB_SCHEMA) + + self.label_id = label.new_label_information( + cursor=self.cursor, + name="test-label", + lot_number=None, + npk=None, + n=None, + p=None, + k=None, + title_en=None, + title_fr=None, + is_minimal=False, + record_keeping=False,) # Set up test data for ingredients self.sample_organic_ingredients = json.dumps( @@ -87,8 +99,7 @@ def setUp(self): def tearDown(self): # Rollback any changes to leave the database state as it was before the test self.conn.rollback() - self.cursor.close() - self.conn.close() + db.end_query(self.conn, self.cursor) def test_update_organic_ingredients(self): # Insert initial organic ingredients diff --git a/tests/fertiscan/db/update_inspection/test_update_inspection.py b/tests/fertiscan/db/update_inspection/test_update_inspection.py index 2ccc9690..94c5b48a 100644 --- a/tests/fertiscan/db/update_inspection/test_update_inspection.py +++ b/tests/fertiscan/db/update_inspection/test_update_inspection.py @@ -5,17 +5,21 @@ import psycopg from dotenv import load_dotenv +import datastore.db.__init__ as db +from datastore.db.metadata import picture_set, validator +from datastore.db.queries import user,picture +from fertiscan.db.queries import label, inspection from fertiscan.db.metadata.inspection import ( DBInspection, Inspection, OrganizationInformation, ) from fertiscan.db.queries.inspection import get_inspection_dict, update_inspection - +from fertiscan.db.queries import organization load_dotenv() # Database connection and schema settings -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if not DB_CONNECTION_STRING: raise ValueError("FERTISCAN_DB_URL is not set") @@ -23,30 +27,36 @@ if not DB_SCHEMA: raise ValueError("FERTISCAN_SCHEMA_TESTING is not set") -INPUT_JSON_PATH = "tests/fertiscan/inspection_export.json" +INPUT_JSON_PATH = "tests/fertiscan/inspection.json" class TestUpdateInspectionFunction(unittest.TestCase): def setUp(self): - # Set up database connection and cursor - self.conn = psycopg.connect( - DB_CONNECTION_STRING, options=f"-c search_path={DB_SCHEMA},public" - ) - self.conn.autocommit = False # Control transaction manually - self.cursor = self.conn.cursor() - - # Create users for the test - self.cursor.execute( - """ - INSERT INTO users (email) - VALUES (%s) - ON CONFLICT (email) DO UPDATE - SET email = EXCLUDED.email - RETURNING id; - """, - ("inspector@example.com",), - ) - self.inspector_id = self.cursor.fetchone()[0] + # Connect to the PostgreSQL database with the specified schema + self.conn = db.connect_db(DB_CONNECTION_STRING, DB_SCHEMA) + self.cursor = db.cursor(self.conn) + db.create_search_path(self.conn, self.cursor, DB_SCHEMA) + + self.user_email = "test-update-inspection@email" + self.inspector_id = user.register_user(self.cursor, self.user_email) + self.folder_name = "test-folder" + self.picture_set = picture_set.build_picture_set_metadata(self.inspector_id, 1) + self.picture_set_id = picture.new_picture_set( + self.cursor, self.picture_set, self.inspector_id, self.folder_name + ) + + self.F = label.new_label_information( + cursor=self.cursor, + name="test-label", + lot_number=None, + npk=None, + n=None, + p=None, + k=None, + title_en=None, + title_fr=None, + is_minimal=False, + record_keeping=False,) self.cursor.execute( "INSERT INTO users (email) VALUES ('other_user@example.com') RETURNING id;" @@ -58,6 +68,7 @@ def setUp(self): create_input_json = json.load(file) create_input_json_str = json.dumps(create_input_json) + print(create_input_json["organizations"]) # Create initial inspection data in the database self.picture_set_id = None # No picture set ID for this test case @@ -66,16 +77,20 @@ def setUp(self): (self.inspector_id, self.picture_set_id, create_input_json_str), ) self.created_data = self.cursor.fetchone()[0] + print(self.created_data["organizations"]) self.created_inspection = Inspection.model_validate(self.created_data) + foo = organization.get_organizations_info_label(self.cursor,self.created_data["product"]["label_id"]) + print("=========") + print(foo) + print("=========") # Store the inspection ID for later use self.inspection_id = self.created_data.get("inspection_id") def tearDown(self): # Roll back any changes to maintain database state self.conn.rollback() - self.cursor.close() - self.conn.close() + db.end_query(self.conn, self.cursor) def test_update_inspection_with_verified_false(self): # Update the JSON data for testing the update function @@ -87,7 +102,7 @@ def test_update_inspection_with_verified_false(self): company_name = "Updated Company Name" # Update the inspection model fields using model-style updates - altered_inspection.company.name = company_name + altered_inspection.organizations[0].name = company_name altered_inspection.product.metrics.weight[0].value = new_value altered_inspection.product.metrics.density.value = new_value altered_inspection.guaranteed_analysis.en[0].value = new_value @@ -95,7 +110,7 @@ def test_update_inspection_with_verified_false(self): altered_inspection.inspection_comment = inspection_comment # Use the updated model for the update - update_inspection( + update_inspection_result = update_inspection( self.cursor, self.inspection_id, self.inspector_id, @@ -137,11 +152,10 @@ def test_update_inspection_with_verified_false(self): 0, "No fertilizer should be created when verified is false.", ) - # Verify the company name was updated in the database self.cursor.execute( - "SELECT name FROM organization_information WHERE id = %s;", - (self.created_data["company"]["id"],), + "SELECT name FROM organization_information where id=%s;", + (self.created_data["organizations"][0]["id"],), ) updated_company_name = self.cursor.fetchone()[0] self.assertEqual( @@ -178,7 +192,9 @@ def test_update_inspection_with_verified_false(self): "SELECT value FROM guaranteed WHERE label_id = %s AND read_name = %s;", (self.created_data["product"]["label_id"], "Total Nitrogen (N)"), ) + print(self.created_data["product"]["label_id"]) updated_nitrogen_value = self.cursor.fetchone()[0] + print(updated_nitrogen_value) self.assertEqual( updated_nitrogen_value, new_value, @@ -232,7 +248,7 @@ def test_update_inspection_with_verified_true(self): # Verify the fertilizer details are correct self.cursor.execute( - "SELECT name, registration_number, owner_id FROM fertilizer WHERE id = %s;", + "SELECT name, registration_number, main_contact_id FROM fertilizer WHERE id = %s;", (fertilizer_id,), ) fertilizer_data = self.cursor.fetchone() @@ -247,31 +263,20 @@ def test_update_inspection_with_verified_true(self): "The registration number should match the input model.", ) - # Check if the owner_id matches the organization information created for the manufacturer + # Check if the organization was created for the fertilizer self.cursor.execute( - "SELECT information_id FROM organization WHERE id = %s;", - (fertilizer_data[2],), + "SELECT id FROM organization WHERE name = %s;", + (altered_inspection.organizations[0].name,), ) - organization_information_id = self.cursor.fetchone()[0] + organization_id = self.cursor.fetchone()[0] - self.cursor.execute( - "SELECT name FROM organization_information WHERE id = %s;", - (organization_information_id,), - ) - organization_name = self.cursor.fetchone()[0] - - self.assertEqual( - organization_name, - altered_inspection.manufacturer.name, - "The organization's name should match the manufacturer's name in the input model.", - ) def test_update_inspection_unauthorized_user(self): # Update the inspection model for testing the update function altered_inspection = self.created_inspection.model_copy() # Modify the company name in the inspection model - altered_inspection.company.name = "Unauthorized Update" + altered_inspection.organizations[0].name = "Unauthorized Update" # Use a different inspector_id that is not associated with the inspection unauthorized_inspector_id = self.other_user_id @@ -285,11 +290,10 @@ def test_update_inspection_unauthorized_user(self): altered_inspection.model_dump(), ) - def test_update_inspection_with_null_company_and_manufacturer(self): + def test_update_inspection_without_organizations(self): # Update the inspection model with null company and manufacturer for testing altered_inspection = self.created_inspection.model_copy() - altered_inspection.company = None # Company is set to null - altered_inspection.manufacturer = None # Manufacturer is set to null + altered_inspection.organizations = [] # orgs is empty altered_inspection.verified = False # Ensure verified is false # Invoke the update_inspection function @@ -317,99 +321,14 @@ def test_update_inspection_with_null_company_and_manufacturer(self): # Verify that no organization record was created for the null company or manufacturer self.cursor.execute( - "SELECT COUNT(*) FROM organization WHERE information_id IS NULL;", + "SELECT COUNT(*) FROM organization WHERE name IS NULL;", ) organization_count = self.cursor.fetchone()[0] self.assertEqual( organization_count, 0, - "No organization record should be created when company or manufacturer is null.", - ) - - def test_update_inspection_with_missing_company_and_manufacturer(self): - # Update the inspection model and remove company and manufacturer fields for testing - altered_inspection = self.created_inspection.model_copy() - altered_inspection.verified = False # Ensure verified is false - - # Set company and manufacturer to None to simulate them being missing - altered_inspection.company = None - altered_inspection.manufacturer = None - - # Invoke the update_inspection function with the altered model - update_inspection( - self.cursor, - self.inspection_id, - self.inspector_id, - altered_inspection.model_dump(), - ) - - # Verify that the inspection record was updated - updated_inspection = get_inspection_dict(self.cursor, self.inspection_id) - updated_inspection = DBInspection.model_validate(updated_inspection) - - self.assertIsNotNone(updated_inspection, "The inspection record should exist.") - self.assertEqual( - updated_inspection.inspector_id, - self.inspector_id, - "The inspector ID should match the expected value.", - ) - self.assertFalse( - updated_inspection.verified, - "The verified status should be False as updated.", - ) - - # Verify that no organization record was created for the missing company or manufacturer - self.cursor.execute( - "SELECT COUNT(*) FROM organization WHERE information_id IS NULL;", + "No organization record should be created when organizations is empty.", ) - organization_count = self.cursor.fetchone()[0] - self.assertEqual( - organization_count, - 0, - "No organization record should be created when company or manufacturer is missing.", - ) - - def test_update_inspection_with_empty_company_and_manufacturer(self): - # Update the inspection model for testing with empty company and manufacturer - altered_inspection = self.created_inspection.model_copy() - altered_inspection.company = OrganizationInformation() # Empty company - altered_inspection.manufacturer = OrganizationInformation() # Empty manuf - altered_inspection.verified = False # Ensure verified is false - - # Invoke the update_inspection function - update_inspection( - self.cursor, - self.inspection_id, - self.inspector_id, - altered_inspection.model_dump(), - ) - - # Verify that the inspection record was updated - updated_inspection = get_inspection_dict(self.cursor, self.inspection_id) - updated_inspection = DBInspection.model_validate(updated_inspection) - - self.assertIsNotNone(updated_inspection, "The inspection record should exist.") - self.assertEqual( - updated_inspection.inspector_id, - self.inspector_id, - "The inspector ID should match the expected value.", - ) - self.assertFalse( - updated_inspection.verified, - "The verified status should be False as updated.", - ) - - # Verify that no organization record was created for the empty company or manufacturer - self.cursor.execute( - "SELECT COUNT(*) FROM organization WHERE information_id IS NULL;", - ) - organization_count = self.cursor.fetchone()[0] - self.assertEqual( - organization_count, - 0, - "No organization record should be created when company or manufacturer is empty.", - ) - if __name__ == "__main__": unittest.main() diff --git a/tests/fertiscan/db/update_inspection/test_update_inspection_python.py b/tests/fertiscan/db/update_inspection/test_update_inspection_python.py index ccb5f496..85a32ec4 100644 --- a/tests/fertiscan/db/update_inspection/test_update_inspection_python.py +++ b/tests/fertiscan/db/update_inspection/test_update_inspection_python.py @@ -13,7 +13,7 @@ load_dotenv() # Constants for test configuration -TEST_DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +TEST_DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if not TEST_DB_CONNECTION_STRING: raise ValueError("FERTISCAN_DB_URL is not set") @@ -76,7 +76,7 @@ def test_python_function_update_inspection_with_verified_false(self): new_value = 66.6 # Update model fields instead of dictionary keys - altered_inspection.company.name = "Updated Company Name" + altered_inspection.organizations[0].name = "Updated Company Name" altered_inspection.product.metrics.weight[0].value = new_value altered_inspection.product.metrics.density.value = new_value altered_inspection.guaranteed_analysis.en[0].value = new_value @@ -98,7 +98,7 @@ def test_python_function_update_inspection_with_verified_false(self): # Assertions using the Inspection model self.assertEqual( - updated_inspection.company.name, + updated_inspection.organizations[0].name, "Updated Company Name", "The company name should reflect the update.", ) diff --git a/tests/fertiscan/db/update_inspection/test_update_metrics.py b/tests/fertiscan/db/update_inspection/test_update_metrics.py index 001a150d..a30c07a5 100644 --- a/tests/fertiscan/db/update_inspection/test_update_metrics.py +++ b/tests/fertiscan/db/update_inspection/test_update_metrics.py @@ -4,13 +4,14 @@ import psycopg from dotenv import load_dotenv +import datastore.db.__init__ as db import fertiscan.db.queries.label as label from fertiscan.db.metadata.inspection import Metric, Metrics, OrganizationInformation load_dotenv() # Fetch database connection URL and schema from environment variables -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") @@ -20,13 +21,24 @@ class TestUpdateMetricsFunction(unittest.TestCase): - def setUp(self): + def setUp(self): # Connect to the PostgreSQL database with the specified schema - self.conn = psycopg.connect( - DB_CONNECTION_STRING, options=f"-c search_path={DB_SCHEMA},public" - ) - self.conn.autocommit = False # Ensure transaction is managed manually - self.cursor = self.conn.cursor() + self.conn = db.connect_db(DB_CONNECTION_STRING, DB_SCHEMA) + self.cursor = db.cursor(self.conn) + db.create_search_path(self.conn, self.cursor, DB_SCHEMA) + + self.label_id = label.new_label_information( + cursor=self.cursor, + name="test-label", + lot_number=None, + npk=None, + n=None, + p=None, + k=None, + title_en=None, + title_fr=None, + is_minimal=False, + record_keeping=False,) # Set up test data for metrics using Pydantic models self.sample_metrics = Metrics( @@ -41,40 +53,10 @@ def setUp(self): volume=Metric(value=25.0, unit="L"), ) - # Insert test data to obtain a valid label_id - sample_org_info = OrganizationInformation( - name="Test Company", - address="123 Test Address", - website="http://www.testcompany.com", - phone_number="+1 800 555 0123", - ) - self.cursor.execute( - "SELECT upsert_organization_info(%s);", (sample_org_info.model_dump_json(),) - ) - self.company_info_id = self.cursor.fetchone()[0] - - self.label_id = label.new_label_information( - self.cursor, - "test-label", - None, - None, - None, - None, - None, - None, - None, - None, - None, - self.company_info_id, - self.company_info_id, - None, - ) - def tearDown(self): # Rollback any changes to leave the database state as it was before the test self.conn.rollback() - self.cursor.close() - self.conn.close() + db.end_query(self.conn, self.cursor) def test_update_metrics(self): # Insert initial metrics using Pydantic model diff --git a/tests/fertiscan/db/update_inspection/test_update_sub_labels.py b/tests/fertiscan/db/update_inspection/test_update_sub_labels.py index 22162741..c471d53c 100644 --- a/tests/fertiscan/db/update_inspection/test_update_sub_labels.py +++ b/tests/fertiscan/db/update_inspection/test_update_sub_labels.py @@ -5,6 +5,7 @@ import psycopg from dotenv import load_dotenv +import datastore.db.__init__ as db import fertiscan.db.queries.sub_label as sub_label import fertiscan.db.queries.label as label from fertiscan.db.metadata.inspection import ( @@ -16,7 +17,7 @@ load_dotenv() # Fetch database connection URL and schema from environment variables -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") @@ -31,11 +32,22 @@ class TestUpdateSubLabelsFunction(unittest.TestCase): def setUp(self): # Connect to the PostgreSQL database with the specified schema - self.conn = psycopg.connect( - DB_CONNECTION_STRING, options=f"-c search_path={DB_SCHEMA},public" - ) - self.conn.autocommit = False # Ensure transaction is managed manually - self.cursor = self.conn.cursor() + self.conn = db.connect_db(DB_CONNECTION_STRING, DB_SCHEMA) + self.cursor = db.cursor(self.conn) + db.create_search_path(self.conn, self.cursor, DB_SCHEMA) + + self.label_id = label.new_label_information( + cursor=self.cursor, + name="test-label", + lot_number=None, + npk=None, + n=None, + p=None, + k=None, + title_en=None, + title_fr=None, + is_minimal=False, + record_keeping=False,) # Load and validate the inspection data from the JSON file using the Inspection model with open(TEST_INPUT_JSON_PATH) as f: @@ -90,41 +102,10 @@ def setUp(self): } self.nb_updated = 10 - # Set up organization information using the Pydantic model - sample_org_info = OrganizationInformation( - name="Test Company", - address="123 Test Address", - website="http://www.testcompany.com", - phone_number="+1 800 555 0123", - ).model_dump_json() - - # Insert organization info and retrieve company_info_id - self.cursor.execute("SELECT upsert_organization_info(%s);", (sample_org_info,)) - self.company_info_id = self.cursor.fetchone()[0] - - # Insert label information - self.label_id = label.new_label_information( - self.cursor, - "test-label", - None, - None, - None, - None, - None, - None, - None, - None, - None, - self.company_info_id, - self.company_info_id, - None, - ) - def tearDown(self): # Rollback any changes to leave the database state as it was before the test self.conn.rollback() - self.cursor.close() - self.conn.close() + db.end_query(self.conn, self.cursor) def test_update_sub_labels(self): # Insert initial sub labels @@ -132,6 +113,7 @@ def test_update_sub_labels(self): "SELECT update_sub_labels(%s, %s);", (self.label_id, json.dumps(self.sample_sub_labels)), ) + saved_data = sub_label.get_sub_label_json(self.cursor, self.label_id) nb_sub_labels = len(saved_data["instructions"]["en"]) + len( diff --git a/tests/fertiscan/db/update_inspection/test_upsert_fertilizer.py b/tests/fertiscan/db/update_inspection/test_upsert_fertilizer.py index 23e47d1c..464a95fa 100644 --- a/tests/fertiscan/db/update_inspection/test_upsert_fertilizer.py +++ b/tests/fertiscan/db/update_inspection/test_upsert_fertilizer.py @@ -4,12 +4,15 @@ import psycopg from dotenv import load_dotenv -from fertiscan.db.queries import inspection +import datastore.db.__init__ as db +from datastore.db.queries import user, picture +from datastore.db.metadata import picture_set +from fertiscan.db.queries import inspection,organization,label load_dotenv() # Fetch database connection URL and schema from environment variables -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") @@ -19,66 +22,49 @@ class TestUpsertFertilizerFunction(unittest.TestCase): - def setUp(self): + def setUp(self): # Connect to the PostgreSQL database with the specified schema - self.conn = psycopg.connect( - DB_CONNECTION_STRING, options=f"-c search_path={DB_SCHEMA},public" - ) - self.conn.autocommit = False # Ensure transaction is managed manually - self.cursor = self.conn.cursor() - - # Prepopulate organization_information table - self.cursor.execute( - "INSERT INTO organization_information (name, website, phone_number) " - "VALUES (%s, %s, %s) RETURNING id;", - ( - "Test Organization Information", - "http://www.testorginfo.com", - "+1 800 555 0101", - ), - ) - self.organization_info_id = self.cursor.fetchone()[0] - - # Prepopulate location table - self.cursor.execute( - "INSERT INTO location (name, address) " "VALUES (%s, %s) RETURNING id;", - ("Test Location", "123 Test Address, Test City"), - ) - self.location_id = self.cursor.fetchone()[0] - - # Prepopulate organization table with references to organization_information and location - self.cursor.execute( - "INSERT INTO organization (information_id, main_location_id) " - "VALUES (%s, %s) RETURNING id;", - (self.organization_info_id, self.location_id), - ) - self.organization_id = self.cursor.fetchone()[0] - - # Insert a user to act as the inspector - self.cursor.execute( - "INSERT INTO users (email) VALUES (%s) RETURNING id;", - ("test_inspector@example.com",), - ) - self.inspector_id = self.cursor.fetchone()[0] - - # Insert a label information record to link with inspection - self.cursor.execute( - "INSERT INTO label_information (lot_number, npk, registration_number, n, p, k) " - "VALUES (%s, %s, %s, %s, %s, %s) RETURNING id;", - ("L123456789", "10-20-30", "R123456", 10.0, 20.0, 30.0), - ) - self.label_info_id = self.cursor.fetchone()[0] + self.conn = db.connect_db(DB_CONNECTION_STRING, DB_SCHEMA) + self.cursor = db.cursor(self.conn) + db.create_search_path(self.conn, self.cursor, DB_SCHEMA) + + self.user_email = "test-update-inspection@email" + self.inspector_id = user.register_user(self.cursor, self.user_email) + self.folder_name = "test-folder" + self.picture_set = picture_set.build_picture_set_metadata(self.inspector_id, 1) + self.picture_set_id = picture.new_picture_set( + self.cursor, self.picture_set, self.inspector_id, self.folder_name + ) + + self.label_info_id = label.new_label_information( + cursor=self.cursor, + name="test-label", + lot_number=None, + npk=None, + n=None, + p=None, + k=None, + title_en=None, + title_fr=None, + is_minimal=False, + record_keeping=False,) # Insert an inspection record self.inspection_id = inspection.new_inspection( self.cursor, self.inspector_id, None, False ) + self.organization_id = organization.new_organization( + cursor=self.cursor, + name="Test Organization", + address="123 Test St.", + website="www.test.com", + phone_number="123-456-7890") + def tearDown(self): # Rollback any changes to leave the database state as it was before the test self.conn.rollback() - self.cursor.close() - self.conn.close() + db.end_query(self.conn, self.cursor) def test_insert_new_fertilizer(self): fertilizer_name = "Test Fertilizer" @@ -98,7 +84,7 @@ def test_insert_new_fertilizer(self): # Verify that the data is correctly saved self.cursor.execute( - "SELECT name, registration_number, owner_id, latest_inspection_id FROM fertilizer WHERE id = %s;", + "SELECT name, registration_number, main_contact_id, latest_inspection_id FROM fertilizer WHERE id = %s;", (fertilizer_id,), ) saved_fertilizer_data = self.cursor.fetchone() @@ -162,7 +148,7 @@ def test_update_existing_fertilizer(self): # Verify that the data is correctly updated self.cursor.execute( - "SELECT name, registration_number, owner_id, latest_inspection_id FROM fertilizer WHERE id = %s;", + "SELECT name, registration_number, main_contact_id, latest_inspection_id FROM fertilizer WHERE id = %s;", (updated_fertilizer_id,), ) updated_fertilizer_data = self.cursor.fetchone() diff --git a/tests/fertiscan/inspection.json b/tests/fertiscan/inspection.json index dfc2154a..0d764c3c 100644 --- a/tests/fertiscan/inspection.json +++ b/tests/fertiscan/inspection.json @@ -47,7 +47,7 @@ "edited": false } }, - "label_id": "cdca3638-a3c0-45df-8c72-74e28a8740c6", + "label_id": null, "record_keeping": null, "lot_number": "L987654321", "registration_number": "F12345678" @@ -231,34 +231,34 @@ "is_minimal" : false, "en" : [ { - "nutrient": "Total Nitrogen (N)", + "name": "Total Nitrogen (N)", "value": "20", "unit": "%" }, { - "nutrient": "Available Phosphate (P2O5)", + "name": "Available Phosphate (P2O5)", "value": "20", "unit": "%" }, { - "nutrient": "Soluble Potash (K2O)", + "name": "Soluble Potash (K2O)", "value": "20", "unit": "%" } ], "fr" : [ { - "nutrient": "Azote total (N)", + "name": "Azote total (N)", "value": "20", "unit": "%" }, { - "nutrient": "Phosphate assimilable (P2O5)", + "name": "Phosphate assimilable (P2O5)", "value": "20", "unit": "%" }, { - "nutrient": "Potasse soluble (K2O)", + "name": "Potasse soluble (K2O)", "value": "20", "unit": "%" } diff --git a/tests/fertiscan/metadata/test_inspection.py b/tests/fertiscan/metadata/test_inspection.py index cb0ffbdb..bf83aedd 100644 --- a/tests/fertiscan/metadata/test_inspection.py +++ b/tests/fertiscan/metadata/test_inspection.py @@ -14,7 +14,7 @@ from fertiscan.db.queries import inspection from fertiscan.db.queries.errors import QueryError -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") @@ -65,6 +65,10 @@ def test_perfect_inspection(self): self.assertEqual(inspection_dict["inspection_id"], data["inspection_id"]) self.assertEqual(inspection_dict["verified"], data["verified"]) self.assertDictEqual(inspection_dict["product"], data["product"]) + print("=====\n========\n") + print(inspection_dict["organizations"]) + print("=====\n========\n") + print(data["organizations"]) self.assertListEqual(inspection_dict["organizations"], data["organizations"]) ## self.assertDictEqual(inspection_dict["micronutrients"], data["micronutrients"]) ## self.assertDictEqual(inspection_dict["ingredients"], data["ingredients"]) @@ -99,11 +103,6 @@ def test_no_organization(self): self.assertEqual(inspection_dict["inspection_id"], data["inspection_id"]) self.assertEqual(inspection_dict["verified"], data["verified"]) self.assertListEqual(inspection_dict["organizations"], data["organizations"]) - self.assertIsNone(data["manufacturer"]["id"]) - self.assertIsNone(data["manufacturer"]["name"]) - self.assertIsNone(data["manufacturer"]["address"]) - self.assertIsNone(data["manufacturer"]["phone_number"]) - self.assertIsNone(data["manufacturer"]["website"]) def test_no_volume(self): self.analyse["volume"] = None @@ -529,10 +528,10 @@ def test_mismatched_sub_label_lengths_fr_longer(self): def test_organizations_not_located(self): # Modify analyse data to have empty addresses test_str = "Test string" - self.analyse["organizations"] = [ - metadata.OrganizationInformation(name=test_str).model_dump_json(), - metadata.OrganizationInformation(website=test_str).model_dump_json() + orgs = [metadata.OrganizationInformation(name=test_str).model_dump(), + metadata.OrganizationInformation(website=test_str).model_dump() ] + self.analyse["organizations"] = orgs formatted_analysis = metadata.build_inspection_import(self.analyse,self.user_id) diff --git a/tests/fertiscan/test_datastore.py b/tests/fertiscan/test_datastore.py index 643c5bd2..6c890b9a 100644 --- a/tests/fertiscan/test_datastore.py +++ b/tests/fertiscan/test_datastore.py @@ -23,7 +23,7 @@ if BLOB_CONNECTION_STRING is None or BLOB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_STORAGE_URL_TESTING is not set") -DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL_TESTING") +DB_CONNECTION_STRING = os.environ.get("FERTISCAN_DB_URL") if DB_CONNECTION_STRING is None or DB_CONNECTION_STRING == "": raise ValueError("FERTISCAN_DB_URL is not set") @@ -152,7 +152,7 @@ def tearDown(self): print(e) def test_register_analysis(self): - print(self.user.id) + #print(self.user.id) self.assertTrue(self.container_client.exists()) analysis = asyncio.run( fertiscan.register_analysis( @@ -180,7 +180,7 @@ 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"])) - print(ingredients) + #print(ingredients) # specifications = specification.get_all_specifications( # cursor=self.cursor, label_id=str(analysis["product"]["label_id"]) @@ -227,24 +227,21 @@ def test_register_analysis(self): label_dimension = label.get_label_dimension(self.cursor, label_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(str(company_info_id), analysis["company"]["id"]) - self.assertEqual(str(manufacturer_info_id), analysis["manufacturer"]["id"]) + self.assertEqual(len(label_dimension[2]), self.nb_instructions) - self.assertEqual(len(label_dimension[5]), self.nb_instructions) - - self.assertEqual(len(label_dimension[6]), self.nb_cautions) + self.assertEqual(len(label_dimension[3]), self.nb_cautions) # self.assertEqual(len(label_dimension[7]), self.nb_first_aid) - # self.assertEqual(len(label_dimension[9]), self.nb_specifications) - self.assertEqual(len(label_dimension[10]), self.nb_ingredients) - # self.assertEqual(len(label_dimension[11]), self.nb_micronutrients) - self.assertEqual(len(label_dimension[12]), self.nb_guaranteed) - self.assertEqual(len(label_dimension[13]), self.nb_weight) - self.assertEqual(len(label_dimension[14]), 1) - self.assertEqual(len(label_dimension[15]), 1) + # self.assertEqual(len(label_dimension[6]), self.nb_specifications) + self.assertEqual(len(label_dimension[7]), self.nb_ingredients) + # self.assertEqual(len(label_dimension[8]), self.nb_micronutrients) + self.assertEqual(len(label_dimension[9]), self.nb_guaranteed) + self.assertEqual(len(label_dimension[10]), self.nb_weight) + self.assertEqual(len(label_dimension[11]), 1) + self.assertEqual(len(label_dimension[12]), 1) def test_register_analysis_empty(self): empty_analysis = { @@ -277,10 +274,10 @@ def test_register_analysis_empty(self): label_id = inspection_dict["product"]["label_id"] self.assertTrue(validator.is_valid_uuid(inspection_id)) - # Make sure the manufacturer is created + # Verify the data label_data = label.get_label_information(self.cursor, label_id) self.assertIsNotNone(label_data) - self.assertIsNotNone(label_data[12]) + self.assertIsNone(label_data[1]) # Verify getters inspection_data = metadata.build_inspection_export( @@ -536,10 +533,10 @@ def test_update_inspection(self): label_info_data = label.get_label_information(self.cursor, label_id) self.assertEqual(label_info_data[3], new_npk) self.assertNotEqual(label_info_data[3], old_npk) - self.assertEqual(label_info_data[8], new_title) - self.assertNotEqual(label_info_data[8], old_title) - self.assertEqual(label_info_data[9], old_title) - self.assertEqual(label_info_data[13], new_record_keeping) + self.assertEqual(label_info_data[7], new_title) + self.assertNotEqual(label_info_data[7], old_title) + self.assertEqual(label_info_data[8], old_title) + self.assertEqual(label_info_data[10], new_record_keeping) guaranteed_data = nutrients.get_all_guaranteeds(self.cursor, label_id) for guaranteed in guaranteed_data: @@ -554,28 +551,27 @@ def test_update_inspection(self): # Verify organizations are saved orgs = organization.get_organizations_info_label(self.cursor, label_id) - self.assertEqual(len(orgs), 1) - self.assertNotEqual(len(orgs), len(old_organizations)) - self.assertEqual(orgs[0][0], new_organizations[0]["name"]) - self.assertNotEqual(new_organizations[0]["name"], old_organizations[0]["name"]) + + self.assertEqual(len(orgs), 3) # 2 default + 1 new + self.assertEqual(len(orgs), len(old_organizations)+1) # VERIFY OLAP new_label_dimension = label.get_label_dimension(self.cursor, label_id) # Check if sub_label created a new id if there is a field that is not in the old label_dimension - self.assertEqual(len(old_label_dimension[6]), self.nb_cautions) + self.assertEqual(len(old_label_dimension[3]), self.nb_cautions) - self.assertEqual(len(new_label_dimension[6]), new_caution_number) - self.assertNotEqual(len(new_label_dimension[6]), len(old_label_dimension[6])) + self.assertEqual(len(new_label_dimension[3]), new_caution_number) + self.assertNotEqual(len(new_label_dimension[3]), len(old_label_dimension[6])) # Check if the total of sub_label reduced after a field has been removed - self.assertEqual(len(old_label_dimension[5]), self.nb_instructions) - self.assertEqual(len(new_label_dimension[5]), new_instruction_nb) - self.assertNotEqual(len(new_label_dimension[5]), len(old_label_dimension[5])) + self.assertEqual(len(old_label_dimension[2]), self.nb_instructions) + self.assertEqual(len(new_label_dimension[2]), new_instruction_nb) + self.assertNotEqual(len(new_label_dimension[2]), len(old_label_dimension[5])) # Check if the total of guaranteed is reduced after a field has been removed - self.assertEqual(len(old_label_dimension[12]), self.nb_guaranteed) - self.assertEqual(len(new_label_dimension[12]), new_guaranteed_nb) - self.assertNotEqual(len(new_label_dimension[12]), len(old_label_dimension[12])) + self.assertEqual(len(old_label_dimension[9]), self.nb_guaranteed) + self.assertEqual(len(new_label_dimension[9]), new_guaranteed_nb) + self.assertNotEqual(len(new_label_dimension[9]), len(old_label_dimension[12])) new_guaranteed_analysis = { "title": {"en": new_title, "fr": old_title}, @@ -645,6 +641,6 @@ def test_update_inspection(self): new_label_dimension = label.get_label_dimension(self.cursor, label_id) # Check if the total of guaranteed is increased after a field has been added - self.assertEqual(len(new_label_dimension[12]), new_guaranteed_nb) - self.assertNotEqual(len(new_label_dimension[12]), len(old_label_dimension[12])) - self.assertNotEqual(len(new_label_dimension[12]), old_guaranteed_nb) + 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)