Ejemplo n.º 1
0
 def find_affidavit_by_org_id(org_id: int):
     """Return affidavit for the org by finding the admin for the org."""
     current_app.logger.debug('<find_affidavit_by_org_id ')
     affidavit = AffidavitModel.find_by_org_id(org_id)
     affidavit_dict = Affidavit(affidavit).as_dict()
     affidavit_dict['documentUrl'] = MinioService.create_signed_get_url(
         affidavit.document_id)
     current_app.logger.debug('>find_affidavit_by_org_id ')
     return affidavit_dict
Ejemplo n.º 2
0
 def find_affidavit_by_user_guid(user_guid: str, status: str = None):
     """Return affidavit for the user."""
     current_app.logger.debug('<find_affidavit_by_user_guid ')
     affidavit = AffidavitModel.find_effective_by_user_guid(
         user_guid, status)
     affidavit_dict = Affidavit(affidavit).as_dict()
     affidavit_dict['documentUrl'] = MinioService.create_signed_get_url(
         affidavit.document_id)
     current_app.logger.debug('>find_affidavit_by_user_guid ')
     return affidavit_dict
Ejemplo n.º 3
0
    def approve_or_reject(org_id: int, is_approved: bool, user: UserModel):
        """Mark the affdiavit as approved or rejected."""
        current_app.logger.debug('<find_affidavit_by_org_id ')
        affidavit: AffidavitModel = AffidavitModel.find_by_org_id(org_id)
        affidavit.decision_made_by = user.username
        affidavit.decision_made_on = datetime.now()
        affidavit.status_code = AffidavitStatus.APPROVED.value if is_approved else AffidavitStatus.REJECTED.value

        current_app.logger.debug('>find_affidavit_by_org_id ')
        return Affidavit(affidavit)
Ejemplo n.º 4
0
    def create_affidavit(token_info: Dict, affidavit_info: Dict):
        """Create a new affidavit record."""
        current_app.logger.debug('<create_affidavit ')
        user = UserService.find_by_jwt_token(token=token_info)
        # If the user already have a pending affidavit, raise error
        existing_affidavit = AffidavitModel.find_pending_by_user_id(
            user_id=user.identifier)
        if existing_affidavit is not None:
            raise BusinessException(Error.ACTIVE_AFFIDAVIT_EXISTS, None)

        contact = affidavit_info.pop('contact')
        affidavit_model = AffidavitModel(
            issuer=affidavit_info.get('issuer'),
            document_id=affidavit_info.get('documentId'),
            status_code=AffidavitStatus.PENDING.value,
            user_id=user.identifier)
        affidavit_model.add_to_session()

        # Save contact for the affidavit
        if contact:
            contact = ContactModel(**camelback2snake(contact))
            contact.add_to_session()

            contact_link = ContactLinkModel()
            contact_link.affidavit = affidavit_model
            contact_link.contact = contact
            contact_link.add_to_session()

        affidavit_model.save()

        return Affidavit(affidavit_model)
Ejemplo n.º 5
0
    def approve_or_reject_bceid_admin(admin_user_id: int, is_approved: bool,
                                      user: UserModel):
        """Mark the BCeId Admin Affidavit as approved or rejected."""
        current_app.logger.debug('<approve_or_reject_bceid_admin ')
        affidavit: AffidavitModel = AffidavitModel.find_pending_by_user_id(
            admin_user_id)
        if affidavit is None:
            raise BusinessException(Error.DATA_NOT_FOUND, None)

        affidavit.decision_made_by = user.username
        affidavit.decision_made_on = datetime.now()
        affidavit.status_code = AffidavitStatus.APPROVED.value if is_approved else AffidavitStatus.REJECTED.value

        current_app.logger.debug('>approve_or_reject_bceid_admin ')
        return Affidavit(affidavit)
Ejemplo n.º 6
0
 def approve_or_reject(org_id: int, is_approved: bool, user: UserModel):
     """Mark the affidavit as approved or rejected."""
     current_app.logger.debug('<approve_or_reject ')
     # In order to get the pending affidavit to be reviewed, we need to filter out the following cases
     # 1. Inactive affidavits - usually while the old affidavit is made inactive
     # while the task is put on hold and the user uploads a new one.
     # 2. When the user account request is rejected, then user creates a new account
     filtered_affidavit_statuses = [
         AffidavitStatus.INACTIVE.value, AffidavitStatus.REJECTED.value
     ]
     affidavit: AffidavitModel = AffidavitModel.find_by_org_id(
         org_id, filtered_affidavit_statuses)
     affidavit.decision_made_by = user.username
     affidavit.decision_made_on = datetime.now()
     affidavit.status_code = AffidavitStatus.APPROVED.value if is_approved else AffidavitStatus.REJECTED.value
     current_app.logger.debug('>approve_or_reject')
     return Affidavit(affidavit)
Ejemplo n.º 7
0
    def create_affidavit(affidavit_info: Dict):
        """Create a new affidavit record."""
        current_app.logger.debug('<create_affidavit ')
        user = UserService.find_by_jwt_token()
        # If the user already have a pending affidavit, raise error
        existing_affidavit: AffidavitModel = AffidavitModel.find_pending_by_user_id(
            user_id=user.identifier)
        trigger_task_update = False
        if existing_affidavit is not None:
            # inactivate the current affidavit
            existing_affidavit.status_code = AffidavitStatus.INACTIVE.value
            existing_affidavit.flush()
            trigger_task_update = True

        contact = affidavit_info.pop('contact')
        affidavit_model = AffidavitModel(
            issuer=affidavit_info.get('issuer'),
            document_id=affidavit_info.get('documentId'),
            status_code=AffidavitStatus.PENDING.value,
            user_id=user.identifier)
        affidavit_model.add_to_session()

        # Save contact for the affidavit
        if contact:
            contact = ContactModel(**camelback2snake(contact))
            contact.add_to_session()

            contact_link = ContactLinkModel()
            contact_link.affidavit = affidavit_model
            contact_link.contact = contact
            contact_link.add_to_session()

        affidavit_model.save()

        if trigger_task_update:
            Affidavit._modify_task(user)

        return Affidavit(affidavit_model)
Ejemplo n.º 8
0
class Org:  # pylint: disable=too-many-public-methods
    """Manages all aspects of Org data.

    This service manages creating, updating, and retrieving Org data via the Org model.
    """
    def __init__(self, model):
        """Return an Org Service."""
        self._model = model

    @ServiceTracing.disable_tracing
    def as_dict(self):
        """Return the internal Org model as a dictionary.

        None fields are not included.
        """
        org_schema = OrgSchema()
        obj = org_schema.dump(self._model, many=False)
        return obj

    @staticmethod
    def create_org(org_info: dict, user_id):
        """Create a new organization."""
        current_app.logger.debug('<create_org ')
        # bcol is treated like an access type as well;so its outside the scheme
        mailing_address = org_info.pop('mailingAddress', None)
        payment_info = org_info.pop('paymentInfo', {})
        product_subscriptions = org_info.pop('productSubscriptions', None)

        bcol_profile_flags = None
        response = Org._validate_and_raise_error(org_info)
        # If the account is created using BCOL credential, verify its valid bc online account
        bcol_details_response = response.get('bcol_response', None)
        if bcol_details_response is not None and (
                bcol_details := bcol_details_response.json()) is not None:
            Org._map_response_to_org(bcol_details, org_info)
            bcol_profile_flags = bcol_details.get('profileFlags')

        access_type = response.get('access_type')

        # set premium for GOVM accounts..TODO remove if not needed this logic
        if access_type == AccessType.GOVM.value:
            org_info.update({'typeCode': OrgType.PREMIUM.value})

        org = OrgModel.create_from_dict(camelback2snake(org_info))
        org.access_type = access_type

        # Set the status based on access type
        # Check if the user is APPROVED else set the org status to PENDING

        if access_type == AccessType.GOVM.value:
            org.status_code = OrgStatus.PENDING_INVITE_ACCEPT.value

        # If mailing address is provided, save it
        if mailing_address:
            Org.add_contact_to_org(mailing_address, org)

        # create the membership record for this user if its not created by staff and access_type is anonymous
        Org.create_membership(access_type, org, user_id)

        if product_subscriptions is not None:
            subscription_data = {'subscriptions': product_subscriptions}
            ProductService.create_product_subscription(
                org.id, subscription_data=subscription_data, skip_auth=True)

        ProductService.create_subscription_from_bcol_profile(
            org.id, bcol_profile_flags)

        Org._create_payment_for_org(mailing_address, org, payment_info, True)

        # TODO do we have to check anything like this below?
        # if payment_account_status == PaymentAccountStatus.FAILED:
        # raise BusinessException(Error.ACCOUNT_CREATION_FAILED_IN_PAY, None)

        # Send an email to staff to remind review the pending account
        is_staff_review_needed = access_type in (
            AccessType.EXTRA_PROVINCIAL.value, AccessType.REGULAR_BCEID.value,
            AccessType.GOVN.value
        ) and not AffidavitModel.find_approved_by_user_id(user_id=user_id)

        user = UserModel.find_by_jwt_token()
        if is_staff_review_needed:
            Org._create_staff_review_task(org, user)

        org.commit()

        current_app.logger.info(f'<created_org org_id:{org.id}')

        return Org(org)
Ejemplo n.º 9
0
    def delete_org(org_id):
        """Soft-Deletes an Org.

        Only admin can perform this.
        1 - All businesses gets unaffiliated.
        2 - All team members removed.
        3 - If there is any credit on the account then cannot be deleted.

        Premium:
        1 - If there is any active PAD transactions going on, then cannot be deleted.

        """
        current_app.logger.debug(f'<Delete Org {org_id}')
        # Affiliation uses OrgService, adding as local import
        # pylint:disable=import-outside-toplevel, cyclic-import
        from auth_api.services.affiliation import Affiliation as AffiliationService

        check_auth(one_of_roles=(ADMIN, STAFF), org_id=org_id)

        org: OrgModel = OrgModel.find_by_org_id(org_id)
        if not org:
            raise BusinessException(Error.DATA_NOT_FOUND, None)
        if org.status_code not in (OrgStatus.ACTIVE.value,
                                   OrgStatus.PENDING_INVITE_ACCEPT.value):
            raise BusinessException(Error.NOT_ACTIVE_ACCOUNT, None)

        # Deactivate pay account
        Org._delete_pay_account(org_id)

        # Find all active affiliations and remove them.
        entities = AffiliationService.find_affiliations_by_org_id(org_id)
        for entity in entities:
            AffiliationService.delete_affiliation(
                org_id=org_id,
                business_identifier=entity['business_identifier'],
                reset_passcode=True)

        # Deactivate all members.
        members = MembershipModel.find_members_by_org_id(org_id)
        for member in members:
            member.status = Status.INACTIVE.value
            member.flush()

            user: UserModel = UserModel.find_by_id(member.user_id)
            # Remove user from keycloak group if they are not part of any orgs
            if len(MembershipModel.find_orgs_for_user(member.user_id)) == 0:
                KeycloakService.remove_from_account_holders_group(
                    user.keycloak_guid)

            # If the admin is BCeID user, mark the affidavit INACTIVE.
            if user.login_source == LoginSource.BCEID.value and member.membership_type_code == ADMIN:
                affidavit: AffidavitModel = AffidavitModel.find_approved_by_user_id(
                    user.id)
                if affidavit:
                    affidavit.status_code = AffidavitStatus.INACTIVE.value
                    affidavit.flush()

        # Set the account as INACTIVE
        org.status_code = OrgStatus.INACTIVE.value
        org.save()

        current_app.logger.debug('org Inactivated>')
Ejemplo n.º 10
0
    def create_org(
            org_info: dict,
            user_id,  # pylint: disable=too-many-locals, too-many-statements, too-many-branches
            token_info: Dict = None,
            bearer_token: str = None,
            origin_url: str = None):
        """Create a new organization."""
        current_app.logger.debug('<create_org ')
        # bcol is treated like an access type as well;so its outside the scheme
        bcol_credential = org_info.pop('bcOnlineCredential', None)
        mailing_address = org_info.pop('mailingAddress', None)
        payment_info = org_info.pop('paymentInfo', {})
        selected_payment_method = payment_info.get('paymentMethod', None)
        org_type = org_info.get('typeCode', OrgType.BASIC.value)
        branch_name = org_info.get('branchName', None)
        bcol_profile_flags = None

        # If the account is created using BCOL credential, verify its valid bc online account
        if bcol_credential:
            bcol_response = Org.get_bcol_details(bcol_credential,
                                                 bearer_token).json()
            Org._map_response_to_org(bcol_response, org_info)
            bcol_profile_flags = bcol_response.get('profileFlags')

        is_staff_admin = token_info and Role.STAFF_CREATE_ACCOUNTS.value in token_info.get(
            'realm_access').get('roles')
        is_bceid_user = token_info and token_info.get(
            'loginSource', None) == LoginSource.BCEID.value

        Org.validate_account_limit(is_staff_admin, user_id)

        access_type = Org.validate_access_type(is_bceid_user, is_staff_admin,
                                               org_info)

        # Always check duplicated name for all type of account.
        Org.raise_error_if_duplicate_name(org_info['name'], branch_name)

        # set premium for GOVM accounts..TODO remove if not needed this logic
        if access_type == AccessType.GOVM.value:
            org_type = OrgType.PREMIUM.value
            org_info.update({'typeCode': OrgType.PREMIUM.value})

        org = OrgModel.create_from_dict(camelback2snake(org_info))
        org.access_type = access_type
        # If the account is anonymous or govm set the billable value as False else True
        org.billable = access_type not in [
            AccessType.ANONYMOUS.value, AccessType.GOVM.value
        ]
        # Set the status based on access type
        # Check if the user is APPROVED else set the org status to PENDING
        # Send an email to staff to remind review the pending account
        if access_type in (AccessType.EXTRA_PROVINCIAL.value, AccessType.REGULAR_BCEID.value) \
                and not AffidavitModel.find_approved_by_user_id(user_id=user_id):
            Org._handle_bceid_status_and_notification(org, origin_url,
                                                      token_info)

        if access_type == AccessType.GOVM.value:
            org.status_code = OrgStatus.PENDING_INVITE_ACCEPT.value

        # If mailing address is provided, save it
        if mailing_address:
            Org.add_contact_to_org(mailing_address, org)

        # create the membership record for this user if its not created by staff and access_type is anonymous
        Org.create_membership(access_type, is_staff_admin, org, user_id)

        # dir search and GOVM doesnt need default products
        if access_type not in (AccessType.ANONYMOUS.value,
                               AccessType.GOVM.value):
            ProductService.create_default_product_subscriptions(
                org, bcol_profile_flags, is_new_transaction=False)

        payment_method = Org._validate_and_get_payment_method(
            selected_payment_method,
            OrgType[org_type],
            access_type=access_type)

        user_name = ''
        if payment_method == PaymentMethod.PAD.value:  # to get the pad accepted date
            user: UserModel = UserModel.find_by_jwt_token(token=token_info)
            user_name = user.username

        Org._create_payment_settings(org, payment_info, payment_method,
                                     mailing_address, user_name, True)

        # TODO do we have to check anything like this below?
        # if payment_account_status == PaymentAccountStatus.FAILED:
        # raise BusinessException(Error.ACCOUNT_CREATION_FAILED_IN_PAY, None)

        org.commit()

        current_app.logger.info(f'<created_org org_id:{org.id}')

        return Org(org)
Ejemplo n.º 11
0
    def create_org(
            org_info: dict,
            user_id,  # pylint: disable=too-many-locals, too-many-statements, too-many-branches
            token_info: Dict = None,
            bearer_token: str = None,
            origin_url: str = None):
        """Create a new organization."""
        current_app.logger.debug('<create_org ')
        # bcol is treated like an access type as well;so its outside the scheme
        bcol_credential = org_info.pop('bcOnlineCredential', None)
        mailing_address = org_info.pop('mailingAddress', None)
        payment_info = org_info.pop('paymentInfo', {})
        selected_payment_method = payment_info.get('paymentMethod', None)
        org_type = org_info.get('typeCode', OrgType.BASIC.value)

        # If the account is created using BCOL credential, verify its valid bc online account
        if bcol_credential:
            bcol_response = Org.get_bcol_details(bcol_credential, org_info,
                                                 bearer_token).json()
            Org._map_response_to_org(bcol_response, org_info)

        is_staff_admin = token_info and Role.STAFF_CREATE_ACCOUNTS.value in token_info.get(
            'realm_access').get('roles')
        is_bceid_user = token_info and token_info.get(
            'loginSource', None) == LoginSource.BCEID.value

        Org.validate_account_limit(is_staff_admin, user_id)

        access_type = Org.validate_access_type(is_bceid_user, is_staff_admin,
                                               org_info)

        duplicate_check = (org_type
                           == OrgType.BASIC.value) or (not bcol_credential)
        if duplicate_check:  # Allow duplicate names if premium and link to bcol
            Org.raise_error_if_duplicate_name(org_info['name'])

        org = OrgModel.create_from_dict(camelback2snake(org_info))
        org.access_type = access_type
        # If the account is anonymous set the billable value as False else True
        org.billable = access_type != AccessType.ANONYMOUS.value

        # Set the status based on access type
        # Check if the user is APPROVED else set the org status to PENDING
        # Send an email to staff to remind review the pending account
        if access_type in (AccessType.EXTRA_PROVINCIAL.value, AccessType.REGULAR_BCEID.value) \
                and not AffidavitModel.find_approved_by_user_id(user_id=user_id):
            org.status_code = OrgStatus.PENDING_AFFIDAVIT_REVIEW.value
            user = UserModel.find_by_jwt_token(token=token_info)
            Org.send_staff_review_account_reminder(user, org.id, origin_url)

        # If mailing address is provided, save it
        if mailing_address:
            Org.add_contact_to_org(mailing_address, org)

        # create the membership record for this user if its not created by staff and access_type is anonymous
        Org.create_membership(access_type, is_staff_admin, org, user_id)

        Org.add_product(org.id, token_info)
        payment_method = Org._validate_and_get_payment_method(
            selected_payment_method, OrgType[org_type])
        Org._create_payment_settings(org, payment_info, payment_method,
                                     mailing_address, True)

        # TODO do we have to check anything like this below?
        # if payment_account_status == PaymentAccountStatus.FAILED:
        # raise BusinessException(Error.ACCOUNT_CREATION_FAILED_IN_PAY, None)

        org.commit()

        current_app.logger.info(f'<created_org org_id:{org.id}')

        return Org(org)