import os
import logging
import boto3
import traceback
from pymorri.exceptions import MoriException
from pymorri.util.response_builder import ResponseBuilder
from pymorri.util.aws_utils import get_event_from_sns, publish_event_to_sns
from pymorri.util.general_utils import build_response_or_throw
from pymorri.util.serverless_utils import resolve_env, get_or_exception
from pymorri.util.datadog_utils import post_datadog_event_to_sns
from pymorri.api.morrisons.customer import Customer
from constants import DATADOG_APP_NAME, OCEAN_SSM_KEY, APP_NAME, DD_CHECK_METRIC_NAME, COLLEAGUE_DISCOUNT_CONFIG, \
DATADOG_CREATE_SHELL_AC_APP_NAME, DATADOG_PROCESS_OCEAN_EVENTS_APP_NAME
from pymorri.util.application_dependencies import ApplicationDependencies
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
deps = None
def _prepare_deps():
global deps
if not deps:
deps = ApplicationDependencies(
config_file=COLLEAGUE_DISCOUNT_CONFIG,
ssm_param_store_name=OCEAN_SSM_KEY,
)
[docs]def delete_from_dynamodb(dynamodb, source_system_cust_id, table_name):
dynamodb_response = dynamodb.delete_item(
TableName=table_name,
Key={
"customerID": {"S": source_system_cust_id},
}
)
logger.info(f'dynamodb_response {dynamodb_response}')
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="count",
metric_name="ocean_colleague_discount_remove", metric_value="1")
[docs]def put_into_dynamodb(dynamodb, source_system_cust_id, table_name):
_ = dynamodb.put_item(
TableName=table_name,
Item={
"customerID": {"S": source_system_cust_id},
}
)
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="count",
metric_name="ocean_colleague_discount_create", metric_value="1")
[docs]@get_event_from_sns
@build_response_or_throw
def lambda_handler(event, context):
"""
This lambda receives event from SNS (event example given further below)
For eventType 'addCustomerToOcean':
- Lambda gets event from SNS with data to create rows in dynamodb table
ENV.xxwmm.storepick.ocean_colleague_discount related to provided customerId.
For eventType 'removeCustomerFromOcean':
- Lambda removes rows related to provided customerId from above dynamodb table.
Additionally function post CHECK status to DataDog API:
- metric name: `colleague_discount_check` in DataDog
- app name: `storepick_colleague_discount`
It sends:
* value 0 (SUCCESS) when this function returns 200
* value 2 (ERROR) when this function throws exception
+ exception is handled and processed in `build_response_or_throw` decorator
and error response with 500 or 4xx is sent.
Input:
- event (dict) - required: eventType, eventData
.. code-block:: python
{
"eventType": "addCustomerToOcean|removeCustomerFromOcean",
"eventData":
{
"customerId": "1234567"
}
}
Output:
- event (dict) - required: eventType, eventData
.. code-block:: python
{
"eventType": "addCustomerToOcean",
"eventData":
{
"customerId": "1234567"
}
}
Raises:
MoriException: MoriException containing details about exception
"""
################################################################################
# need to populate the global deps (which is cached deliberately outside this
# main handler
################################################################################
_prepare_deps()
global deps
# update event in order this function could send STATUS data to DataDog API
# from build_response_or_throw
event.update({
"DATADOG_APP_NAME": DATADOG_APP_NAME,
"DD_CHECK_METRIC_NAME": DD_CHECK_METRIC_NAME,
})
event_type = get_or_exception(event, "eventType")
event_data = get_or_exception(event, "eventData")
customer_id = get_or_exception(event_data, "customerId")
club_id = get_or_exception(event, "club_id")
# get sourceSystemId from API based on customerId
try:
logger.info(f"Getting data for customer with customer_id: {customer_id}")
customer = Customer(configuration=deps.get_config(), ssm=deps.get_ssm_params())
resp = customer.request(customer_id)
logger.info(f"Successfully got data for customer with customer_id: {customer_id}")
except MoriException as ex:
if ex.http_status_code == 404:
logger.warning(f"Customer {customer_id} does NOT EXISTS in Morrisons Customer V2 API")
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="count",
metric_name="ocean_customer_not_found", metric_value="1")
event['response_message'] = "customer not found"
return event
else:
logger.error("Unexpected exception from request Customer V2")
raise ex
source_system_cust_id = resp.get('payload').get("sourceSystemCustomerId")
if not source_system_cust_id or len(source_system_cust_id.strip()) == 0:
error_msg = f"source_system_cust_id is null for customer_id {customer_id}"
logger.error(error_msg)
post_datadog_event_to_sns(application_name=DATADOG_PROCESS_OCEAN_EVENTS_APP_NAME, metric_type="count",
metric_name="ocean_colleague_discount_no_source_id", metric_value="1")
raise MoriException(http_status_code=500, detail=error_msg)
logger.info(f"Got source_system_cust_id from API: {source_system_cust_id}")
dynamodb = boto3.client("dynamodb")
table_name = os.environ.get("COLLEAGUE_DISCOUNT_TABLE")
friends_and_family_table_name = os.environ.get("FRIENDS_AND_FAMILY_DISCOUNT_TABLE")
if event_type not in ("addCustomerToOcean", "removeCustomerFromOcean"):
msg = f"invalid event type for processing {event_type}"
logger.warning(msg)
post_datadog_event_to_sns(application_name=DATADOG_APP_NAME, metric_type="count",
metric_name="ocean_customer_fail", metric_value="1")
event['response_message'] = msg
return event
if event_type == "addCustomerToOcean":
# not needed to get response => if error then exception will be thrown
# which should be cautght in build_response_or_throw and published into
# failure SNS topic
if club_id == "6":
put_into_dynamodb(dynamodb, source_system_cust_id, table_name)
elif club_id == "7":
put_into_dynamodb(dynamodb, source_system_cust_id, friends_and_family_table_name)
elif event_type == "removeCustomerFromOcean":
# not needed to get response => if error then exception will be thrown
# which should be cautght in build_response_or_throw and published into
# failure SNS topic
if club_id == "6":
logger.info(f'club_id {club_id}')
delete_from_dynamodb(dynamodb, source_system_cust_id, table_name)
elif club_id == "7":
logger.info(f'club_id {club_id}')
delete_from_dynamodb(dynamodb, source_system_cust_id, friends_and_family_table_name)
return event
if __name__ == "__main__":
event = {
"eventType": "addCustomerToOcean",
"eventData": {
# "customerId" : "1234567"
"customerId": "1025974240"
}
}
response = lambda_handler(event, '')
logger.info(f"{response}")