Skip to content

Tender Management API with Data Insertion, Update, and Review Handling


Key Features:

  1. Tender Creation Endpoint (/createNew):

    • Accepts POST requests to create new tenders.
    • Automatically assigns system-generated fields (e.g., created_at, serial_id, and id).
    • Stores tender information in a MongoDB database.
    • Returns a success message along with the tender_id and serial_id.
  2. Tender Update Endpoint (/update-tender-by-serial-id):

    • Accepts PUT requests to update an existing tender by its serial_id.
    • Updates specific fields in the tender, ensuring missing fields are filled with defaults or existing values.
    • Provides validation for input data, such as checking if serial_id exists and if nested fields like detailsEOI and detailsTOR are valid objects.
    • Manages reviewer data and sends notifications (though the actual email-sending is commented out).
    • Returns the status of the update operation.
  3. MongoDB Integration:

    • Both endpoints interact with MongoDB to insert new documents or update existing ones using the serial_id as the unique identifier.
  4. Error Handling and Logging:

    • Detailed error handling is implemented, including logging for debugging, checks for missing fields, and handling unexpected errors during execution.
  5. Custom Validation:

    • The code checks the structure of incoming data to ensure that necessary fields are present and appropriately formatted (e.g., submission_deadline as a date, nested objects as dictionaries).

Key Functionalities:

  1. Tender Creation (create_tender_new):

    • Data Processing: The incoming request data is copied, auto-generated fields (like created_at and serial_id) are added, and then it is inserted into the MongoDB collection.
    • Unique ID Assignment: The uuid.uuid4().hex ensures that each tender gets a unique ID.
    • Response: On successful insertion, the system returns the tender’s ID and serial ID in a JSON response.
    tender_data = request.json.copy()
    tender_data['created_at'] = datetime.now(timezone.utc)
    tender_data['serial_id'] = get_next_serial_id()
    tender_data['id'] = uuid.uuid4().hex
    result = tender_collection.insert_one(tender_data)
    return jsonify({
    "message": "Tender created successfully",
    "tender_id": str(result.inserted_id),
    "serial_id": tender_data['serial_id']
    }), 201
  2. Tender Update (update_tender_by_serial_id):

    • Data Validation: Checks whether the serial_id is present in the request and whether nested fields are correctly formatted as dictionaries.
    • Field Update Logic: The code iterates over a predefined set of fields (fields_with_defaults), updating the existing document with either the new values or the current values from the database if the field is missing.
    • Sending Notifications: Although not fully implemented, the reviewer information (reviewers_TOR, reviewers_EOI) is processed, and email notifications are prepared to notify the relevant procurement managers about the updates.
    updates = {}
    for field, default_value in fields_with_defaults.items():
    updates[field] = data.get(field, existing_tender.get(field, default_value))
    result = tender_collection.update_one({'serial_id': serial_id}, {'$set': updates})
  3. Error Handling:

    • Try-Except Blocks: For both the tender creation and update processes, the code uses try-except blocks to catch and handle any exceptions. This ensures that if an error occurs (e.g., missing required fields, database errors), the system can respond with meaningful error messages.
    • Response on Error: If the operation fails, it returns a JSON response with an error message and details of the exception.
    except Exception as e:
    return jsonify({
    "error": "An unexpected error occurred",
    "details": str(e)
    }), 500

Data Fetching and Step Handling:

  1. Fetching Data:

    • In the update endpoint, data is fetched from MongoDB using find_one based on the serial_id. This fetches the existing tender document so that updates can be made to it.
    • The get_tender_collection method is responsible for retrieving the MongoDB collection, and data is fetched using MongoDB’s find_one method to locate the document.
    existing_tender = tender_collection.find_one({"serial_id": serial_id})
  2. Step Handling:

    • The tender’s step is stored in the database, although it is not actively manipulated in the provided code. The step field is part of the data structure for both tender creation and update, suggesting that it may be used later to track the progress of the tender.
    • The update process involves updating various steps or stages (such as reviewers_TOR, reviewers_EOI) based on the data provided. This suggests that the tender may be in different phases, and different actions may be triggered based on the current step.
    updates['step'] = data.get('step', existing_tender.get('step', None))
  3. Information Flow:

    • In tender creation, the flow starts with the frontend sending a request with tender data. The backend processes the data, assigns additional fields like serial_id and id, and inserts the data into the database.
    • In tender update, the frontend sends updated tender information (with serial_id), which is validated and merged with existing data before being saved back to the database. This also involves handling specific fields like submission deadlines, reviewer information, and status changes.

Code Example for Reference:

Tender Creation:

tender_data = request.json.copy()
tender_data['created_at'] = datetime.now(timezone.utc)
tender_data['serial_id'] = get_next_serial_id()
tender_data['id'] = uuid.uuid4().hex
tender_collection = get_tender_collection()
result = tender_collection.insert_one(tender_data)
return jsonify({
"message": "Tender created successfully",
"tender_id": str(result.inserted_id),
"serial_id": tender_data['serial_id']
}), 201

Tender Update:

updates = {}
for field, default_value in fields_with_defaults.items():
updates[field] = data.get(field, existing_tender.get(field, default_value))
result = tender_collection.update_one({'serial_id': serial_id}, {'$set': updates})

This code demonstrates the key features of creating and updating tenders, managing errors, and handling data flow between the frontend and MongoDB.