Billing Entity Management via Odoo #54

Open
opened 2025-05-07 12:52:17 +00:00 by tobru · 0 comments
Owner

Stories

As a user, I want to connect my organization to a billing address

As the system, I want to sync billing entity data with Odoo so that this information stays consistent.

We need to sync billing entity data in the Portal with contact information in Odoo (called "VSHN Central"), where Odoo is the source of truth.

A classic two-way sync, where Odoo takes precedence.

Implementation Notes

The Odoo API

The Odoo API is accessible either via XMLRPC or JSONRPC. We can either work directly with one of these APIs, or reuse an existing library. Example of how to work with the Odoo API: https://servala.app.codey.ch/servala/website/src/branch/main/hub/services/odoo.py. This uses https://pypi.org/project/OdooRPC/ which is a bit outdated. It's probably better to either use https://pypi.org/project/odoo-client-lib/ or plain XMLRPC (Example: https://github.com/vshn/conferenceli/blob/main/contactform/odoo_client.py).

We will need to read and write more data from and to Odoo in the future, so it makes sense to have the Odoo connection implemented in a reusable way.

Make the Odoo connection configurable via environment variables:

Billing entity specific

A billing entity in Servala Portal represents two records in the Odoo model res.partner:

  • A record with the field company_type set to company
  • A record with the following field configuration:
    • company_type=person
    • type=invoice
    • parent_id=company_id

This means:

  • When creating a billing entity in Servala, it must create these two records in Odoo and make sure the portal keeps track of these two records. See also fd065b51ed/apiserver/billing/odoostorage/odoo/odoo16/odoo16.go (L311-L318) to get an idea how this is done in APPUiO.
  • The portal regularly imports (syncs) billing entities from Odoo into Servala portal to make them available. How to handle records which are deleted in Odoo?
  • Triggering of the sync should happen regularly (cron) and when certain user actions happen, like when a new organization gets created.
  • Not all information has to be synced, only the ones important for listing and syncing. Detail information should be directly retrieved from Odoo when accessing it.

User flow:

  • The user must choose a billing entity when creating an organization. Either an existing one, or a new one.
  • Changing the billing entity after creating is not to be supported yet, this is coming later
  • We call this "Billing Address" in the frontend

Access control:

  • A user must only see billing entities which match the following criteria:
    • The user is the creator of the record
    • The users' email address matches with a contact related to the company_type set to company. This means we have to query Odoo for the email address in the res.partner model ([["email","=","email@example.com"]]) and when a contact is returned check of the parent_id of this contact matches the company of this billing entity. (To be discussed how to effectively do that - including caching)
  • Alternative: We implement the same system as we started with in organizations and use roles. A user is then assigned a role in the billing entity. And we could sync the access to billing entities with contacts from Odoo to begin with. (We don't want existing VSHN customers to have to create a new billing address, that is bad user experience and duplicates data).

More notes:

## Stories _As a user, I want to connect my organization to a billing address_ _As the system, I want to sync billing entity data with Odoo so that this information stays consistent_. We need to sync billing entity data in the Portal with contact information in Odoo (called "VSHN Central"), where Odoo is the source of truth. A classic two-way sync, where Odoo takes precedence. ## Implementation Notes ### The Odoo API The Odoo API is accessible either via XMLRPC or JSONRPC. We can either work directly with one of these APIs, or reuse an existing library. Example of how to work with the Odoo API: https://servala.app.codey.ch/servala/website/src/branch/main/hub/services/odoo.py. This uses https://pypi.org/project/OdooRPC/ which is a bit outdated. It's probably better to either use https://pypi.org/project/odoo-client-lib/ or plain XMLRPC (Example: https://github.com/vshn/conferenceli/blob/main/contactform/odoo_client.py). We will need to read and write more data from and to Odoo in the future, so it makes sense to have the Odoo connection implemented in a reusable way. Make the Odoo connection configurable via environment variables: * ODOO_URL=https://preprod.central.vshn.ch/ * ODOO_DB=VSHNPreProd * ODOO_USERNAME=CHANGEME * ODOO_PASSWORD=CHANGEME ### Billing entity specific A billing entity in Servala Portal represents two records in the Odoo model `res.partner`: * A record with the field `company_type` set to `company` * A record with the following field configuration: * `company_type=person` * `type=invoice` * `parent_id=company_id` This means: * When creating a billing entity in Servala, it must create these two records in Odoo and make sure the portal keeps track of these two records. See also https://github.com/appuio/control-api/blob/fd065b51ed8e5ecd02b869c558ac35cb25f20425/apiserver/billing/odoostorage/odoo/odoo16/odoo16.go#L311-L318 to get an idea how this is done in APPUiO. * The portal regularly imports (syncs) billing entities from Odoo into Servala portal to make them available. How to handle records which are deleted in Odoo? * Triggering of the sync should happen regularly (cron) and when certain user actions happen, like when a new organization gets created. * Not all information has to be synced, only the ones important for listing and syncing. Detail information should be directly retrieved from Odoo when accessing it. User flow: * The user must choose a billing entity when creating an organization. Either an existing one, or a new one. * Changing the billing entity after creating is not to be supported yet, this is coming later * We call this "Billing Address" in the frontend Access control: * A user must only see billing entities which match the following criteria: * The user is the creator of the record * The users' email address matches with a contact related to the `company_type` set to `company`. This means we have to query Odoo for the email address in the `res.partner` model (`[["email","=","email@example.com"]]`) and when a contact is returned check of the `parent_id` of this contact matches the company of this billing entity. (To be discussed how to effectively do that - including caching) * Alternative: We implement the same system as we started with in organizations and use roles. A user is then assigned a role in the billing entity. And we could sync the access to billing entities with contacts from Odoo to begin with. (We don't want existing VSHN customers to have to create a new billing address, that is bad user experience and duplicates data). More notes: * For now, we only allow creating, listing and viewing a billing entity, updating and deleting is coming later * We more or less resemble what we already do in the APPUiO control API: https://kb.vshn.ch/appuio-cloud/references/architecture/control-api-billing-entity.html * This is how the creation screen looks like in APPUiO portal today: ![Screenshot_20250507_143244.png](/attachments/1e5e0dce-7c89-48dc-9c99-43a4132614b1)
tobru added this to the Servala Portal MVP milestone 2025-05-07 12:52:17 +00:00
tobru added the
enhancement
label 2025-05-07 12:52:17 +00:00
tobru added this to the Servala Portal project 2025-05-07 12:52:17 +00:00
tobru changed title from BillingEntities via Odoo to Billing Entity Management via Odoo 2025-05-07 12:54:44 +00:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: servala/servala-portal#54
No description provided.