Billing Entity Management #66

Open
rixx wants to merge 20 commits from 54-billing-entity-management into main
3 changed files with 67 additions and 18 deletions
Showing only changes of commit fe6580c3d3 - Show all commits

View file

@ -1,7 +1,7 @@
import rules
import urlman
from django.conf import settings
from django.db import models
from django.db import models, transaction
from django.utils.functional import cached_property
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
@ -9,6 +9,7 @@ from django_scopes import ScopedManager, scopes_disabled
from servala.core import rules as perms
from servala.core.models.mixins import ServalaModelMixin
from servala.core.odoo import CLIENT
class Organization(ServalaModelMixin, models.Model):
@ -125,9 +126,63 @@ class BillingEntity(ServalaModelMixin, models.Model):
return self.name
@classmethod
def create_from_data(cls, odoo_data):
instance = BillingEntity.objects.create(name=odoo_data.get("name"))
# TODO implement odoo creation from data
@transaction.atomic
def create_from_data(cls, name, odoo_data):
"""
Creates a BillingEntity and corresponding Odoo records.
This method creates a `res.partner` record in Odoo with `company_type='company'`
for the main company, and another `res.partner` record with `company_type='person'`
and `type='invoice'` (linked via `parent_id` to the first record) for the
invoice address. The IDs of these Odoo records are stored in the BillingEntity.
Args:
odoo_data (dict): A dictionary containing the data for creating
the BillingEntity and Odoo records.
Expected keys in `odoo_data`:
- `invoice_street` (str): Street for the invoice address.
- `invoice_street2` (str): Second line of street address for the invoice address.
- `invoice_city` (str): City for the invoice address.
- `invoice_zip` (str): ZIP/Postal code for the invoice address.
- `invoice_country` (int): Odoo `res.country` ID for the invoice address country.
- `invoice_email` (str): Email address for the invoice contact.
- `invoice_phone` (str): Phone number for the invoice contact.
"""
instance = cls.objects.create(name=name)
company_payload = {
"name": odoo_data.get("company_name", name),
"company_type": "company",
}
if vat := odoo_data.get("invoice_vat"):
company_payload["vat"] = vat
company_id = CLIENT.execute("res.partner", "create", [company_payload])
instance.odoo_company_id = company_id
invoice_address_payload = {
"name": name,
"company_type": "person",
"type": "invoice",
"parent_id": company_id,
}
invoice_optional_fields = {
"street": odoo_data.get("invoice_street"),
"street2": odoo_data.get("invoice_street2"),
"city": odoo_data.get("invoice_city"),
"zip": odoo_data.get("invoice_zip"),
"country_id": odoo_data.get("invoice_country"),
"email": odoo_data.get("invoice_email"),
}
invoice_address_payload.update(
{k: v for k, v in invoice_optional_fields.items() if v is not None}
)
invoice_address_id = CLIENT.execute(
"res.partner", "create", [invoice_address_payload]
)
instance.odoo_invoice_id = invoice_address_id
instance.save(update_fields=["odoo_company_id", "odoo_invoice_id"])
return instance
@classmethod

View file

@ -39,9 +39,7 @@ class OrganizationCreateForm(OrganizationForm):
choices=get_odoo_countries(),
)
invoice_email = forms.EmailField(label=_("Billing Email"), required=False)
invoice_phone = forms.CharField(
label=_("Billing Phone"), required=False, max_length=30
)
invoice_phone = forms.CharField(label=_("Phone"), required=False, max_length=30)
invoice_vat = forms.CharField(label=_("VAT ID"), required=False, max_length=50)
class Meta(OrganizationForm.Meta):
@ -77,18 +75,13 @@ class OrganizationCreateForm(OrganizationForm):
if not self.is_bound and "billing_processing_choice" not in self.initial:
self.fields["billing_processing_choice"].initial = "existing"
else:
# No existing Odoo addresses. Force 'new' choice.
self.fields["billing_processing_choice"].choices = [
("new", _("Create a new billing address")),
]
self.fields["billing_processing_choice"].initial = "new"
self.fields["billing_processing_choice"].widget = forms.HiddenInput()
self.fields.pop("billing_processing_choice")
self.fields["existing_odoo_address_id"].widget = forms.HiddenInput()
def clean(self):
cleaned_data = super().clean()
choice = cleaned_data.get("billing_processing_choice")
if choice == "new":
if not choice or choice == "new":
required_fields = [
"invoice_street",
"invoice_city",

View file

@ -22,13 +22,14 @@ class OrganizationCreateView(AutoPermissionRequiredMixin, CreateView):
billing_choice = form.cleaned_data.get("billing_processing_choice")
billing_entity = None
if billing_choice == "new":
if not billing_choice or billing_choice == "new":
billing_entity = BillingEntity.create_from_data(
form.cleaned_data["name"],
{
key[3:]: value
key: value
for key, value in form.cleaned_data.items()
if key.startswith("ba_")
}
if key.startswith("invoice_")
},
)
elif odoo_id := form.cleaned_data.get("existing_odoo_address_id"):
billing_entity = BillingEntity.objects.filter(