def clean_amount(self):
        from cc3.cyclos import backends

        available_balance = backends.get_account_status(
            self.user.username).accountStatus.availableBalance

        if self.cleaned_data['amount'] > available_balance:
            raise forms.ValidationError(
                _(u'You do not have sufficient credit.'))
        return self.cleaned_data['amount']
    def clean_amount(self):
        from cc3.cyclos import backends

        # NB need to use availableBalance here really - as overdrafts are
        # possible.
        available_balance = backends.get_account_status(
            self.user.username).accountStatus.availableBalance
        if self.cleaned_data['amount'] > available_balance:
            raise forms.ValidationError(
                _(u'You do not have sufficient credit to complete the payment')
            )
        return self.cleaned_data['amount']
Exemple #3
0
    def _classify_balances(self):
        """
        Given a couple of accepted dates and a queryset of all registered
        ``BusinessProfiles``, retrieves the balance for each business and
        classifies as currently debtors or creditors.

        This method is called during the class instantiation.
        """
        # only process businesses with account holder, IBAN, BIC, Mandate and
        # signature date filled in
        businesses_to_classify = self.businesses.exclude(
            iban__isnull=True).exclude(bic_code__isnull=True).exclude(
                mandate_id__isnull=True).exclude(
                    signature_date__isnull=True).exclude(iban='').exclude(
                        bic_code='').exclude(account_holder='')

        for business in businesses_to_classify:
            # ignore in case of exceptions
            available_balance = None

            try:
                available_balance = backends.get_account_status(
                    business.profile.user.username).accountStatus.balance
            except MemberNotFoundException:
                LOG.error(u'Member not found (in Cyclos): {0}'.format(
                    business.profile.user.username))

            # Store the business and its balance in the correspondent group.

            # if current balance, ignore business
            if not available_balance:
                continue

            # Cast `available_balance` to `int` and deduct the amount of euros.
            euros = getattr(settings, 'CC3_CURRENCY_CONVERSION', 100)
            balance = Decimal(available_balance / euros).quantize(
                Decimal(10)**-2)

            if balance > 0:
                self.credit_transactions[business] = balance
                self.total_credit_transactions += balance
            else:
                # Balances must always be positive.
                balance = -balance
                if not business.latest_payment_date:
                    self.debit_transactions['FRST'][business] = balance
                else:
                    self.debit_transactions['RCUR'][business] = balance
                    self.total_debit_transactions_rcur += balance
                self.total_debit_transactions += balance

                business.latest_payment_date = self.date_to
                business.save()
    def validate_amount(self, attrs, source):
        amount = attrs[source]
        sender = self.context['user']
        available_balance = backends.get_account_status(
            sender.username).accountStatus.availableBalance

        if amount > available_balance:
            raise serializers.ValidationError(
                _(u'You do not have sufficient credit to complete the payment')
            )

        # TODO: Update to validate integer for systems with integer currencies

        return attrs
Exemple #5
0
class BulkPurchaseAdminForm(forms.ModelForm):
    model = BulkPurchase

    def clean(self):
        from .utils import get_current_draw
        from cc3.cyclos import backends
#        from cc3.cyclos.models import User

        cd = self.cleaned_data
        current_draw = get_current_draw()

        if current_draw is None:
            raise forms.ValidationError(_(u"There is no current draw, bulk "
                                          u"purchases are not available"))

        if cd['num_tickets'] <= 0:
            raise forms.ValidationError(_(u"Please enter a number greater than "
                                          u"1"))

        is_business = False
        try:
            business_cc3_profile = cd['purchased_by'].get_profile()
            is_business = business_cc3_profile.is_business_profile()
        except Exception, e:
            pass

        if not is_business:
            raise forms.ValidationError(_(u"Admin users can only make bulk "
                                          u"ticket purchases for Businesses"))

        # validate user has enough credit
        available_balance = backends.get_account_status(
            cd['purchased_by'].username).accountStatus.availableBalance
        ticket_cost = cd['num_tickets'] * current_draw.ticket_price
        if ticket_cost > available_balance:
            raise forms.ValidationError(
                _(u"You don't have enough credit"))

        # not currently validating max tickets in draw, so no point doing this:
        #        if cd['num_tickets'] > current_draw.remaining_tickets:
        #            raise forms.ValidationError(_(u"Only {0} tickets left
        # for draw".format(current_draw.remaining_tickets)))

        return cd
def balance(request):
    _balance = upper_credit_limit = lower_credit_limit = None
    has_account = False

    if request.user.is_authenticated():
        if not request.user.is_superuser:
            try:
                # http://www.cyclos.org/wiki/index.php/Web_services#Model_data_details
                account_status = backends.get_account_status(
                    request.user.username).accountStatus
                _balance = account_status.balance
                upper_credit_limit = account_status.upperCreditLimit
                lower_credit_limit = account_status.creditLimit
                has_account = True
            except MemberNotFoundException:
                LOG.info(u"Member '{0}' not present in Cyclos backend".format(
                    request.user))
                has_account = False
                _balance = None
            # except ExpatError:
            #     LOG.info(u"Member '{0}' not present in Cyclos backend".format(
            #         request.user))
            #     has_account = False
            #     _balance = None
            except ExpatError as e:
                messages.add_message(
                    request, messages.WARNING,
                    _("Unable to get account "
                      "details at present"))
                LOG.info(u"Exception {0}".format(e))
                has_account = False
                _balance = None

    if upper_credit_limit:
        upper_credit_limit = int(upper_credit_limit)
    if lower_credit_limit:
        lower_credit_limit = int(lower_credit_limit)
    return {
        'balance': _balance,
        'has_account': has_account,
        'upper_credit_limit': upper_credit_limit,
        'lower_credit_limit': lower_credit_limit
    }
def check_user_can_buy_tickets(num_tickets, user, draw=None,
                               check_balance=True):
    """Check whether a user can buy the requested number of tickets in draw

    If draw is None, default to the "current" draw
    """
    if not draw:
        draw = get_current_draw()

    if not draw:
        raise TicketException(_(u"There is no Draw in progress"))

    num_can_buy = draw.max_tickets_user_can_buy(user)
    if num_can_buy <= 0:
        raise TicketException(
            _(u"You have already bought the maximum of {0} tickets".format(
                draw.max_tickets_per_person)))
    if num_can_buy < num_tickets:
        per_person = draw.max_tickets_per_person
        if num_can_buy < per_person:
            raise TicketException(
                _(u"You already have {0} ticket(s), you can buy a maximum of "
                  u"{1} ticket(s) more".format(
                    (per_person-num_can_buy), num_can_buy)))

        raise TicketException(
            _(u"You can buy a maximum of {0} tickets".format(num_can_buy)))

    available_balance = backends.get_account_status(
        user.username).accountStatus.availableBalance
    if check_balance:
        ticket_cost = num_tickets * draw.ticket_price
        if ticket_cost > available_balance:
            raise TicketException(
                _(u"You don't have enough credit"))

    return True
Exemple #8
0
    def reset_balance(self):
        """
        Resets the current user Positoos balance to zero.

        Taking into account the ``accountStatus.balance`` of the user, it makes
        a payment from or to the system for a similar amount, turning the
        balance equal to zero.
        """

        # Getting settings - defaulting to Positoos values if settings missing.
        debit_transfer_type_id = getattr(settings,
                                         'SEPA_EXPORT_DEBIT_TRANSFER_TYPE_ID',
                                         39)
        debit_transfer_description = getattr(
            settings, 'SEPA_EXPORT_DEBIT_TRANSFER_DESCRIPTION',
            "Bijschrijving na automatisch incasso")

        credit_transfer_type_id = getattr(
            settings, 'SEPA_EXPORT_CREDIT_TRANSFER_TYPE_ID', 36)
        credit_transfer_description = getattr(
            settings, 'SEPA_EXPORT_CREDIT_TRANSFER_DESCRIPTION',
            "Afschrijving na automatisch incasso")

        vat_rate = getattr(settings, 'VAT_RATE', 21)

        try:
            balance = backends.get_account_status(
                self.profile.user.username).accountStatus.balance
        except MemberNotFoundException:
            LOG.error(u'Member not found (in Cyclos): {0}'.format(
                self.profile.user.username))
            return False
        LOG.info(u"Resetting balance for user {0}, current balance {1}".format(
            self.profile.user.username, balance))
        if balance == 0:
            LOG.info(u"Not resetting balance, no transaction required as "
                     u"balance is already 0")
            return True

        try:
            if balance > 0:
                # Positive balance. Move the cash from user to the system.
                # From Organisatie rekening (member) to Reserve account
                # (system),
                # Transfer type ID 36.
                # Transfer Type 'Take out of circulation'.
                LOG.info(u"Credit transfer, ID: {0}, {1}".format(
                    credit_transfer_type_id, credit_transfer_description))
                backends.to_system_payment(
                    self.profile.user.username,
                    balance,
                    credit_transfer_description,
                    transfer_type_id=credit_transfer_type_id)
                LOG.info(
                    _(u'Monthly balance for business {0} reconciled. {1} '
                      u'Positoos recovered by Cyclos system'.format(
                          self.profile.user.username, balance)))

                # biz a/c b
                # Create euro invoice from Positoos BV (marked unpaid).
                today = datetime.date.today()

                currency, created = Currency.objects.get_or_create(
                    code='EUR', defaults={
                        'name': 'Euro',
                        'symbol': '€'
                    })
                nr_days_due = getattr(settings,
                                      "SEPA_EXPORT_CREDIT_INVOICE_DAYS_DUE",
                                      15)
                sender, created = User.objects.get_or_create(username=getattr(
                    settings, "CC3_BANK_USER", "Positoos Reserve"))
                to_be_paid_status = PaymentStatus.objects.filter(
                    is_active=True, is_paid=False)
                if not to_be_paid_status:
                    LOG.error(u"Payment status with 'is_active' True and "
                              u"'is_paid' False is not defined")
                    return False
                to_be_paid_status = to_be_paid_status[0]
                invoice_description = credit_transfer_description

                invoice_type = "SEPA export"
                invoice = Invoice.objects.create(
                    from_user=sender,
                    to_user=self.profile.user,
                    inv_date=today,
                    due_date=today + datetime.timedelta(days=nr_days_due),
                    currency=currency,
                    payment_status=to_be_paid_status,
                    automatic_invoice=True,
                    admin_comment=u"Automatic invoice of type {0}".format(
                        invoice_type))

                InvoiceLine.objects.create(invoice=invoice,
                                           description=invoice_description,
                                           quantity=1,
                                           amount=balance,
                                           tax_rate=vat_rate)
            else:
                # Negative balance. Move some cash from system to user.
                # From Reserve account (system) to Organisatie rekening
                # (member).
                # Transfer type ID 39.
                # Transfer Type 'Acquiring Positoos'.
                LOG.info(u"Debit transfer, ID: {0}, {1}".format(
                    debit_transfer_type_id, debit_transfer_description))
                backends.from_system_payment(
                    self.profile.user.username,
                    -balance,
                    debit_transfer_description,
                    transfer_type_id=debit_transfer_type_id)
                LOG.info(
                    _(u'Monthly balance for business {0} reconciled. {1} '
                      u'Positoos paid by Cyclos system'.format(
                          self.profile.user.username, balance)))
        except TransactionException, e:
            LOG.error(u'Unable to perform balance reset. The transaction '
                      u'failed: {0}\nSure the user is a business?'.format(e))
            return False
Exemple #9
0
    def reset_balance(self):
        """
        Resets the current user Positoos balance to zero.

        Taking into account the ``accountStatus.balance`` of the user, it makes
        a payment from or to the system for a similar amount, turning the
        balance equal to zero.
        """
        # Getting settings - defaulting to Positoos values if settings missing.
        debit_transfer_type_id = getattr(settings,
                                         'SEPA_EXPORT_DEBIT_TRANSFER_TYPE_ID',
                                         39)
        debit_transfer_description = getattr(
            settings, 'SEPA_EXPORT_DEBIT_TRANSFER_DESCRIPTION',
            "Bijschrijving na automatisch incasso")

        credit_transfer_type_id = getattr(
            settings, 'SEPA_EXPORT_CREDIT_TRANSFER_TYPE_ID', 36)
        credit_transfer_description = getattr(
            settings, 'SEPA_EXPORT_CREDIT_TRANSFER_DESCRIPTION',
            "Afschrijving na automatisch incasso")

        to_date = datetime.date.today()
        from_date = last_month_first_of_month()
        div_by = Decimal("100.00")

        try:
            balance = backends.get_account_status(
                self.profile.user.username).accountStatus.balance

            transactions = backends.transactions(
                username=self.profile.user.username,
                from_date=from_date,
                to_date=to_date)

        except MemberNotFoundException:
            LOG.error(u'Member not found (in Cyclos): {0}'.format(
                self.profile.user.username))
            return False
        LOG.info(u"Resetting balance for user {0}, current balance {1}".format(
            self.profile.user.username, balance))
        if balance == 0:
            LOG.info(u"Not resetting balance, no transaction required as "
                     u"balance is already 0")
            return True

        invoice_description = self.invoice_description(
            from_date,
            to_date,
            transactions,
            reset_transfer_descriptions=[
                debit_transfer_description, credit_transfer_description
            ])

        try:
            if balance > 0:
                # Positive balance. Move the cash from user to the system.
                # From Organisatie rekening (member) to Reserve account
                # (system),
                # Transfer type ID 36.
                # Transfer Type 'Take out of circulation'.
                LOG.info(u"Credit transfer, ID: {0}, {1}".format(
                    credit_transfer_type_id, credit_transfer_description))
                backends.to_system_payment(
                    self.profile.user.username,
                    balance,
                    credit_transfer_description,
                    transfer_type_id=credit_transfer_type_id)
                LOG.info(
                    _(u'Monthly balance for business {0} reconciled. {1} '
                      u'Positoos recovered by Cyclos system'.format(
                          self.profile.user.username, balance)))
                self.create_invoice((balance / div_by) * Decimal("-1.00"),
                                    invoice_description)
            else:
                # Negative balance. Move some cash from system to user.
                # From Reserve account (system) to Organisatie rekening
                # (member).
                # Transfer type ID 39.
                # Transfer Type 'Acquiring Positoos'.
                LOG.info(u"Debit transfer, ID: {0}, {1}".format(
                    debit_transfer_type_id, debit_transfer_description))
                backends.from_system_payment(
                    self.profile.user.username,
                    -balance,
                    debit_transfer_description,
                    transfer_type_id=debit_transfer_type_id)
                LOG.info(
                    _(u'Monthly balance for business {0} reconciled. {1} '
                      u'Positoos paid by Cyclos system'.format(
                          self.profile.user.username, balance)))
                self.create_invoice((balance / div_by) * Decimal("-1.00"),
                                    invoice_description)
        except TransactionException, e:
            LOG.error(u'Unable to perform balance reset. The transaction '
                      u'failed: {0}\nSure the user is a business?'.format(e))
            return False
    def test_account_status(self):
        sender = get_username()
        email = sender + '@example.com'
        member = backends.new(sender, 'Sender', email, 'Test Business',
                              USER_GROUP_ID)
        self.assertIsNotNone(member)
        receiver = get_username()
        member = backends.new(receiver, 'Receiver', receiver + '@example.com',
                              'Test Business', USER_GROUP_ID)
        self.assertIsNotNone(member)

        # test initial account status
        status = backends.get_account_status(sender)

        self.assertEqual(status.accountStatus.balance, Decimal('0'))
        self.assertEqual(status.accountStatus.availableBalance, Decimal('0'))
        self.assertEqual(status.accountStatus.reservedAmount, Decimal('0'))
        self.assertEqual(status.accountStatus.creditLimit, Decimal('0'))
        self.assertIsNone(status.accountStatus.upperCreditLimit)

        status = backends.get_account_status(receiver)

        self.assertEqual(status.accountStatus.balance, Decimal('0'))
        self.assertEqual(status.accountStatus.availableBalance, Decimal('0'))
        self.assertEqual(status.accountStatus.reservedAmount, Decimal('0'))
        self.assertEqual(status.accountStatus.creditLimit, Decimal('0'))
        self.assertIsNone(status.accountStatus.upperCreditLimit)

        # set credit limit
        limit = 10000.0
        self._set_credit_limit(email, limit)

        status = backends.get_account_status(sender)

        self.assertEqual(status.accountStatus.balance, Decimal('0'))
        self.assertEqual(status.accountStatus.availableBalance, Decimal(limit))
        self.assertEqual(status.accountStatus.reservedAmount, Decimal('0'))
        self.assertEqual(status.accountStatus.creditLimit, Decimal(limit))
        self.assertIsNone(status.accountStatus.upperCreditLimit)

        # transact
        amount = 10.00
        description = 'a test transaction'
        transaction = backends.user_payment(sender, receiver, amount,
                                            description)
        self.assertIsNotNone(transaction)
        status = backends.get_account_status(sender)

        self.assertEqual(status.accountStatus.balance, Decimal(amount * -1.0))
        self.assertEqual(status.accountStatus.availableBalance,
                         Decimal(limit - amount))
        self.assertEqual(status.accountStatus.reservedAmount, Decimal('0'))
        self.assertEqual(status.accountStatus.creditLimit, Decimal(limit))
        self.assertIsNone(status.accountStatus.upperCreditLimit)

        status = backends.get_account_status(receiver)

        self.assertEqual(status.accountStatus.balance, Decimal(amount))
        self.assertEqual(status.accountStatus.availableBalance,
                         Decimal(amount))
        self.assertEqual(status.accountStatus.reservedAmount, Decimal('0'))
        self.assertEqual(status.accountStatus.creditLimit, Decimal('0'))
        self.assertIsNone(status.accountStatus.upperCreditLimit)