예제 #1
0
    def add_membership_payment_record(self, ctx, membership: Membership,
                                      free: bool):
        LOG.debug("membership_add_membership_payment_record",
                  extra=log_extra(ctx,
                                  duration=membership.duration,
                                  membership_accoun=membership.account))

        if free and not Roles.TRESO_WRITE.value in ctx.get(CTX_ROLES):
            raise UnauthorizedError(
                "Impossibilité de faire une cotisation gratuite")

        payment_method = self.payment_method_repository.get_by_id(
            ctx, membership.payment_method)
        asso_account, _ = self.account_repository.search_by(
            ctx,
            limit=1,
            filter_=AbstractAccount(
                name=KnownAccountExpense.ASSOCIATION_EXPENCE.value))
        if len(asso_account) != 1:
            raise AccountNotFoundError(
                KnownAccountExpense.ASSOCIATION_EXPENCE.value)
        tech_account, _ = self.account_repository.search_by(
            ctx,
            limit=1,
            filter_=AbstractAccount(
                name=KnownAccountExpense.TECHNICAL_EXPENSE.value))
        if len(tech_account) != 1:
            raise AccountNotFoundError(
                KnownAccountExpense.TECHNICAL_EXPENSE.value)
        src_account = self.account_repository.get_by_id(
            ctx, membership.account)
        price = self.duration_price[membership.duration]  # Expressed in EUR.
        if price == 50 and not membership.has_room:
            price = 9
        duration_str = self.duration_string.get(membership.duration)
        title = f'Internet - {duration_str}'

        self.transaction_repository.create(
            ctx,
            AbstractTransaction(value=9 if not free else 0,
                                src=src_account.id,
                                dst=asso_account[0].id,
                                name=title + " (gratuit)" if free else title,
                                payment_method=payment_method.id))
        if price > 9 and not free:
            self.transaction_repository.create(
                ctx,
                AbstractTransaction(value=price - 9,
                                    src=src_account.id,
                                    dst=tech_account[0].id,
                                    name=title,
                                    payment_method=payment_method.id))
예제 #2
0
    def test_unknown_account(
            self, ctx, mock_membership_repository: MembershipRepository,
            mock_member_repository: MemberRepository,
            mock_account_repository: AccountRepository, sample_member: Member,
            mock_charter_repository: CharterRepository,
            sample_subscription_duration_account_payment_method:
        SubscriptionBody, sample_membership_pending_rules: Membership,
            member_manager: MemberManager):
        mock_member_repository.get_by_id = MagicMock(
            return_value=(sample_member))
        mock_membership_repository.search = MagicMock(
            return_value=([sample_membership_pending_rules], 1))
        mock_account_repository.get_by_id = MagicMock(
            return_value=(None), side_effect=AccountNotFoundError(""))
        mock_charter_repository.get = MagicMock(
            return_value=str(datetime.datetime.today()))

        with raises(AccountNotFoundError):
            member_manager.update_subscription(
                ctx, sample_member.id,
                sample_subscription_duration_account_payment_method)

        mock_membership_repository.search.assert_called_once()
        mock_member_repository.get_by_id.assert_called_once()
        mock_account_repository.get_by_id.assert_called_once()
        mock_charter_repository.get.assert_called_once()
        mock_membership_repository.update.assert_not_called()
예제 #3
0
    def create(self, ctx, abstract_transaction: AbstractTransaction) -> object:
        session: Session = ctx.get(CTX_SQL_SESSION)

        now = datetime.now()

        admin_id = ctx.get(CTX_ADMIN)

        account_src = None
        if abstract_transaction.src is not None:
            account_src = session.query(Account).filter(
                Account.id == abstract_transaction.src).one_or_none()
            if not account_src:
                raise AccountNotFoundError(abstract_transaction.src)

        account_dst = None
        if abstract_transaction.dst is not None:
            account_dst = session.query(Account).filter(
                Account.id == abstract_transaction.dst).one_or_none()
            if not account_dst:
                raise AccountNotFoundError(abstract_transaction.dst)

        method = None
        if abstract_transaction.payment_method is not None:
            method = session.query(PaymentMethod).filter(
                PaymentMethod.id ==
                abstract_transaction.payment_method).one_or_none()
            if not method:
                raise PaymentMethodNotFoundError(
                    abstract_transaction.payment_method)

        transaction = SQLTransaction(
            src=account_src.id if account_src else None,
            dst=account_dst.id if account_dst else None,
            value=abstract_transaction.value,
            name=abstract_transaction.name,
            timestamp=now,
            attachments="",
            type=method.id if method else None,
            author_id=admin_id,
            pending_validation=abstract_transaction.pending_validation
            if abstract_transaction.pending_validation else False)

        with track_modifications(ctx, session, transaction):
            session.add(transaction)
        session.flush()

        return _map_transaction_sql_to_entity(transaction)
예제 #4
0
    def buy(self, ctx, member_id: int, payment_method_id: int, product_ids: List[int] = []) -> None:
        if not product_ids:
            raise ProductNotFoundError("None")

        payment_method = self.payment_method_repository.get_by_id(ctx, payment_method_id)
        dst_accounts, _ = self.account_repository.search_by(ctx, limit=1, filter_=AbstractAccount(name=KnownAccountExpense.TECHNICAL_EXPENSE.value))
        if not dst_accounts:
            raise AccountNotFoundError(KnownAccountExpense.TECHNICAL_EXPENSE.value)
        src_accounts, _ = self.account_repository.search_by(ctx, limit=1, filter_=AbstractAccount(member=member_id))
        if not src_accounts:
            raise AccountNotFoundError(KnownAccountExpense.TECHNICAL_EXPENSE.value)

        for i in product_ids:
            product = self.product_repository.get_by_id(ctx, i)

            _ = self.transaction_repository.create(
                ctx, 
                AbstractTransaction(
                    src=src_accounts[0].id,
                    dst=dst_accounts[0].id,
                    name=product.name,
                    value=product.selling_price,
                    payment_method=payment_method.id,
                ))
예제 #5
0
    def test_unknown_account(
            self, ctx, mock_membership_repository: MembershipRepository,
            mock_member_repository: MemberRepository,
            mock_account_repository: AccountRepository, sample_member: Member,
            mock_charter_repository: CharterRepository,
            sample_subscription_duration_account_payment_method:
        SubscriptionBody, member_manager: MemberManager):
        mock_member_repository.get_by_id = MagicMock(
            return_value=(sample_member))
        mock_membership_repository.search = MagicMock(return_value=([], 0))
        mock_account_repository.get_by_id = MagicMock(
            return_value=(None), side_effect=AccountNotFoundError(""))
        mock_charter_repository.get = MagicMock(
            return_value=str(datetime.datetime.today()))

        with raises(AccountNotFoundError):
            member_manager.create_subscription(
                ctx, sample_member.id,
                sample_subscription_duration_account_payment_method)
예제 #6
0
    def test_no_src_account(
            self, ctx, mock_payment_method_repository: PaymentMethodRepository,
            mock_account_repository: AccountRepository,
            member_manager: MemberManager, sample_membership_empty: Membership,
            sample_account1: Account, sample_payment_method: PaymentMethod):
        mock_payment_method_repository.get_by_id = MagicMock(
            return_value=(sample_payment_method)
        )  # in this test don't care of the return value, the most important thing is that the function does not raise NotFound exception
        mock_account_repository.search_by = MagicMock(
            side_effect=[([sample_account1], 0), ([sample_account1], 0)])
        mock_account_repository.get_by_id = MagicMock(
            side_effect=AccountNotFoundError(""))

        with raises(AccountNotFoundError):
            member_manager.add_membership_payment_record(
                ctx, sample_membership_empty, False)

        mock_payment_method_repository.get_by_id.assert_called_once()
        mock_account_repository.search_by.assert_called()
        mock_account_repository.get_by_id.assert_called_once()
예제 #7
0
    def create(self, ctx, abstract_account: Account) -> object:
        session: Session = ctx.get(CTX_SQL_SESSION)
        LOG.debug("sql_account_repository_create_called", extra=log_extra(ctx, account_type=abstract_account.account_type))

        now = datetime.now()

        account_type_query = session.query(AccountType)
        if abstract_account.account_type is not None:
            LOG.debug("sql_account_repository_search_account_type", extra=log_extra(ctx, account_type=abstract_account.account_type))
            account_type_query = account_type_query.filter(AccountType.id == abstract_account.account_type)
        else:
            account_type_query = account_type_query.filter(AccountType.name == "Adherent")

        account_type = account_type_query.one_or_none()
        if account_type is None:
            raise AccountNotFoundError(abstract_account.account_type)

        adherent = None
        if abstract_account.member is not None:
            adherent = session.query(Adherent).filter(Adherent.id == abstract_account.member).one_or_none()
            if not adherent:
                raise MemberNotFoundError(abstract_account.member)

        account = SQLAccount(
            name=abstract_account.name,
            actif=abstract_account.actif,
            type=account_type.id,
            creation_date=now,
            compte_courant=abstract_account.compte_courant,
            pinned=abstract_account.pinned,
            adherent_id=adherent.id if adherent else None
        )

        with track_modifications(ctx, session, account):
            session.add(account)
        session.flush()
        LOG.debug("sql_account_repository_create_finished", extra=log_extra(ctx, account_id=account.id))

        return _map_account_sql_to_entity(account)
예제 #8
0
    def update_subscription(self, ctx, member_id: int,
                            body: SubscriptionBody) -> None:
        member = self.member_repository.get_by_id(ctx, member_id)
        if not member:
            raise MemberNotFoundError(member_id)

        subscription = self.latest_subscription(ctx=ctx, member_id=member_id)
        if not subscription:
            raise MembershipNotFoundError()

        if subscription.status in [
                MembershipStatus.COMPLETE, MembershipStatus.CANCELLED,
                MembershipStatus.ABORTED
        ]:
            raise MembershipStatusNotAllowed(
                subscription.status,
                "membership already completed, cancelled or aborted")

        state = MembershipStatus(subscription.status)

        if state == MembershipStatus.PENDING_RULES:
            date_signed_minet = self.charter_repository.get(
                ctx, member_id=member_id, charter_id=1)
            if date_signed_minet is not None and date_signed_minet != "":
                LOG.debug(
                    "create_membership_record_switch_status_to_pending_payment_initial"
                )
                state = MembershipStatus.PENDING_PAYMENT_INITIAL
            else:
                raise CharterNotSigned(str(member_id))

        if body.duration is not None and body.duration != 0:
            if body.duration not in self.duration_price:
                LOG.warning("create_membership_record_no_price_defined",
                            extra=log_extra(ctx, duration=body.duration))
                raise NoPriceAssignedToThatDuration(body.duration)

        if state == MembershipStatus.PENDING_PAYMENT_INITIAL:
            if body.duration is not None:
                LOG.debug(
                    "create_membership_record_switch_status_to_pending_payment"
                )
                state = MembershipStatus.PENDING_PAYMENT

        if body.account is not None:
            account = self.account_repository.get_by_id(ctx, body.account)
            if not account:
                raise AccountNotFoundError(body.account)
        if body.payment_method is not None:
            payment_method = self.payment_method_repository.get_by_id(
                ctx, body.payment_method)
            if not payment_method:
                raise PaymentMethodNotFoundError(body.payment_method)

        if state == MembershipStatus.PENDING_PAYMENT:
            if body.account is not None and body.payment_method is not None:
                LOG.debug(
                    "create_membership_record_switch_status_to_pending_payment_validation"
                )
                state = MembershipStatus.PENDING_PAYMENT_VALIDATION

        try:
            self.membership_repository.update(ctx, subscription.uuid, body,
                                              state)
        except Exception:
            raise
예제 #9
0
    def create_subscription(self, ctx, member_id: int,
                            body: SubscriptionBody) -> Membership:
        """
        Core use case of ADH. Registers a membership.

        User story: As an admin, I can create a new membership record, so that a member can have internet access.
        :param ctx: context
        :param member_id: member_id
        :param membership: entity AbstractMembership

        :raise IntMustBePositiveException
        :raise NoPriceAssignedToThatDurationException
        :raise MemberNotFound
        :raise UnknownPaymentMethod
        """

        member = self.member_repository.get_by_id(ctx, member_id)
        if not member:
            raise MemberNotFoundError(member_id)

        latest_subscription = self.latest_subscription(ctx=ctx,
                                                       member_id=member_id)

        if latest_subscription and latest_subscription.status not in [
                MembershipStatus.COMPLETE.value,
                MembershipStatus.CANCELLED.value,
                MembershipStatus.ABORTED.value
        ]:
            raise MembershipAlreadyExist(latest_subscription.status)

        state = MembershipStatus.PENDING_RULES

        if state == MembershipStatus.PENDING_RULES:
            date_signed_minet = self.charter_repository.get(
                ctx, member_id=member_id, charter_id=1)
            if date_signed_minet is not None and date_signed_minet != "":
                LOG.debug(
                    "create_membership_record_switch_status_to_pending_payment_initial"
                )
                state = MembershipStatus.PENDING_PAYMENT_INITIAL

        if state == MembershipStatus.PENDING_PAYMENT_INITIAL:
            if body.duration is not None and body.duration != 0:
                if body.duration not in self.duration_price:
                    LOG.warning("create_membership_record_no_price_defined",
                                extra=log_extra(ctx, duration=body.duration))
                    raise NoPriceAssignedToThatDuration(body.duration)
                LOG.debug(
                    "create_membership_record_switch_status_to_pending_payment"
                )
                state = MembershipStatus.PENDING_PAYMENT

        if state == MembershipStatus.PENDING_PAYMENT:
            if body.account is not None and body.payment_method is not None:
                account = self.account_repository.get_by_id(ctx, body.account)
                if not account:
                    raise AccountNotFoundError(body.account)
                payment_method = self.payment_method_repository.get_by_id(
                    ctx, body.payment_method)
                if not payment_method:
                    raise PaymentMethodNotFoundError(body.payment_method)
                LOG.debug(
                    "create_membership_record_switch_status_to_pending_payment_validation"
                )
                state = MembershipStatus.PENDING_PAYMENT_VALIDATION

        try:
            membership_created = self.membership_repository.create(
                ctx, body, state)
        except UnknownPaymentMethod:
            LOG.warning("create_membership_record_unknown_payment_method",
                        extra=log_extra(ctx,
                                        payment_method=body.payment_method))
            raise

        LOG.info("create_membership_record",
                 extra=log_extra(ctx,
                                 membership_uuis=membership_created.uuid,
                                 membership_status=membership_created.status))

        return membership_created