# Find or Create Vendor and Subaccount

## Overview

The `find_or_create_account` Lambda function is responsible for finding or creating a vendor and subaccount in the system. It performs the following tasks:

1. **Check if the Product Already Exists**  
   - If the product exists under a vendor/subaccount where `notForDistribution` is equal to `SMEAnalyticsDummy`, use the corresponding vendor and subaccount, then proceed to step 7.  
   - If the product exists under a vendor/subaccount where `notForDistribution` is *not* equal to `SMEAnalyticsDummy`, raise a `ProductExistUnderDifferentVendorException` and terminate the process.  
   - If the product does not exist, proceed to the next step.  

2. **Check for Parent Repertoire Owner Remapping**  
   Determine if the `parent_repertoire_owner` needs to be remapped by querying the Snowflake table `SONY_INTERNAL.DEV.REP_OWNER_HIERARCHY` using the `rep_owner_key`.  
   - If the `parent_repertoire_code` in the table differs from the value in the metadata, update it to the new value from the table.  
   - This updated `parent_repertoire_code` will be used in subsequent steps for vendor search and creation.

3. **Search for Vendor and Subaccount**
   Searches for a vendor and subaccount in the `inbound_major_label_mapping` table based on the provided `repertoire_owner_code` and `parent_repertoire_owner_code`.

4. **Retrieve via GraphQL**
   If no mapping exists, it attempts to retrieve the vendor and subaccount via GraphQL.

   - **Vendor Search**: The vendor is searched by `external_identifier_1`, where `external_identifier_1 = parent_repertoire_owner_code`.
   - **Subaccount Search**: The subaccount is searched by `vendor_id` and then filtered by `subaccount_name`, where `subaccount_name = repertoire_owner_name`.

5. **Create Vendor and Subaccount**
   If the vendor or subaccount is still not found, it creates a new vendor and/or subaccount.

6. **Update Mapping Table**
   Updates the `inbound_major_label_mapping` table with the new vendor and subaccount if applicable.

7. **Save Context to S3**
   Saves the updated context to an S3 bucket for further processing.


## Important Note

To **prevent the creation of duplicate vendors or subaccounts**, concurrent execution of the function must be avoided due to the **complexity of the logic**.

---

## Error Handling

### Exceptions Raised
1. **`LambdaException`**  
   Raised when the mapping query returns multiple values, or the GraphQL response contains multiple vendors or subaccounts. This ensures that the function fails gracefully when unexpected multiple results are encountered. For example:
   - Mapping query returns more than one result when only a single result is expected.
   - GraphQL response includes multiple vendors instead of a single vendor.
   - GraphQL response includes multiple subaccounts instead of a single subaccount.

2. **`ProductExistUnderDifferentVendorException`**  
   Raised when a product exists under a different vendor with `notForDistribution` is not equal to `SMEAnalyticsDummy`.
   In that case we can't update the product.

3. **`VendorDoNotIngestException`**  
   Raised when a mapping is marked as "do not ingest," indicating that the vendor or subaccount should not be processed further.

---

## How to set up

### 1. Install Requirements
Ensure you have Python installed. Install the required dependencies by running:

```bash
pip install -r requirements.txt
pip install -r requirements-dev.txt
```

### 2. Set Up Environment Variables
Make sure to set the following environment variables in your Lambda function configuration as mentioned .env.shadow file

### 3. Set AWS Credentials
To run the function end-to-end, you need to set QA AWS credentials that have access to the following resource:

`qa/ddex-ingester-find-or-create-account/M2M_JWT_ACCESS_TOKEN`

Alternatively, you can copy this token to the dev environment for testing.
This token is used to authenticate the GraphQL requests made by the function.
