"""Job Creation Logic.""" from typing import Any from sqlalchemy import func from video.connectors import mysql from video.constants import ( product as product_constants, release as release_constants, ) from video.exceptions import ( ProductVideoNotFound, SubmissionNotAllowed, ) from video.logic import ( approval as approval_logic, auto_approval as auto_approval_logic, metadata, ) from video.models.ows import ( artist as ows_artist, product as ows_product, project as ows_project, track as ows_track, ) from video.models.sql.classes import approval, product_video, release from video.utils import status_checker def create_product( data: dict[str, Any], account_type: str | None, account_id: int | str | None ) -> dict[str, Any]: """Create product.""" project_id = data["project_id"] ows_project.check_project_ownership(project_id, account_type, account_id) project = ows_project.get_project_by_id(project_id) subaccount_id = project.get("subaccount_id") or None artist_id = project.get("artist_id") vendor_catalog_number = data.get("vendor_catalog_number") or None placeholder_upc = ows_product.generate_placeholder_upc() values = { "upc": placeholder_upc, "subaccount_id": subaccount_id, "vendor_catalog_number": vendor_catalog_number, "release_status": "label_processing", "artist_id": artist_id, "project_id": project_id, "distribution_format_id": ( product_constants.MUSIC_VIDEO_DISTRIBUTION_FORMAT_ID ), "product_type_id": product_constants.MUSIC_PRODUCT_TYPE_ID, # Set release name to an empty string instead of null to avoid # 'No product are available to see' error on workstation catalog page. "release_name": product_constants.DEFAULT_RELEASE_NAME, } created_release = release.create(values) return metadata.save_metadata( created_release["release_id"], { "primary_artist_id": artist_id, "video_title": product_constants.DEFAULT_RELEASE_NAME, }, ) def delete( product_id: int, account_type: str | None, account_id: int | str | None ) -> dict[str, Any]: """Delete product.""" ows_product.check_product_ownership(product_id, account_type, account_id) status_checker.check_release_status_before_action( product_id, frozenset({release_constants.LABEL_PROCESSING}) ) with mysql.ar_db_session() as session: product_video.delete_product(product_id, session=session) approval.delete_approval(product_id, session=session) release.delete_release(product_id, session=session) return {} def submit( product_id: int, account_type: str | None, account_id: int | str | None ) -> dict[str, Any]: """Submit product.""" ows_product.check_product_ownership(product_id, account_type, account_id) status_checker.check_release_status_before_action( product_id, frozenset({release_constants.LABEL_PROCESSING}) ) product_metadata = product_video.get(product_id) if not product_metadata: raise ProductVideoNotFound() if product_metadata["is_valid"] is False: raise SubmissionNotAllowed() if product_metadata["submitted_at"] is None: product_video.upsert({"release_id": product_id, "submitted_at": func.now()}) product = _update_orchard_created_fields(product_id, product_metadata) # Set release as transfer_to_content because approval_logic.change # is expecting the release to be in transfer_to_content status release_response = release.update( product_id, {"release_status": release_constants.TRANSFER_TO_CONTENT}, ) release_response_with_vendor = release.get_by_id_with_vendor(product_id) if auto_approval_logic.should_auto_apply_label_mgr_approval(product): auto_approval_logic.auto_apply_label_mgr_approval(product_id) auto_approval_logic.auto_apply_video_type_carveouts(product_id) if auto_approval_logic.should_auto_apply_vidops_approval(product_id): auto_approval_logic.auto_apply_vidops_approval(product_id) if auto_approval_logic.should_final_approval_be_applied(product_id): release_response = auto_approval_logic.apply_final_approval( product_id, product, release_response_with_vendor ) # Retrieve product again in case isrc was updated from # the placeholder isrc product = product_video.get(product_id) if not product: raise ProductVideoNotFound() is_isrc_used = ows_track.is_isrc_used(product.get("isrc"), "video") # Previously, the truthiness check was against an oto.Response object, which # was truthy on any successful API call regardless of whether the ISRC was # actually in use. This now correctly checks the "used" flag in the response. if auto_approval_logic.should_auto_apply_label_mgr_approval( product ) and is_isrc_used.get("used"): approval_logic.revert_label_mgr_approval(product_id) return release_response def _update_orchard_created_fields( product_id: int, product_metadata: dict[str, Any] ) -> dict[str, Any]: """Update any orchard created fields on submit.""" product = product_metadata update_fields = {} if not product.get("upc"): update_fields["upc"] = release.get_upc() if not product.get("isrc"): update_fields["isrc"] = release.get_isrc() if len(update_fields.keys()) > 0: return metadata.save_metadata(product_id, update_fields) return product_metadata def disassociate_tracks(track_ids: list[int]) -> None: """Clear associated_track_id on video products referencing the given tracks. Args: track_ids: Track tuids to disassociate from any video products. """ product_video.clear_associated_track(track_ids) def migrate_artist( artist_id: int, product_id: int, account_type: str | None, account_id: int | str | None, ) -> dict[str, Any]: """Update artist of the product. Args: artist_id (int): Identifier of Artist. product_id (int): Unique Identifier of Product. account_type (str): Grass account type i.e vendor or subaccount account_id (int): Identifier of vendor or subaccount Returns: dict: product information associated with product_id """ ows_product.check_product_ownership(product_id, account_type, account_id) ows_artist.check_artist_ownership( artist_id, account_type, str(account_id) if account_id else None ) return product_video.update_primary_artist(product_id, artist_id)