Skip to content

Commit

Permalink
feat(models): link service/donation directly to customer
Browse files Browse the repository at this point in the history
  • Loading branch information
nijel committed Oct 11, 2024
1 parent 7dab2c1 commit 6aaf104
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 3 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ max-complexity = 16
[tool.ruff.lint.per-file-ignores]
"payments/backends.py" = ["T201"]
"scripts/*" = ["T201"]
"weblate_web/migrations/0031_fill_in_customer.py" = ["T201"]
4 changes: 2 additions & 2 deletions weblate_web/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class DonationAdmin(admin.ModelAdmin):
"reward",
"active",
]
autocomplete_fields = ("user",)
autocomplete_fields = ("user", "customer")


class ProjectAdmin(admin.TabularInline):
Expand Down Expand Up @@ -82,7 +82,7 @@ class ServiceAdmin(admin.ModelAdmin):
"note",
)
date_hierarchy = "created"
autocomplete_fields = ("users",)
autocomplete_fields = ("users", "customer")
inlines = (ProjectAdmin,)

def get_form(self, request, obj=None, **kwargs):
Expand Down
32 changes: 32 additions & 0 deletions weblate_web/migrations/0030_donation_customer_service_customer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 5.0.6 on 2024-10-11 11:58

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("payments", "0028_alter_customer_email"),
("weblate_web", "0029_package_category"),
]

operations = [
migrations.AddField(
model_name="donation",
name="customer",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="payments.customer",
),
),
migrations.AddField(
model_name="service",
name="customer",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="payments.customer",
),
),
]
88 changes: 88 additions & 0 deletions weblate_web/migrations/0031_fill_in_customer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Generated by Django 5.0.6 on 2024-10-11 11:59

from django.conf import settings
from django.db import migrations
from django_countries import countries
from fakturace.storage import InvoiceStorage


def get_customer(customer_model, payments, invoice_storage, instance_name):
# First look at the invoice
for payment in payments:
if not payment.invoice:
continue
try:
invoice = invoice_storage.get(payment.invoice)
except KeyError:
print(f"<{instance_name}>: Could not load invoice {payment.invoice}!")
continue

# Try using database model
contact_id = invoice.invoice["contact"]
if contact_id.startswith("web-"):
contact_pk = int(contact_id[4:])
try:
return customer_model.objects.get(pk=contact_pk)
except customer_model.DoesNotExist:
print(
f"<{instance_name}>: Could not load contact {contact_pk} ({contact_id})"
)

# Create from the data
print(f"<{instance_name}>: Matching customer for {invoice.contact['name']}")
return customer_model.objects.get_or_create(
vat=invoice.contact.get("vat_reg", None),
name=invoice.contact["name"],
address=invoice.contact["address"],
city=invoice.contact["city"],
country=countries.by_name(invoice.contact["country"]),
user_id=-1,
origin="https://weblate.org/auto",
email=invoice.contact.get("email", ""),
)[0]

print(f"<{instance_name}>: Fallback to model: {payments[0].customer.name}")

# Fallback to model
return payments[0].customer


def update_customer(apps, schema_editor):
print()
Donation = apps.get_model("weblate_web", "Donation")
Service = apps.get_model("weblate_web", "Service")
Payment = apps.get_model("payments", "Payment")
Customer = apps.get_model("payments", "Customer")

invoice_storage = InvoiceStorage(settings.PAYMENT_FAKTURACE)

for donation in Donation.objects.filter(customer=None):
payment = Payment.objects.get(pk=donation.payment)
donation.customer = get_customer(
Customer, [payment], invoice_storage, f"Donation {donation.id}"
)
donation.save(update_fields=["customer"])

for service in Service.objects.filter(customer=None):
payments = Payment.objects.filter(
pk__in=service.subscription_set.values_list("payment", flat=True)
)
if not payments:
print(
f"<Service {service.pk}> missing payment {service.status}: {service.site_title} {service.site_url} {service.note}"
)
continue
service.customer = get_customer(
Customer, payments, invoice_storage, f"Service {service.id}"
)
service.save(update_fields=["customer"])


class Migration(migrations.Migration):
dependencies = [
("weblate_web", "0030_donation_customer_service_customer"),
]

operations = [
migrations.RunPython(update_customer, migrations.RunPython.noop, elidable=True),
]
5 changes: 4 additions & 1 deletion weblate_web/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ def create_backup_repository(service):

class Donation(models.Model):
user = models.ForeignKey(User, on_delete=models.deletion.CASCADE)
customer = models.ForeignKey(Customer, on_delete=models.deletion.CASCADE, null=True)
payment = Char32UUIDField(blank=True, null=True)
reward = models.IntegerField(choices=REWARDS, default=0)
link_text = models.CharField(
Expand Down Expand Up @@ -301,6 +302,7 @@ def process_donation(payment):
# Create new
donation = Donation.objects.create(
user=user,
customer=payment.customer,
payment=payment.pk,
reward=int(reward),
expires=expires,
Expand All @@ -319,7 +321,7 @@ def get_service(payment, user):
try:
return user.service_set.get()
except (Service.MultipleObjectsReturned, Service.DoesNotExist):
service = user.service_set.create()
service = user.service_set.create(customer=payment.customer)
service.was_created = True
return service

Expand Down Expand Up @@ -496,6 +498,7 @@ def get_repeat(self):
class Service(models.Model):
secret = models.CharField(max_length=100, default=generate_secret, db_index=True)
users = models.ManyToManyField(User)
customer = models.ForeignKey(Customer, on_delete=models.deletion.CASCADE, null=True)
status = models.CharField(
max_length=150,
choices=(
Expand Down

0 comments on commit 6aaf104

Please sign in to comment.