Example #1
0
    def test_bic_model_field(self):
        valid = {
            'DEUTDEFF': 'DEUTDEFF',
            'NEDSZAJJXXX': 'NEDSZAJJXXX',
            'DABADKKK': 'DABADKKK',
            'UNCRIT2B912': 'UNCRIT2B912',
            'DSBACNBXSHA': 'DSBACNBXSHA'
        }

        invalid = {
            'NEDSZAJJXX': ['BIC codes have either 8 or 11 characters.'],
            'CIBCJJH2': ['JJ is not a valid country code.'],
            'D3UTDEFF': ['D3UT is not a valid institution code.']
        }

        self.assertFieldOutput(BICFormField, valid=valid, invalid=invalid)

        bic_model_field = BICField()

        # Test valid inputs for model field.
        for input, output in valid.items():
            self.assertEqual(bic_model_field.clean(input, None), output)

        self.assertIsNone(bic_model_field.to_python(None))

        # Invalid inputs for model field.
        for input, errors in invalid.items():
            with self.assertRaises(ValidationError) as context_manager:
                bic_model_field.clean(input, None)
            self.assertEqual(errors, context_manager.exception.messages)
    def test_bic_model_field(self):
        valid = {
            "DEUTDEFF": "DEUTDEFF",
            "NEDSZAJJXXX": "NEDSZAJJXXX",
            "DABADKKK": "DABADKKK",
            "UNCRIT2B912": "UNCRIT2B912",
            "DSBACNBXSHA": "DSBACNBXSHA",
        }

        invalid = {
            "NEDSZAJJXX": ["BIC codes have either 8 or 11 characters."],
            "CIBCJJH2": ["JJ is not a valid country code."],
            "D3UTDEFF": ["D3UT is not a valid institution code."],
        }

        self.assertFieldOutput(BICFormField, valid=valid, invalid=invalid)

        bic_model_field = BICField()

        # Test valid inputs for model field.
        for input, output in valid.items():
            self.assertEqual(bic_model_field.clean(input, None), output)

        self.assertIsNone(bic_model_field.to_python(None))

        # Invalid inputs for model field.
        for input, errors in invalid.items():
            with self.assertRaises(ValidationError) as context_manager:
                bic_model_field.clean(input, None)
            self.assertEqual(errors, context_manager.exception.messages)
Example #3
0
class SepaRoute(models.Model):
    """Represent an available route to a SEPA destination."""

    # FIXME: Could terminology here be aligned with BGP4?

    # FIXME: We must store here the source of where the data comes
    # from. Which directory and which version of the directory.

    class ReachabilityChoice(models.TextChoices):
        DIRECT = 'direct', 'Direct Participant'
        INDIRECT = 'indirect', 'Indirect Participant'
        UNKNOWN = 'unknown', 'Unknown'

    uuid = models.UUIDField(default=uuid.uuid4, editable=False)
    scheme = models.CharField(max_length=70,
                              blank=False,
                              choices=PaymentScheme.choices)
    external_key = models.CharField(max_length=16, blank=True)
    bic = BICField(blank=False)
    psp_name = models.CharField(max_length=140, blank=False)
    psp_city = models.CharField(max_length=35, blank=True)
    psp_country = CountryField(blank=True)
    reachable_via = models.CharField(max_length=4,
                                     blank=True,
                                     choices=SepaCsm.choices)
    reachability_type = models.CharField(max_length=16,
                                         blank=False,
                                         choices=ReachabilityChoice.choices)
    intermediary_bic = BICField(blank=True)
    preferred_route = models.BooleanField(default=False)
    valid_from = models.DateTimeField(null=True, blank=True)
    valid_to = models.DateTimeField(null=True, blank=True)

    class Meta:
        verbose_name = 'SEPA route'
Example #4
0
class Application(models.Model):

    applicant = models.ForeignKey('Applicant')
    offer_year = models.ForeignKey('base.OfferYear')
    creation_date = models.DateTimeField(auto_now=True)
    application_type = models.CharField(
        max_length=20, choices=application_type.APPLICATION_TYPE_CHOICES)
    coverage_access_degree = models.CharField(
        max_length=30,
        blank=True,
        null=True,
        choices=coverage_access_degree.COVERAGE_ACCESS_DEGREE_CHOICES)
    valuation_possible = models.NullBooleanField(default=None)
    started_similar_studies = models.NullBooleanField(default=None)
    credits_to_value = models.NullBooleanField(default=None)
    applied_to_sameprogram = models.NullBooleanField(default=None)
    resident = models.NullBooleanField(default=None)
    raffle_number = models.CharField(max_length=50, blank=True, null=True)
    study_grant = models.BooleanField(default=False)
    study_grant_number = models.CharField(max_length=50, blank=True, null=True)
    deduction_children = models.BooleanField(default=False)
    scholarship = models.BooleanField(default=False)
    scholarship_organization = models.TextField(blank=True, null=True)
    sport_membership = models.BooleanField(default=False)
    culture_membership = models.BooleanField(default=False)
    solidarity_membership = models.BooleanField(default=False)
    bank_account_iban = IBANField(include_countries=IBAN_SEPA_COUNTRIES,
                                  blank=True,
                                  null=True)
    bank_account_bic = BICField(blank=True, null=True)
    bank_account_name = models.CharField(max_length=255, blank=True, null=True)

    def __str__(self):
        return u"%s %s" % (self.applicant, self.offer_year)
Example #5
0
class MemberSepa(Auditable, models.Model):

    member = AutoOneToOneField(
        to='members.Member',
        related_name='profile_sepa',
        on_delete=models.PROTECT,
    )

    iban = IBANField(null=True, blank=True, verbose_name="IBAN")
    bic = BICField(null=True, blank=True, verbose_name="BIC")

    institute = models.CharField(
        max_length=255,
        null=True, blank=True,
        verbose_name="IBAN Institute")

    issue_date = models.DateField(
        null=True, blank=True,
        verbose_name="IBAN Issue Date",
        help_text="The issue date of the direct debit mandate. (1970-01-01 means there is no issue date in the database )")

    fullname = models.CharField(
        null=True, blank=True,
        max_length=255, verbose_name="IBAN full name",
        help_text="Full name for IBAN account owner")

    address = models.CharField(
        null=True, blank=True,
        max_length=255, verbose_name="IBAN address",
        help_text="Address line (e.g. Street / House Number)")

    zip_code = models.CharField(
        null=True, blank=True,
        max_length=20, verbose_name="IBAN zip code",
        help_text="ZIP Code")

    city = models.CharField(
        null=True, blank=True,
        max_length=255, verbose_name="IBAN City",)

    country = models.CharField(
        null=True, blank=True,
        max_length=255, default="Deutschland",
        verbose_name="IBAN Country",)

    mandate_reference = models.CharField(
        null=True, blank=True,
        max_length=255,
        verbose_name="IBAN Mandate Reference",)

    mandate_reason = models.CharField(
        null=True, blank=True,
        max_length=255,
        verbose_name="IBAN Mandate Reason",)

    form_title = _('SEPA information')

    @property
    def is_usable(self):
        return bool(self.iban and self.bic and self.mandate_reference)
Example #6
0
class DirectDebitMandate(models.Model):
    customer = models.ForeignKey('customer.Customer',
                                 on_delete=models.CASCADE,
                                 verbose_name=_('customer'),
                                 related_name='direct_debit_mandate_set')
    reference = models.CharField(_('mandate reference'),
                                 max_length=35,
                                 unique=True,
                                 blank=True,
                                 null=True)
    name = models.CharField(max_length=100)
    street = models.CharField(max_length=100)
    postal_code = models.CharField(max_length=20)
    city = models.CharField(max_length=100)
    country = CountryField(default='DE')
    iban = IBANField('IBAN', help_text='International Bank Account Number')
    bic = BICField('BIC', help_text='Bank Identifier Code')
    bank_name = models.CharField(max_length=50, blank=True)
    created = models.DateTimeField(_('created'), auto_now_add=True)
    updated = models.DateTimeField(_('updated'), auto_now=True)
    signed = models.DateField(blank=True, null=True)
    revoked = models.DateField(_('revoked'), blank=True, null=True)
    last_used = models.DateField(_('last_used'), blank=True, null=True)
    TYPE_CORE = 'CORE'
    TYPE_COR1 = 'COR1'
    TYPE_B2B = 'B2B'
    TYPE_CHOICES = (
        (TYPE_CORE, 'CORE'),
        (TYPE_COR1, 'COR1'),
        (TYPE_B2B, 'B2B'),
    )
    type = models.CharField(max_length=4, choices=TYPE_CHOICES)

    #document = models.ForeignKey('documents.Document',
    #        on_delete=models.CASCADE,
    #        verbose_name=_('signed document'),
    #        blank=True, null=True)

    class Meta:
        verbose_name = _('SEPA direct debit mandate')
        verbose_name_plural = _('SEPA direct debit mandates')

    def __str__(self):
        if self.reference:
            return self.reference
        else:
            return '<no reference>'

    @property
    def address_lines(self):
        return [
            self.name, self.street, self.postal_code + ' ' + self.city,
            self.get_country_display()
        ]

    @property
    def anonymized_iban(self):
        return anonymize_iban(self.iban)
Example #7
0
class BillingProfile(BillingInfo):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, models.CASCADE)
    bic = BICField(blank=True)
    iban = IBANField(blank=True)


    @receiver(post_save, sender=settings.AUTH_USER_MODEL)
    def create_profile(sender, instance, created=False, **kwargs):
        if created:
            BillingProfile.objects.create(user=instance)
Example #8
0
    def test_bic_model_field(self):
        valid = {
            'DEUTDEFF': 'DEUTDEFF',
            'NEDSZAJJXXX': 'NEDSZAJJXXX',
            'DABADKKK': 'DABADKKK',
            'UNCRIT2B912': 'UNCRIT2B912',
            'DSBACNBXSHA': 'DSBACNBXSHA'
        }

        invalid = {
            'NEDSZAJJXX': ['BIC codes have either 8 or 11 characters.'],
            'CIBCJJH2': ['JJ is not a valid country code.'],
            'D3UTDEFF': ['D3UT is not a valid institution code.']
        }

        self.assertFieldOutput(BICFormField, valid=valid, invalid=invalid)

        bic_model_field = BICField()

        # Test valid inputs for model field.
        for input, output in valid.items():
            self.assertEqual(bic_model_field.clean(input, None), output)

        self.assertIsNone(bic_model_field.to_python(None))

        # Invalid inputs for model field.
        for input, errors in invalid.items():
            with self.assertRaises(ValidationError) as context_manager:
                bic_model_field.clean(input, None)
            self.assertEqual(errors, context_manager.exception.messages)
Example #9
0
class Expense(models.Model):
  name = models.CharField(ugettext_lazy('Name'), max_length=255, validators=validators['name'])
  email = models.EmailField(ugettext_lazy('Email address'), validators=validators['email'])
  cc_email = models.EmailField(ugettext_lazy('CC email address'), blank=True, null=True, help_text=ugettext_lazy('Copy of the expense will be sent to the email.'), validators=validators['email'])
  phone = models.CharField(ugettext_lazy('Phone'), max_length=255, validators=validators['phoneno'])
  address = models.CharField(ugettext_lazy('Address'), max_length=255, validators=validators['address'])
  iban = IBANField(ugettext_lazy('Bank account no'))
  swift_bic = BICField(ugettext_lazy('BIC no'), blank=True, null=True)
  personno = models.CharField(ugettext_lazy('Person number'), max_length=11, validators=validators['hetu_or_businessid'], help_text=ugettext_lazy('If you apply for an expense reimbursement for a local group, enter the group’s business ID here. Kilometric allowances and daily subsistence allowances can not be applied for with a business ID.'))
  user = models.ForeignKey(User,on_delete=models.PROTECT)

  description = models.CharField(ugettext_lazy('Purpose'), max_length=255)
  memo = models.TextField(ugettext_lazy('Info'), help_text=ugettext_lazy('Eg. Names of the additional passengers, people in the meeting, cost centre or activity sector.'), blank=True, null=True)
  organisation = models.ForeignKey(Organisation, on_delete=models.PROTECT)
  status = models.IntegerField(ugettext_lazy('Status'), choices=APPLICATION_STATUSES, default=0)
  katre_status = models.IntegerField(ugettext_lazy('Katre status'), choices=KATRE_STATUSES, default=0)

  created_at = models.DateTimeField(ugettext_lazy('Sent'), auto_now_add=True)
  updated_at = models.DateTimeField(ugettext_lazy('Edited'), auto_now=True)

  def amount(self):
    sum = 0
    lines = ExpenseLine.objects.filter(expense=self)
    for line in lines:
      sum+= line.sum()
    return sum

  def __unicode__(self):
    return self.name + ': ' + self.description + ' (' + str(self.amount()) + ' e)'

  def finvoice(self):
    expense = self
    expenselines = ExpenseLine.objects.filter(expense=expense)

    return createFinvoice(expense, expenselines)

  def needsKatre(self):
    expense = self
    expenselines = ExpenseLine.objects.filter(expense=expense)

    for line in expenselines:
      if line.expensetype_type in ['FPD', 'PPD', 'FOPD', 'MA', 'T']:
        return True
    
    return False

  def katre(self):
    expense = self
    expenselines = ExpenseLine.objects.filter(expense=expense)

    return createKatreReport(expense, expenselines)
Example #10
0
class MangoPayBankAccount(models.Model):
    mangopay_user = models.ForeignKey(MangoPayUser,
                                      related_name="mangopay_bank_accounts")
    mangopay_id = models.PositiveIntegerField(null=True, blank=True)

    address = models.CharField(max_length=254)
    account_type = models.CharField(max_length=2,
                                    choices=BANK_ACCOUNT_TYPE_CHOICES,
                                    default=BANK_ACCOUNT_TYPE_CHOICES.iban)
    iban = IBANField(blank=True, null=True)

    bic = BICField(blank=True, null=True)
    country = CountryField(null=True, blank=True)
    account_number = models.CharField(max_length=15, null=True, blank=True)

    # BA_US type only fields
    aba = models.CharField(max_length=9, null=True, blank=True)
    deposit_account_type = models.CharField(max_length=8,
                                            choices=DEPOSIT_CHOICES,
                                            default=DEPOSIT_CHOICES.checking)

    def get_bank_account(self):
        bank_account = BankAccount(
            id=self.mangopay_id,
            owner_name=self.mangopay_user.user.get_full_name(),
            owner_address=Address(address_line_1=self.address),
            user=self.mangopay_user.get_user(),
            type=self.account_type)

        if self.account_type == BANK_ACCOUNT_TYPE_CHOICES.iban:
            bank_account.iban = self.iban
        elif self.account_type == BANK_ACCOUNT_TYPE_CHOICES.us:
            bank_account.aba = self.aba
            bank_account.deposit_account_type = self.deposit_account_type
            bank_account.account_number = self.account_number
        elif self.account_type == BANK_ACCOUNT_TYPE_CHOICES.other:
            bank_account.account_number = self.account_number
        else:
            raise NotImplementedError(
                "Bank Account Type ({0}) not implemented.".format(
                    self.account_type))

        return bank_account

    def create(self):
        bank_account = self.get_bank_account()
        bank_account.save()
        self.mangopay_id = bank_account.get_pk()
        self.save()
Example #11
0
class Person(models.Model):
  user = models.OneToOneField(User, on_delete=models.PROTECT)

  phone = models.CharField(ugettext_lazy('Phone'), max_length=255, blank=True, null=True, validators=validators['phoneno'])
  address = models.CharField(ugettext_lazy('Address'), max_length=255, blank=True, null=True, validators=validators['address'])
  iban = IBANField(ugettext_lazy('Bank account no'), blank=True, null=True)
  swift_bic = BICField(ugettext_lazy('BIC no'), blank=True, null=True)
  personno = models.CharField(ugettext_lazy('Person number'), max_length=11, blank=True, null=True, validators=validators['hetu_or_businessid'], help_text=ugettext_lazy('Person number is required for every expense application for annual announcements to the tax authority. If you don\'t want to save it here, you can enter it to each expense application separately.'))
  type = models.IntegerField(ugettext_lazy('Type'), choices=PERSONTYPE_CHOICES, default=1)
  language = models.CharField(ugettext_lazy('Site language'), max_length=6, blank=True, null=True, choices=settings.LANGUAGES)

  def name(self):
    return self.user.first_name + ' ' + self.user.last_name

  def __unicode__(self):
    return self.name()
Example #12
0
class BankAccount(RulesModel):
    class Meta:
        rules_permissions = {
            "add":
            pred.is_super_admin | pred.is_admin | pred.is_author
            | pred.is_editor | pred.is_member,
            "view":
            pred.is_super_admin | pred.is_admin | pred.is_user_of_bank_account,
            "change":
            pred.is_super_admin | pred.is_admin | pred.is_user_of_bank_account,
            "delete":
            pred.is_super_admin,
        }

    account_holder = models.CharField(max_length=100)
    iban = IBANField(include_countries=IBAN_SEPA_COUNTRIES)
    bic = BICField()

    def belongs_to_host(self, host):
        if hasattr(self, 'host') and self.host == host:
            return True
        elif hasattr(self, 'user') and self.user.host == host:
            return True
        else:
            return False

    def type(self):
        if hasattr(self, 'host'):
            return 'host'
        if hasattr(self, 'user'):
            return 'user'

    def __str__(self):
        return self.account_holder

    def get_hosts(self):
        if self.host:
            return self.host
        elif self.user:
            return self.user.hosts
        else:
            return None
Example #13
0
class Organization(models.Model):
    name = models.CharField(_('organization name'), max_length=150)
    street = models.CharField(_('street'),
                              max_length=150,
                              blank=True,
                              default='')
    city = models.CharField(_('city'), max_length=150, blank=True, default='')
    postal_code = PostalCodeField(_('postal code'), blank=True, default='')
    email = EmailField(_('email address'), blank=True, default='')
    phone = models.CharField(_('phone'), max_length=30, blank=True, default='')
    company_num = models.CharField(_('company number'),
                                   max_length=8,
                                   blank=True,
                                   default='')
    vat_number = models.CharField(_('VAT number'),
                                  max_length=12,
                                  blank=True,
                                  default='')
    iban = IBANField(_('IBAN'), blank=True, default='')
    bic = BICField(_('BIC (SWIFT)'), blank=True, default='')

    class Meta:
        app_label = 'leprikon'
        verbose_name = _('organization')
        verbose_name_plural = _('organizations')

    def __str__(self):
        return f'{self.name} ({self.bank_account})'

    @cached_property
    def address(self):
        return ', '.join(
            filter(bool, (self.street, self.city, self.postal_code)))

    address.short_description = _('address')

    @cached_property
    def bank_account(self):
        return self.iban and BankAccount(self.iban)

    bank_account.short_description = _('bank account')
Example #14
0
class Player(BasePlayer):

    iban = IBANField(verbose_name="IBAN")

    bic = BICField(verbose_name="BIC")

    bankname = models.CharField(verbose_name="Nachname:", max_length=50)

    bankvname = models.CharField(verbose_name="Vorname:", max_length=50)

    street = models.CharField(verbose_name="Straße / Hausnr.:", max_length=50)

    city = models.CharField(verbose_name="Stadt:", max_length=50)

    zipcode = models.IntegerField(verbose_name="PLZ:")

    user_agent = models.CharField()
    window_height = models.CharField()
    window_width = models.CharField()

    ibanmsgseen = models.PositiveIntegerField(default=0)
 def test_default_form(self):
     bic_model_field = BICField()
     self.assertEqual(type(bic_model_field.formfield()), type(BICFormField()))
Example #16
0
class Company(UUIDModel):
    name = models.CharField(_("Company name"), max_length=255)
    address = models.TextField(_("Address"), blank=True)
    zip_code = models.CharField(_("Postal code"), max_length=10, blank=True)
    city = models.CharField(_("City"), max_length=255, blank=True)
    country = CountryField(_("Country"), blank=True, null=True)

    phone = PhoneNumberField(_("Phone number"), blank=True)
    email = models.EmailField(_("Email"), blank=True)
    website = models.URLField(_("Web site"), blank=True)
    vat_id = models.CharField(_("VAT ID"), blank=True, max_length=20)

    name_for_bank = models.CharField(_("Bank account name"),
                                     max_length=255,
                                     blank=True)
    bank = models.TextField(_("Bank"), blank=True)
    bic = BICField(_("BIC"), blank=True)
    iban = IBANField(_("IBAN"), blank=True)

    logo = models.ImageField(_("Logo"), blank=True, null=True)
    contrast_color = ColorField(_("Contrast color"), default="#3B4451")

    signature_text = models.CharField(_("Signature as text"),
                                      max_length=100,
                                      blank=True)
    signature_image = models.ImageField(_("Signature as image"),
                                        null=True,
                                        blank=True)
    email_signature = models.TextField(_("Email signature"), blank=True)
    from_email = models.CharField(_("From email"),
                                  max_length=255,
                                  default='{} <{}>'.format(
                                      settings.ADMINS[0][0],
                                      settings.ADMINS[0][1]))
    bcc_email = models.EmailField(
        _("Copy of invoices"),
        help_text=_(
            "Email address that will receive every sent invoice in bcc"),
        blank=True)
    thanks = models.TextField(
        _("Thanks"),
        blank=True,
        help_text=
        _("Thanks at bottom of invoice. If set, this will be on every invoice, regardless of language"
          ))

    class Meta:
        ordering = ('name', 'created')
        verbose_name = _("Company")
        verbose_name_plural = _("Companies")

    def __str__(self):
        return self.name

    @property
    def all_invoices_api_url(self):
        return reverse('api:company-invoices', kwargs={'company_pk': self.pk})

    @property
    def bank_account_name(self):
        return self.name_for_bank or self.name

    @property
    def delete_url(self):
        return reverse('companies:delete', kwargs={'pk': self.pk})

    @property
    def earnings_api_url(self):
        return reverse('api:earnings-per-company',
                       kwargs={'company_pk': self.pk})

    @property
    def detail_url(self):
        return reverse('companies:detail', kwargs={'pk': self.pk})

    @property
    def edit_url(self):
        return reverse('companies:update', kwargs={'pk': self.pk})

    @property
    def has_signature(self):
        return bool(self.signature_text or self.signature_image)

    @property
    def open_invoices_api_url(self):
        return reverse('api:open-invoices-per-company',
                       kwargs={'company_pk': self.pk})

    @property
    def single_line_address(self):
        output = []
        if self.address:
            output.append(self.address)
        if self.zip_code:
            output.append(f'{self.zip_code} {self.city}')
        if self.country:
            output.append(self.country.name)
        return ', '.join(output)

    def open_invoices(self):
        from beyondtheadmin.invoices.models import Invoice
        return Invoice.visible.filter(company=self).select_related('client')

    def latest_open_invoices(self):
        return self.open_invoices().order_by('-due_date')[:5]

    def get_absolute_url(self):
        return self.detail_url
Example #17
0
class Member(models.Model):
    class Meta:
        ordering = ('-created', )

    member_id = models.IntegerField(unique=True, help_text="Membership ID")

    comment = models.TextField(blank=True, null=True)
    name = models.CharField(max_length=255, help_text="First/Given Name")

    surname = models.CharField(max_length=255, help_text="Last/Family Name")

    nickname = models.CharField(max_length=255, blank=True, null=True)

    form_of_address = models.CharField(
        choices=(('F', 'Frau'), ('H', 'Herr')),
        max_length=10,
        default="H",
        help_text="How to formally address this person")

    is_underaged = models.BooleanField(default=False,
                                       help_text="Member is not 18+.")

    date_of_birth = models.DateField(
        blank=True,
        null=True,
    )

    address1 = models.CharField(
        max_length=255,
        help_text="Address line 1 (e.g. Street / House Number)")

    address2 = models.CharField(max_length=255,
                                blank=True,
                                null=True,
                                help_text="Address line 2 (optional)")

    zip_code = models.CharField(max_length=20, help_text="ZIP Code")

    city = models.CharField(max_length=255, )

    country = models.CharField(
        max_length=255,
        default="Deutschland",
    )

    email = models.EmailField(max_length=255, )

    phone_number = models.CharField(max_length=32, blank=True, null=True)

    join_date = models.DateField(
        help_text=
        "Member joined on this date. The date is forced to the begin of given month."
    )

    leave_date = models.DateField(
        null=True,
        blank=True,
        help_text=
        "Member left on this date. The date is forced to the end of given month"
    )

    mailing_list_initial_mitglieder = models.BooleanField(
        default=True,
        help_text="Member should be subscribed on the Mitglieder mailing list")

    mailing_list_initial_mitglieder_announce = models.BooleanField(
        default=True,
        help_text=
        "Member should be subscribed on the Mitglieder-announce mailing list")

    is_active = models.BooleanField(default=True, )

    is_cancellation_confirmed = models.BooleanField(default=False)

    payment_type = models.CharField(choices=(('SEPA', 'Lastschrift'),
                                             ('transfer', 'Überweisung')),
                                    default="SEPA",
                                    max_length=20)

    iban = IBANField(null=True, blank=True, verbose_name="IBAN")
    bic = BICField(null=True, blank=True, verbose_name="BIC")

    iban_institute = models.CharField(max_length=255,
                                      null=True,
                                      blank=True,
                                      verbose_name="IBAN Institute")

    iban_issue_date = models.DateField(
        null=True,
        blank=True,
        verbose_name="IBAN Issue Date",
        help_text=
        "The issue date of the direct debit mandate. (1970-01-01 means there is no issue date in the database )"
    )

    iban_fullname = models.CharField(
        null=True,
        blank=True,
        max_length=255,
        verbose_name="IBAN full name",
        help_text="Full name for IBAN account owner")

    iban_address = models.CharField(
        null=True,
        blank=True,
        max_length=255,
        verbose_name="IBAN address",
        help_text="Address line (e.g. Street / House Number)")

    iban_zip_code = models.CharField(null=True,
                                     blank=True,
                                     max_length=20,
                                     verbose_name="IBAN zip code",
                                     help_text="ZIP Code")

    iban_city = models.CharField(
        null=True,
        blank=True,
        max_length=255,
        verbose_name="IBAN City",
    )

    iban_country = models.CharField(
        null=True,
        blank=True,
        max_length=255,
        default="Deutschland",
        verbose_name="IBAN Country",
    )

    is_welcome_mail_sent = models.BooleanField(default=False)

    is_registration_to_mailinglists_sent = models.BooleanField(default=False)

    is_cancellation_mail_sent_to_cashmaster = models.BooleanField(
        default=False)

    is_revoke_memberspecials_mail_sent = models.BooleanField(default=False)

    objects = MemberManager()

    modified = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, )

    def __str__(self):
        memberships = ', '.join([
            "{ms.valid_from.year}-{ms.valid_from.month:02d} {ms.membership_fee_monthly}/{ms.membership_fee_interval}"
            .format(ms=membership) for membership in Membership.objects.filter(
                member=self).order_by('valid_from')
        ])
        if self.nickname:
            return "{}, {} ({}) [ID: {}] {{{}}}".format(
                self.surname, self.name, self.nickname, self.member_id,
                memberships)
        return "{}, {} [ID: {}] {{{}}}".format(self.surname, self.name,
                                               self.member_id, memberships)

    def save(self, *args, **kwargs):
        if not self.member_id:
            self.member_id = (Member.objects.aggregate(
                models.Max('member_id')).get('member_id__max') or 0) + 1
        if self.join_date and not self.join_date.day == 1:
            self.join_date = self.join_date.replace(day=1)
        if self.leave_date:
            from .utils import last_day_of_month
            self.leave_date = last_day_of_month(self.leave_date)
        if self.is_cancellation_confirmed:
            # if the membership is cancelled the member isn't active anymore
            self.is_active = False
        if not self.is_cancellation_mail_sent_to_cashmaster and not self.is_active and self.payment_type == 'SEPA':
            from .views import send_cancellation_mail_to_cashmaster
            ret = send_cancellation_mail_to_cashmaster(self)
            if ret:
                self.is_cancellation_mail_sent_to_cashmaster = True


#        if not self.is_registration_to_mailinglists_sent and self.is_active:
#            from .utils import add_to_mailman
#            add_to_mailman(self.email, self.mailing_list_initial_mitglieder)
#            self.is_registration_to_mailinglists_sent = True

        is_welcome_mail_sent = self.is_welcome_mail_sent
        self.is_welcome_mail_sent = True and self.is_active

        is_revoke_memberspecials_mail_sent = self.is_revoke_memberspecials_mail_sent
        self.is_revoke_memberspecials_mail_sent = not self.is_active

        ret = super().save(*args, **kwargs)

        if not self.is_active and not is_revoke_memberspecials_mail_sent:
            from .views import send_revoke_memberspecials_mail
            send_revoke_memberspecials_mail(self)

        if not is_welcome_mail_sent and self.is_active:
            from .views import send_welcome_email
            send_welcome_email(self)

        return ret

    def get_ssh_public_key(self):
        if hasattr(self, 'memberspecials'):
            return self.memberspecials.ssh_public_key
        return None

    def get_nickname(self):
        if self.nickname:
            return self.nickname
        return "{} {}.".format(self.name, self.surname[:2])

    def get_mandate_reference(self):
        return "SHACKEVBEITRAGID{:04d}".format(self.member_id)

    def get_mandate_reason(self):
        return "shack e.V. Mitgliedsbeitrag ID {:d}".format(self.member_id)

    def get_postal_address(self):
        postal_address = "{} {}\n{}\n{}\n{} {}".format(
            self.name or "", self.surname or "", self.address1 or "",
            self.address2 or "", self.zip_code or "", self.city or "")
        postal_address = "\n".join(
            [line for line in postal_address.splitlines() if line.strip()])
        return postal_address

    def get_payed_membership_fee(self, year):
        sum_fee = AccountTransaction.objects \
            .filter(member=self, due_date__year=year, transaction_type='membership fee') \
            .filter(Q(booking_type='deposit') | Q(booking_type='charge back')) \
            .aggregate(models.Sum('amount')).get('amount__sum') or 0
        return sum_fee

    def send_email(self, email_type="generic", **kwargs):
        from django.core.mail import EmailMessage
        email_parameter = dict(kwargs)
        email_parameter['to'] = [self.email]

        email = EmailMessage(**email_parameter)
        ret = email.send()
        Memberlog.objects.create(member=self,
                                 action="email_{}".format(email_type),
                                 data=email_parameter)
        return ret
Example #18
0
class Event(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(_("short name"), help_text=_("Short name for the URL, only use alphanumeric characters and dashes, e.g. 'arizona-muni-event-2021'"), unique=True)
    begin_date = models.DateTimeField(_("begin date"))
    end_date = models.DateTimeField(_("end date"))
    description = models.TextField(_("description"))
    logo = models.ImageField(_("logo"), upload_to="logos", blank=True, null=True)
    is_open = models.BooleanField(default=True, help_text=_("Registration is currently open"))

    contact_email = models.EmailField(_("e-mail contact"))
    contact_name = models.CharField(_("name"), max_length=100)
    host = models.CharField(help_text=_("name of the host"), max_length=100)

    paypal = models.EmailField(_("PayPal address"), help_text=_("Payments are sent to this address"), blank=True)
    account_holder = models.CharField(max_length=100, blank=True)
    bic = BICField(_("BIC"), blank=True)
    iban = IBANField(_("IBAN"), blank=True)

    address_is_required = models.BooleanField(
        _("address is required"), 
        help_text=_("Does the post address need to be entered upon registration?"), 
        default=False
    )
    
    phone_is_required = models.BooleanField(
        _("phone is required"), 
        help_text=_("Does an emergency phone number need to be provided upon registration?"), 
        default=False
    )

    sex_is_required  = models.BooleanField(
        _("sex is required"), 
        help_text=_("Does the sex need to be specified upon registration?"), 
        default=False
    )

    food_is_included = models.BooleanField(
        _("food is included"),
        help_text=_("Food is offered and included in the booking fee"), 
        default=True
    )
    
    vegetarian = models.BooleanField(
        _("vegetarian"), 
        help_text=_("Vegetarian meals can be selected"), 
        default=True
    )

    vegan = models.BooleanField(
        _("vegan"), 
        help_text=_("There's a vegan choice available"), 
        default=True
    )

    vegan_breakfast_only = models.BooleanField(
        _("Only vegan breakfast"), 
        help_text="Der Benutzer wird bei der Buchung darauf hingewiesen, dass nur das Frühstück vegan ist.", 
        default=False
    )

    admin = models.ForeignKey("auth.User", on_delete=models.CASCADE, help_text="Dieser Benutzer kann das Event verwalten")

    def get_absolute_url(self):
        return reverse("convention:seite", args=[self.slug])

    def __str__(self):
        return self.name

    @property
    def arrival(self):
        return self.days.filter(arrival=True)

    @property
    def departure(self):
        return self.days.filter(departure=True)

    @property
    def rates_available(self):
        return self.rates.filter(is_active=True)


    class Meta:
        verbose_name = _("event")
        verbose_name_plural = _("events")
        ordering = ("-begin_date", "-end_date")  
Example #19
0
class MemberSepa(Auditable, models.Model):

    member = AutoOneToOneField(
        to="members.Member", related_name="profile_sepa", on_delete=models.PROTECT
    )

    iban = IBANField(null=True, blank=True, verbose_name="IBAN")
    bic = BICField(null=True, blank=True, verbose_name="BIC")

    mandate_state = models.CharField(
        choices=[
            ("inactive", _("Inactive")),
            ("active", _("Active")),
            ("bounced", _("Bounced")),
            ("rescinded", _("Rescinded")),
        ],
        default="active",
        max_length=10,
        blank=False,
        null=False,
        verbose_name=_("Mandate state"),
    )

    institute = models.CharField(
        max_length=255, null=True, blank=True, verbose_name=_("IBAN Institute")
    )

    issue_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("IBAN Issue Date"),
        help_text=_(
            "The issue date of the direct debit mandate. (1970-01-01 means there is no issue date in the database )"
        ),
    )

    fullname = models.CharField(
        null=True,
        blank=True,
        max_length=255,
        verbose_name=_("IBAN full name"),
        help_text=_("Full name for IBAN account owner"),
    )

    address = models.CharField(
        null=True,
        blank=True,
        max_length=255,
        verbose_name=_("IBAN address"),
        help_text=_("Address line (e.g. Street / House Number)"),
    )

    zip_code = models.CharField(
        null=True,
        blank=True,
        max_length=20,
        verbose_name=_("IBAN zip code"),
        help_text=_("ZIP Code"),
    )

    city = models.CharField(
        null=True, blank=True, max_length=255, verbose_name=_("IBAN City")
    )

    country = models.CharField(
        null=True,
        blank=True,
        max_length=255,
        default="Deutschland",
        verbose_name=_("IBAN Country"),
    )

    mandate_reference = models.CharField(
        null=True, blank=True, max_length=255, verbose_name=_("IBAN Mandate Reference")
    )

    mandate_reason = models.CharField(
        null=True, blank=True, max_length=255, verbose_name=_("IBAN Mandate Reason")
    )

    form_title = _("SEPA information")

    @property
    def is_usable(self):
        return self.sepa_direct_debit_state == SepaDirectDebitState.OK

    @property
    def iban_parsed(self):
        with suppress(ValueError):
            if self.iban:
                return IBAN(self.iban)

        return None

    @property
    def bic_autocomplete(self):
        if self.bic:
            return self.bic

        iban_parsed = self.iban_parsed
        if not iban_parsed:
            return None

        with suppress(ValueError):
            return str(iban_parsed.bic)

        return None

    @property
    def bic_parsed(self):
        with suppress(ValueError):
            bic = self.bic_autocomplete
            if bic:
                return BIC(bic)

        return None

    @property
    def sepa_direct_debit_state(self):
        if not self.iban:
            return SepaDirectDebitState.NO_IBAN

        if not self.iban_parsed:
            return SepaDirectDebitState.INVALID_IBAN

        if self.mandate_state == "rescinded":
            return SepaDirectDebitState.RESCINDED

        if self.mandate_state == "bounced":
            return SepaDirectDebitState.BOUNCED

        if self.mandate_state == "inactive":
            return SepaDirectDebitState.INACTIVE

        if not self.bic_autocomplete:
            return SepaDirectDebitState.NO_BIC

        bic = self.bic_parsed
        if not bic:
            return SepaDirectDebitState.INVALID_BIC

        if bic.country_code == "DE" and not bic.exists:
            # PBNKDEFF and PBNKDEFFXXX should be the same
            b_ = BIC(str(bic) + "XXX")
            if not b_.exists:
                return SepaDirectDebitState.INVALID_BIC

        if not self.mandate_reference:
            return SepaDirectDebitState.NO_MANDATE_REFERENCE

        return SepaDirectDebitState.OK
Example #20
0
class DirectDebitBatch(models.Model):
    '''
    This model is used to process multiple SEPA DD transactions
    together. This is typically achieved by generating a SEPA XML
    file.
    '''
    uuid = models.UUIDField(_('UUID'), default=uuid.uuid4)
    creditor_id = models.CharField(_('creditor id'),
                                   max_length=20,
                                   default=get_default_creditor_id)
    creditor_name = models.CharField(_('creditor name'),
                                     max_length=70,
                                     default=get_default_creditor_name)
    creditor_country = models.CharField(_('creditor country'),
                                        max_length=2,
                                        default=get_default_creditor_country)
    creditor_iban = IBANField(_('creditor IBAN'),
                              default=get_default_creditor_iban)
    creditor_bic = BICField(_('creditor BIC'),
                            default=get_default_creditor_bic)
    due_date = models.DateField(
        _('due date'),
        help_text=
        _('Must be min. 5 TARGET dates in the future for the first transaction and 2 target days in the future for recurring transactions.'
          ))
    mandate_type = models.CharField(_('mandate type'),
                                    max_length=4,
                                    choices=DirectDebitMandate.TYPE_CHOICES)
    SEQUENCE_TYPE_FRST = "FRST"
    SEQUENCE_TYPE_RCUR = "RCUR"
    SEQUENCE_TYPE_CHOICES = (
        (SEQUENCE_TYPE_FRST, 'FRST'),
        (SEQUENCE_TYPE_RCUR, 'RCUR'),
    )
    sequence_type = models.CharField(_('sequence type'),
                                     max_length=4,
                                     choices=SEQUENCE_TYPE_CHOICES)
    created = models.DateTimeField(_('created'), auto_now_add=True)
    executed = models.DateTimeField(_('executed'), blank=True, null=True)

    @property
    def transactions(self):
        return list(self.directdebittransaction_set.all())

    def render_sepa_xml(self):
        '''
        Create SEPA XML document according to ISO20222.
        '''
        dd = sepaxml.DirectDebit(
            id=self.uuid.hex,
            creditor_id=self.creditor_id,
            creditor_name=self.creditor_name,
            creditor_country=self.creditor_country,
            creditor_iban=self.creditor_iban,
            creditor_bic=self.creditor_bic,
            due_date=self.due_date,
            mandate_type=self.mandate_type,
            sequence_type=self.sequence_type,
            transactions=[
                sepaxml.Transaction(debitor_name=txn.mandate.name,
                                    debitor_country=txn.mandate.country,
                                    debitor_iban=txn.mandate.iban,
                                    debitor_bic=txn.mandate.bic,
                                    reference=settings.SHARK['SEPA']
                                    ['TRANSACTION_REFERENCE_PREFIX'] +
                                    txn.reference,
                                    amount=txn.amount,
                                    mandate_id=txn.mandate.reference,
                                    mandate_date=txn.mandate.signed)
                for txn in self.directdebittransaction_set.all()
            ])
        return dd.render_xml()
Example #21
0
 def test_default_form(self):
     bic_model_field = BICField()
     self.assertEqual(type(bic_model_field.formfield()),
                      type(BICFormField()))
Example #22
0
class BankAccount(models.Model):
    """
    Describes a bank account
    """

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    created_at = models.DateTimeField(_("created at"), default=timezone.now)

    last_used = models.DateField(
        verbose_name=_("last used"),
        blank=True,
        null=True,
    )

    owner = models.ForeignKey(
        to="members.Member",
        verbose_name=_("owner"),
        related_name="bank_accounts",
        on_delete=models.SET_NULL,
        blank=False,
        null=True,
    )

    initials = models.CharField(
        verbose_name=_("initials"),
        max_length=20,
    )

    last_name = models.CharField(
        verbose_name=_("last name"),
        max_length=255,
    )

    iban = IBANField(
        verbose_name=_("IBAN"),
        include_countries=IBAN_SEPA_COUNTRIES,
    )

    bic = BICField(
        verbose_name=_("BIC"),
        blank=True,
        null=True,
        help_text=_("This field is optional for Dutch bank accounts."),
    )

    valid_from = models.DateField(
        verbose_name=_("valid from"),
        blank=True,
        null=True,
    )

    valid_until = models.DateField(
        verbose_name=_("valid until"),
        blank=True,
        null=True,
    )

    signature = models.TextField(
        verbose_name=_("signature"),
        blank=True,
        null=True,
    )

    mandate_no = models.CharField(
        verbose_name=_("mandate number"),
        max_length=255,
        blank=True,
        null=True,
        unique=True,
    )

    def clean(self):
        super().clean()
        errors = {}

        if self.bic is None and self.iban[0:2] != "NL":
            errors.update({
                "bic":
                _("This field is required for foreign bank accounts.")
            })

        if not self.owner:
            errors.update({"owner": _("This field is required.")})

        mandate_fields = [
            ("valid_from", self.valid_from),
            ("signature", self.signature),
            ("mandate_no", self.mandate_no),
        ]

        if any(not field[1] for field in mandate_fields) and any(
                field[1] for field in mandate_fields):
            for field in mandate_fields:
                if not field[1]:
                    errors.update({
                        field[0]:
                        _("This field is required "
                          "to complete the mandate.")
                    })

        if self.valid_from and self.valid_until and self.valid_from > self.valid_until:
            errors.update({
                "valid_until":
                _("This date cannot be before the from date.")
            })

        if self.valid_until and not self.valid_from:
            errors.update(
                {"valid_until": _("This field cannot have a value.")})

        if errors:
            raise ValidationError(errors)

    @property
    def name(self):
        return f"{self.initials} {self.last_name}"

    @property
    def valid(self):
        if self.valid_from is not None and self.valid_until is not None:
            return self.valid_from <= timezone.now().date() < self.valid_until
        return self.valid_from is not None and self.valid_from <= timezone.now(
        ).date()

    def __str__(self):
        return f"{self.iban} - {self.name}"

    class Meta:
        ordering = ("created_at", )
Example #23
0
class MangoPayBankAccount(models.Model):
    mangopay_user = models.ForeignKey(MangoPayUser,
                                      related_name="mangopay_bank_accounts")
    mangopay_id = models.PositiveIntegerField(null=True, blank=True)

    address = models.CharField(max_length=254)
    account_type = models.CharField(
        max_length=2, choices=MANGOPAY_BANKACCOUNT_TYPE,
        default=BA_BIC_IBAN)  # Defaults to BIC/IBAN type

    iban = IBANField(blank=True, null=True)

    bic = BICField(blank=True, null=True)
    country = CountryField(null=True, blank=True)
    account_number = models.CharField(max_length=15, null=True, blank=True)

    # BA_US type only fields
    aba = models.CharField(max_length=9, null=True, blank=True)
    deposit_account_type = models.CharField(
        choices=BA_US_DEPOSIT_ACCOUNT_TYPES,
        max_length=8,
        null=True,
        blank=True,
    )

    def create(self):
        client = get_mangopay_api_client()
        mangopay_bank_account = BankAccount()
        mangopay_bank_account.UserId = self.mangopay_user.mangopay_id

        mangopay_bank_account.OwnerName = \
            self.mangopay_user.user.get_full_name()

        mangopay_bank_account.OwnerAddress = unicode(self.address)

        if self.account_type == BA_BIC_IBAN:
            # BIC / IBAN type requires setting IBAN and BIC codes only
            mangopay_bank_account.Details = BankAccountDetailsIBAN()
            mangopay_bank_account.Details.Type = "IBAN"
            mangopay_bank_account.Details.IBAN = self.iban

        elif self.account_type == BA_US:
            mangopay_bank_account.Details = BankAccountDetailsUS()
            mangopay_bank_account.Details.Type = "US"
            mangopay_bank_account.Details.ABA = self.aba
            mangopay_bank_account.Details.DepositAccountType = \
                self.deposit_account_type
            mangopay_bank_account.Details.AccountNumber = self.account_number

        elif self.account_type == BA_OTHER:
            # OTHER type requires setting Details object with Account number
            # country and BIC code.
            mangopay_bank_account.Details = BankAccountDetailsOTHER()
            mangopay_bank_account.Details.Type = "OTHER"
            mangopay_bank_account.Details.AccountNumber = self.account_number

        else:
            if self.account_type in BA_NOT_IMPLEMENTED:
                raise NotImplementedError(
                    "Bank Account Type ({0}) not implemeneted.".format(
                        self.account_type))
            else:
                raise Exception("Bank Account Type ({0}) is not valid.".format(
                    self.account_type))

        # Shared Details for IBAN and Other
        mangopay_bank_account.Details.BIC = self.bic

        if self.country:
            mangopay_bank_account.Details.Country = self.country.code
        else:
            if self.account_type != BA_BIC_IBAN:
                raise Exception("Country is required for Bank Accounts of "
                                "types other than BIC/IBAN")

        created_bank_account = client.users.CreateBankAccount(
            str(self.mangopay_user.mangopay_id), mangopay_bank_account)

        self.mangopay_id = created_bank_account.Id

        self.save()