• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sergei-maertens / regex-it / 75

pending completion
75

push

travis-ci

sergei-maertens
:arrow_up: Change Travis CI python version

44 of 70 branches covered (62.86%)

570 of 672 relevant lines covered (84.82%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.59
/src/regex/crm/models.py
1
from decimal import Decimal
1✔
2

3
from django.conf import settings
1✔
4
from django.core.exceptions import ValidationError
1✔
5
from django.db import models
1✔
6
from django.utils.translation import ugettext_lazy as _
1✔
7

8
from autoslug.fields import AutoSlugField
1✔
9
from django_countries.fields import CountryField
1✔
10
from djchoices import DjangoChoices, ChoiceItem
1✔
11

12

13
class Contact(models.Model):
1✔
14

15
    """
16
    Contact details for a single contact.
17
    """
18

19
    label = models.CharField(_('label'), max_length=50)
1✔
20
    name = models.CharField(_('name'), max_length=255)
1✔
21
    email = models.EmailField(_('email'))
1✔
22
    phone = models.CharField(_("phone number"), max_length=100, blank=True)
1✔
23
    address = models.CharField(_('address'), max_length=255, blank=True)
1✔
24
    postal_code = models.CharField(_('postal code'), max_length=10, blank=True)
1✔
25
    city = models.CharField(_('city'), max_length=255, blank=True)
1✔
26
    country = CountryField(default=settings.DEFAULT_COUNTRY, verbose_name=_('Country'))
1✔
27

28
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, blank=True, null=True)
1✔
29

30
    created = models.DateTimeField(_('created'), auto_now_add=True)
1✔
31
    modified = models.DateTimeField(_('modified'), auto_now=True)
1✔
32

33
    class Meta:
1✔
34
        verbose_name = _('contact')
1✔
35
        verbose_name_plural = _('contacts')
1✔
36

37
    def __str__(self):
1✔
38
        return self.name
×
39

40

41
class Client(models.Model):
1✔
42

43
    name = models.CharField(_('name'), max_length=255)
1✔
44
    slug = AutoSlugField(_('slug'), populate_from='name', unique=True)
1✔
45

46
    # global company contact details
47
    email = models.EmailField(_('email'))
1✔
48
    phone = models.CharField(_("phone number"), max_length=100, blank=True)
1✔
49
    address = models.CharField(_('address'), max_length=255)
1✔
50
    city = models.CharField(_('city'), max_length=255)
1✔
51
    country = CountryField(default=settings.DEFAULT_COUNTRY, verbose_name=_('Country'))
1✔
52
    language = models.CharField(_('language'), max_length=10, choices=settings.LANGUAGES, default='nl')
1✔
53

54
    # invoicing fields
55
    crn = models.CharField(_('registration number'), max_length=50, blank=True, help_text=_('KvK number'))
1✔
56
    vat = models.CharField(_('VAT number'), max_length=50, blank=True)
1✔
57

58
    contacts = models.ManyToManyField('Contact', blank=True)
1✔
59

60
    created = models.DateTimeField(_('created'), auto_now_add=True)
1✔
61
    modified = models.DateTimeField(_('modified'), auto_now=True)
1✔
62

63
    class Meta:
1✔
64
        verbose_name = _("client")
1✔
65
        verbose_name_plural = _("clients")
1✔
66

67
    def __str__(self):
1✔
68
        return self.name
×
69

70

71
class TaxRates(DjangoChoices):
1✔
72
    low = ChoiceItem(Decimal('0.06'), _('low'))
1✔
73
    high = ChoiceItem(Decimal('0.21'), _('high'))
1✔
74

75

76
class Project(models.Model):
1✔
77

78
    """
79
    Logical entity to group work entities under.
80

81
    Clients can have multiple projects going on.
82
    """
83

84
    client = models.ForeignKey(Client, on_delete=models.CASCADE)
1✔
85
    name = models.CharField(max_length=50)
1✔
86
    slug = AutoSlugField(populate_from='name')
1✔
87

88
    # base financial information
89
    base_rate = models.DecimalField(_('hourly base rate'), max_digits=8, decimal_places=2, null=True, blank=True)
1✔
90
    flat_fee = models.DecimalField(_('flat fee'), max_digits=10, decimal_places=2, null=True, blank=True)
1✔
91
    tax_rate = models.DecimalField(
1✔
92
        _('tax rate'), max_digits=4, decimal_places=2,
93
        choices=TaxRates.choices, default=TaxRates.high
94
    )
95

96
    class Meta:
1✔
97
        verbose_name = _('project')
1✔
98
        verbose_name_plural = _('projects')
1✔
99
        unique_together = (
1✔
100
            ('client', 'slug'),
101
        )
102

103
    def __str__(self):
1✔
104
        return '{client} - {name}'.format(name=self.name, client=self.client)
×
105

106
    def save(self, *args, **kwargs):
1✔
107
        self.full_clean()
1✔
108
        super().save(*args, **kwargs)
1✔
109

110
    def clean(self):
1✔
111
        """
112
        Validate that at least one rate is provided.
113
        """
114
        if not self.base_rate and not self.flat_fee:
1✔
115
            raise ValidationError(_('Provide a base hourly rate or a flat fee.'))
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2023 Coveralls, Inc