"""Product timed release Logic CRUD operation.""" from datetime import timedelta, timezone from dateutil import parser from oto import response from oto import status as http_status from timed_release.connectors import sql from timed_release.constants import error from timed_release.logic import scheduled_update from timed_release.models import scheduled_update as scheduled_update_model from timed_release.models import timed_release def get_unsupported_timed_release_data(product_id): """Get scheduled update and transform it into unsupported_timed list. Args: product_id (int): Product id to fetch scheduled update data. Return: repsonse.Response: unsupported release data on successful fetch or error on response. """ scheduled_update_res = scheduled_update.get_scheduled_update(product_id) if scheduled_update_res.status != 200: if scheduled_update_res.status == 404: return response.Response(status=200, message=[]) return response.create_error_response( error.ERROR_CODE_BAD_REQUEST, error.ERROR_CODE_AUTHORIZATION) scheduled_update_body = scheduled_update_res.message unsupported_schedules = [] for store_id in scheduled_update_body.get('delivery_store_ids', []): unsupported_schedules.append({ 'delivery_store': { 'id': store_id, }, 'sale_date_time': scheduled_update_body['schedule_datetime'], 'time_offset': scheduled_update_body['schedule_time_offset'] }) return response.Response(status=200, message=unsupported_schedules) def get_timed_release_data(product_id): """Check if product id exist in timed_release table and return it. Args: product_id (int): Product id to fetch timed release data. Return: response.Response: timed release data on successful fetch or error response. """ unsupported_schedules_res = get_unsupported_timed_release_data(product_id) if unsupported_schedules_res.status != 200: return unsupported_schedules_res release_schedules_res = timed_release.get_product_timed_release_data( product_id) if release_schedules_res.status != 200: return release_schedules_res release_schedules = release_schedules_res.message unsupported_schedules = unsupported_schedules_res.message release_data = { 'staggered': release_schedules.get('staggered'), 'timed': release_schedules.get('timed'), 'unsupported_timed': unsupported_schedules } return response.Response(status=200, message=release_data) def update_unsupported_timed_release_data( product_id, data, orchard_identity_id, session=None): """Update or delete scheduled update and return unsupported release data. If data exists and key is not None, update scheduled_update. If data exists and key is None or undefined, do nothing. Args: product_id (int): Product id to update scheduled update. data (dict): Release Schedule with timed, unsupported timed, and staggered data. orchard_identity_id (string): Users orchard identity id. Return: response.Response: unsupported release data on succeessful put or error response. """ unsupported_timed = data.get('unsupported_timed') if unsupported_timed is not None: if len(unsupported_timed) == 0: delete_res = scheduled_update.delete(product_id, session=session) if delete_res.status == 500: return delete_res else: store_ids, schedules = [], set() for schedule in unsupported_timed: schedules.add(( schedule.get('sale_date_time'), schedule.get('time_offset'))) store_ids.append(schedule['delivery_store']['id']) if len(schedules) > 1: return response.create_error_response( error.ERROR_CODE_BAD_REQUEST, error.ERROR_MESSAGE_NON_MATCHING_TIME_VALUES) schedule_time_fields = schedules.pop() schedule_datetime = parser.isoparse(schedule_time_fields[0]) earliest_tz = timezone(timedelta(hours=-12)) earliest_datetime = schedule_datetime.astimezone(earliest_tz) schedule_update = { 'delivery_store_ids': store_ids, 'schedule_datetime': schedule_time_fields[0], 'schedule_time_offset': schedule_time_fields[1], 'update': { 'sale_start_date': earliest_datetime.strftime('%Y-%m-%d') } } upsert_res = scheduled_update.upsert( product_id, schedule_update, orchard_identity_id, session=session) if upsert_res.status == 500: return upsert_res unsupported_schedules_res = get_unsupported_timed_release_data(product_id) if unsupported_schedules_res.status != 200: return unsupported_schedules_res return response.Response( status=200, message=unsupported_schedules_res.message) def update_timed_release_data(product_id, data, orchard_identity_id): """Check if timed release data exists for the product and store. If data exists, update the data. If data does not exist, create new records. Args: product_id (int): Product id to update timed release data. data (dict): Release Schedule with timed and staggered data. orchard_identity_id (string): Users orchard identity id. Return: response.Response: timed release data on successful update or error response. """ with sql.db_session() as session: release_schedule_res = \ timed_release.update_product_timed_release_data( product_id, data, orchard_identity_id, session) if release_schedule_res.status != 200: session.rollback() return release_schedule_res unsupported_schedules_res = update_unsupported_timed_release_data( product_id, data, orchard_identity_id, session) if unsupported_schedules_res.status != 200: session.rollback() return unsupported_schedules_res session.commit() return get_timed_release_data(product_id) def get_product_timed_release_by_store_id(product_id, store_id): """Fetch the timed release or scheduled update for product_id and store_id. The function first tries to fetch a timed release for the specified `product_id` and `store_id`, regardless of whether it was set from OA or Workstation. If no timed release is available, it falls back to checking for a scheduled update. If neither a timed release nor a scheduled update exists, the function returns a 404 response with a descriptive error message. Args: product_id (int): The product ID to look up. store_id (int): The DMS store identifier to filter by. Returns: response.Response: - 200 OK with timed release details if a timed release exists. - 200 OK with scheduled update details if no timed release exists but a scheduled update is available. - 404 NOT_FOUND if neither is found. - 500 internal error """ with sql.db_session(read_only=True) as session: timed_release_response = ( timed_release.get_product_timed_release_by_store_id( product_id, store_id, session ) ) if timed_release_response.status != http_status.NOT_FOUND: return timed_release_response scheduled_update_response = ( scheduled_update_model.get_product_scheduled_update_by_store_id( product_id, store_id, session ) ) return scheduled_update_response