Skip to content

Commit

Permalink
refactor(models.py): decouple customer information from invoice
Browse files Browse the repository at this point in the history
  • Loading branch information
sepehr-akbarzadeh committed Oct 18, 2024
1 parent 7076190 commit 5acc08c
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 169 deletions.
Binary file removed invoices/logos/sageteam-logo.png
Binary file not shown.
Binary file not shown.
22 changes: 15 additions & 7 deletions sage_invoice/admin/invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from import_export.admin import ImportExportModelAdmin

from sage_invoice.admin.actions import export_pdf
from sage_invoice.models import Column, Expense, Invoice, Item
from sage_invoice.models import Column, Expense, Invoice, Item, CustomerProfile
from sage_invoice.resource import InvoiceResource


Expand Down Expand Up @@ -31,18 +31,28 @@ class ExpenseInline(admin.TabularInline):
)


class CustomerProfileInline(admin.StackedInline):
model = CustomerProfile


@admin.register(Invoice)
class InvoiceAdmin(ImportExportModelAdmin, admin.ModelAdmin):
resource_class = InvoiceResource
admin_priority = 1
list_display = ("title", "invoice_date", "customer_name", "status")
search_fields = ("customer_name", "status", "customer_email")
list_display = ("title", "invoice_date", "status")
search_fields = ("status", "customer_email")
save_on_top = True
list_filter = ("status", "invoice_date", "category")
ordering = ("-invoice_date",)
autocomplete_fields = ("category",)
readonly_fields = ("slug",)
actions = [export_pdf]
inlines = [
CustomerProfileInline,
ItemInline,
ColumnInline,
ExpenseInline,
]

class Media:
js = ("assets/js/invoice_admin.js",)
Expand All @@ -58,8 +68,6 @@ def get_fieldsets(self, request, obj=None):
"invoice_date",
"tracking_code",
"due_date",
"customer_name",
"contacts",
"category",
"receipt",
),
Expand Down Expand Up @@ -99,18 +107,18 @@ def get_fieldsets(self, request, obj=None):

return fieldsets

inlines = [ItemInline, ColumnInline, ExpenseInline]

def get_inline_instances(self, request, obj=None):
inlines = []
if obj and obj.pk:
inlines = [
CustomerProfileInline(self.model, self.admin_site),
ItemInline(self.model, self.admin_site),
ColumnInline(self.model, self.admin_site),
ExpenseInline(self.model, self.admin_site),
]
else:
inlines = [
CustomerProfileInline(self.model, self.admin_site),
ItemInline(self.model, self.admin_site),
ExpenseInline(self.model, self.admin_site),
]
Expand Down
22 changes: 22 additions & 0 deletions sage_invoice/helpers/choice.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@


class InvoiceStatus(models.TextChoices):
"""
This class defines the possible statuses for an invoice in the system.
- **DRAFT**: The invoice is saved but has not yet been sent to the customer.
This is the initial state when an invoice is being created and hasn't been
finalized or issued.
- **OVERDUE**: The invoice was sent, but the payment due date has passed, and
payment has not been received. It indicates that the customer is late in making
the payment.
- **PAID**: The invoice has been fully paid by the customer. No further action is
required from either party.
- **UNPAID**: The invoice has been sent to the customer (via email or manual download).
It has not been paid yet, but it is now awaiting customer action. The invoice
is still pending and has not yet been paid. This status includes invoices that
are still within the payment period and those that might require follow-up
(before they become overdue).
"""
DRAFT = ("draft", "DRAFT")
OVERDUE = ("overdue", "OVERDUE")
PAID = ("paid", "PAID")
UNPAID = ("unpaid", "UNPAID")

Expand Down
127 changes: 97 additions & 30 deletions sage_invoice/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 5.1 on 2024-10-08 14:44
# Generated by Django 5.1.2 on 2024-10-18 00:01

import django.db.models.deletion
import django_jsonform.models.fields
Expand Down Expand Up @@ -48,12 +48,9 @@ class Migration(migrations.Migration):
),
(
"description",
models.CharField(
blank=True,
db_comment="Description of the Category",
help_text="Description of the Category.",
max_length=255,
null=True,
models.TextField(
db_comment="Stores a detailed description of the instance.",
help_text="Enter a detailed description of the item. This can include its purpose, characteristics, and any other relevant information.",
verbose_name="Description",
),
),
Expand Down Expand Up @@ -105,15 +102,6 @@ class Migration(migrations.Migration):
verbose_name="Invoice Date",
),
),
(
"customer_name",
models.CharField(
db_comment="Customer name created",
help_text="The name of the customer.",
max_length=255,
verbose_name="Customer Name",
),
),
(
"tracking_code",
models.CharField(
Expand All @@ -123,16 +111,15 @@ class Migration(migrations.Migration):
verbose_name="Tracking Code",
),
),
(
"contacts",
django_jsonform.models.fields.JSONField(
blank=True, null=True, verbose_name="Customer Contacts"
),
),
(
"status",
models.CharField(
choices=[("paid", "PAID"), ("unpaid", "UNPAID")],
choices=[
("draft", "DRAFT"),
("overdue", "OVERDUE"),
("paid", "PAID"),
("unpaid", "UNPAID"),
],
db_comment="Current status of the invoice (Paid, Unpaid)",
help_text="The current status of the invoice (Paid, Unpaid).",
max_length=50,
Expand Down Expand Up @@ -241,10 +228,13 @@ class Migration(migrations.Migration):
"template_choice",
models.CharField(
choices=[
("1", "Invoice1 Template"),
("2", "Invoice2 Template"),
("3", "Invoice3 Template"),
("4", "Invoice4 Template"),
("quotation_1", "quotation_1"),
("quotation_2", "quotation_2"),
("quotation_3", "quotation_3"),
("quotation_4", "quotation_4"),
("receipt1", "receipt1"),
("receipt2", "receipt2"),
("receipt3", "receipt3"),
],
db_comment="Template choice for the invoice",
help_text="The template you want for your invoice",
Expand All @@ -260,7 +250,7 @@ class Migration(migrations.Migration):
help_text="The category associated with this invoice.",
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="category",
related_name="invoices",
to="sage_invoice.category",
verbose_name="Category",
),
Expand Down Expand Up @@ -378,7 +368,7 @@ class Migration(migrations.Migration):
db_comment="Reference to the associated invoice",
help_text="The invoice associated with this total.",
on_delete=django.db.models.deletion.CASCADE,
related_name="total",
related_name="expense",
to="sage_invoice.invoice",
verbose_name="Invoice",
),
Expand All @@ -390,6 +380,82 @@ class Migration(migrations.Migration):
"db_table": "sage_expense",
},
),
migrations.CreateModel(
name="CustomerProfile",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"name",
models.CharField(
db_comment="Customer name created",
help_text="The name of the customer.",
max_length=255,
verbose_name="Customer Name",
),
),
(
"company_name",
models.CharField(
blank=True,
db_comment="Company name associated with the customer, if applicable.",
help_text="The company name of the customer (optional).",
max_length=255,
null=True,
verbose_name="Company Name",
),
),
(
"billing_address",
django_jsonform.models.fields.JSONField(
blank=True,
db_comment="Stores billing address details such as street, city, state, postal code, and country.",
help_text="The full billing address of the customer.",
null=True,
verbose_name="Billing Address",
),
),
(
"shipping_address",
django_jsonform.models.fields.JSONField(
blank=True,
db_comment="Stores shipping address details if different from the billing address.",
help_text="The shipping address of the customer (optional).",
null=True,
verbose_name="Shipping Address",
),
),
(
"contacts",
django_jsonform.models.fields.JSONField(
blank=True, null=True, verbose_name="Customer Contacts"
),
),
(
"invoice",
models.OneToOneField(
db_comment="Link to the customer profile associated with this invoice",
help_text="The customer profile linked to this invoice.",
on_delete=django.db.models.deletion.CASCADE,
related_name="customer",
to="sage_invoice.invoice",
verbose_name="Customer Profile",
),
),
],
options={
"verbose_name": "Customer Profile",
"verbose_name_plural": "Customer Profiles",
"db_table": "sage_invoice_customer",
},
),
migrations.CreateModel(
name="Item",
fields=[
Expand All @@ -414,9 +480,10 @@ class Migration(migrations.Migration):
(
"quantity",
models.PositiveIntegerField(
blank=True,
db_comment="The quantity of the invoice item",
default=1,
help_text="The quantity of the item.",
null=True,
verbose_name="Quantity",
),
),
Expand Down
32 changes: 0 additions & 32 deletions sage_invoice/migrations/0002_alter_invoice_template_choice.py

This file was deleted.

This file was deleted.

3 changes: 2 additions & 1 deletion sage_invoice/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .column import Column
from .expense import Expense
from .invoice import Invoice
from .customer import CustomerProfile
from .item import Item

__all__ = ["Invoice", "Column", "Item", "Expense", "Category"]
__all__ = ["Invoice", "Column", "Item", "Expense", "Category", "CustomerProfile"]
Loading

0 comments on commit 5acc08c

Please sign in to comment.