Commit f44b48a6 authored by Patrick Kimber's avatar Patrick Kimber

Merge branch '4924-customers-on-account' into 'master'

Magento - identify "account" customers, so we always post their invoices "on-account"

See merge request !17
parents da0160bb d90f3e8a
Pipeline #137079993 passed with stage
in 5 minutes and 2 seconds
# Generated by Django 3.0.5 on 2020-04-14 15:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("invoice", "0022_auto_20191029_1235"),
]
operations = [
migrations.AddField(
model_name="invoicecontact",
name="on_account",
field=models.BooleanField(
default=False,
help_text="Post the invoice on-account (do not batch)",
),
),
]
......@@ -180,20 +180,36 @@ class TimeAnalysis:
class InvoiceContactManager(models.Manager):
def _create_invoice_contact(
self, contact, country, hourly_rate, vat_number
self, contact, country, hourly_rate, vat_number, on_account
):
x = self.model(
contact=contact,
country=country,
hourly_rate=hourly_rate,
on_account=on_account,
vat_number=vat_number or "",
)
x.save()
return x
def init_invoice_contact(
self, contact, country=None, hourly_rate=None, vat_number=None
self,
contact,
country=None,
hourly_rate=None,
vat_number=None,
on_account=None,
):
"""Initialise the invoice details for the contact.
.. note:: The on account flag (``on_account``) can only be switched on.
It can't be switched off.
If we are posting to an accounts package e.g. Xero, then we
should always post on-account if we ever posted on-account.
"""
if on_account is None:
on_account = False
try:
x = self.model.objects.get(contact=contact)
update = False
......@@ -203,6 +219,9 @@ class InvoiceContactManager(models.Manager):
if hourly_rate:
x.hourly_rate = hourly_rate
update = True
if on_account is True and x.on_account is False:
x.on_account = on_account
update = True
if vat_number:
x.vat_number = vat_number
update = True
......@@ -210,7 +229,7 @@ class InvoiceContactManager(models.Manager):
x.save()
except self.model.DoesNotExist:
x = self._create_invoice_contact(
contact, country, hourly_rate, vat_number
contact, country, hourly_rate, vat_number, on_account
)
return x
......@@ -231,6 +250,9 @@ class InvoiceContact(TimeStampedModel):
on_delete=models.CASCADE,
related_name="+",
)
on_account = models.BooleanField(
default=False, help_text="Post the invoice on-account (do not batch)"
)
# Maximum of 12 characters?
# https://www.gov.uk/guidance/vat-eu-country-codes-vat-numbers-and-vat-in-other-languages
# 10/09/2019 The Xero 'TaxNumber' has a maximum length of 50 characters.
......
......@@ -26,3 +26,13 @@
{% endif %}
</td>
</tr>
<tr>
<td>On Account</td>
<td>
{% if invoice_contact.on_account %}
<i class="fa fa-check"></i>
{% else %}
<i class="fa fa-times"></i>
{% endif %}
</td>
</tr>
......@@ -40,16 +40,19 @@ def test_str(hourly_rate, vat_number, expect):
@pytest.mark.parametrize(
"country_code,hourly,vat_number,expect_country_code,expect_hourly,expect_vat_number",
(
"country_code,hourly,vat_number,on_account,"
"expect_country_code,expect_hourly,expect_vat_number,expect_on_account"
),
[
("GB", Decimal("1"), "ABC", "GB", Decimal("1"), "ABC"),
("GB", Decimal("1"), "XYZ", "GB", Decimal("1"), "XYZ"),
("GB", Decimal("2"), "ABC", "GB", Decimal("2"), "ABC"),
("GB", Decimal("2"), "XYZ", "GB", Decimal("2"), "XYZ"),
("GB", Decimal(), "", "GB", Decimal("1"), "ABC"),
(None, Decimal(), "", "FR", Decimal("1"), "ABC"),
("GB", Decimal(), "ABC", "GB", Decimal("1"), "ABC"),
(None, None, None, "FR", Decimal("1"), "ABC"),
("GB", Decimal("1"), "ABC", False, "GB", Decimal("1"), "ABC", False),
("GB", Decimal("1"), "XYZ", True, "GB", Decimal("1"), "XYZ", True),
("GB", Decimal("2"), "ABC", False, "GB", Decimal("2"), "ABC", False),
("GB", Decimal("2"), "XYZ", None, "GB", Decimal("2"), "XYZ", False),
("GB", Decimal(), "", True, "GB", Decimal("1"), "ABC", True),
(None, Decimal(), "", False, "FR", Decimal("1"), "ABC", False),
("GB", Decimal(), "ABC", True, "GB", Decimal("1"), "ABC", True),
(None, None, None, False, "FR", Decimal("1"), "ABC", False),
],
)
@pytest.mark.django_db
......@@ -57,9 +60,11 @@ def test_init_invoice_contact(
country_code,
hourly,
vat_number,
on_account,
expect_country_code,
expect_hourly,
expect_vat_number,
expect_on_account,
):
contact = ContactFactory()
country = None
......@@ -73,11 +78,16 @@ def test_init_invoice_contact(
vat_number="ABC",
)
x = InvoiceContact.objects.init_invoice_contact(
contact, country=country, hourly_rate=hourly, vat_number=vat_number
contact,
country=country,
hourly_rate=hourly,
vat_number=vat_number,
on_account=on_account,
)
assert contact == x.contact
assert Country.objects.get(iso2_code=expect_country_code) == x.country
assert expect_hourly == x.hourly_rate
assert expect_on_account == x.on_account
assert expect_vat_number == x.vat_number
......@@ -127,6 +137,36 @@ def test_init_invoice_contact_hourly_rate():
assert "" == x.vat_number
@pytest.mark.parametrize(
"init_on_account,on_account,expect",
[
(True, True, True),
(True, False, True),
(False, False, False),
(False, True, True),
],
)
@pytest.mark.django_db
def test_init_invoice_on_account(init_on_account, on_account, expect):
"""Initialise the on-account status for the contact.
.. note:: The on account flag (``on_account``) can only be switched on.
It can't be switched off.
If we are posting to an accounts package e.g. Xero, then we
should always post on-account if we ever posted on-account.
"""
contact = ContactFactory()
InvoiceContact.objects.init_invoice_contact(
contact, on_account=init_on_account,
)
x = InvoiceContact.objects.init_invoice_contact(
contact, on_account=on_account,
)
x.refresh_from_db()
assert expect == x.on_account
@pytest.mark.django_db
def test_init_invoice_contact_vat_number():
contact = ContactFactory()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment