-
Notifications
You must be signed in to change notification settings - Fork 41
T3284 - remove recurring invoicer object #279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 18.0
Are you sure you want to change the base?
Changes from all commits
97a3794
07752e9
8876eca
f8ea7a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import logging | ||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def migrate(cr, version): | ||
| """Drop recurring.invoicer: remove FK column from account_move and drop table.""" | ||
| cr.execute("ALTER TABLE account_move DROP COLUMN IF EXISTS recurring_invoicer_id") | ||
| _logger.info( | ||
| "post-migration: dropped recurring_invoicer_id column (%s rows affected)", | ||
| cr.rowcount, | ||
| ) | ||
|
|
||
| cr.execute("DROP TABLE IF EXISTS recurring_invoicer CASCADE") | ||
| _logger.info("post-migration: dropped recurring_invoicer table") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import logging | ||
|
|
||
| _logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def migrate(cr, version): | ||
| """Remove stale ir.actions.act_window for action_invoice_automatic_generation. | ||
|
|
||
| This action is recreated as ir.actions.server in recurring_contract_view.xml. | ||
| Odoo refuses to update a record if the model type changes, so we delete it first. | ||
| """ | ||
| cr.execute(""" | ||
| DELETE FROM ir_act_window | ||
| WHERE id IN ( | ||
| SELECT res_id FROM ir_model_data | ||
| WHERE module = 'recurring_contract' | ||
| AND name = 'action_invoice_automatic_generation' | ||
| AND model = 'ir.actions.act_window' | ||
| ) | ||
| """) | ||
| cr.execute(""" | ||
| DELETE FROM ir_model_data | ||
| WHERE module = 'recurring_contract' | ||
| AND name = 'action_invoice_automatic_generation' | ||
| AND model = 'ir.actions.act_window' | ||
| """) | ||
|
Comment on lines
+12
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
ArtifactsRepro: focused migration harness that seeds old and new cron XML IDs and runs pre-migration.py
|
||
| _logger.info( | ||
| "pre-migration: removed stale act_window action_invoice_automatic_generation" | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -242,15 +242,19 @@ def open_invoices(self): | |
|
|
||
| def button_generate_invoices(self): | ||
| """Immediately generate invoices for the contract group.""" | ||
| invoicer = ( | ||
| self.with_context(queue_job__no_delay=True) | ||
| .with_company(self.company_id) | ||
| .generate_invoices() | ||
| before_invoice_ids = set( | ||
| self.mapped("active_contract_ids.invoice_line_ids.move_id").ids | ||
| ) | ||
|
Comment on lines
243
to
+247
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The def button_generate_invoices(self):
"""Immediately generate invoices for the contract group."""
self.ensure_one()
before_invoice_ids = set(
self.mapped("active_contract_ids.invoice_line_ids.move_id").ids
) |
||
| self.with_context(queue_job__no_delay=True).with_company( | ||
| self.company_id | ||
| ).generate_invoices() | ||
| after_invoice_ids = set( | ||
| self.mapped("active_contract_ids.invoice_line_ids.move_id").ids | ||
| ) | ||
| notification = { | ||
| "type": "ir.actions.client", | ||
| } | ||
| if invoicer.invoice_ids: | ||
| if after_invoice_ids - before_invoice_ids: | ||
| notification["tag"] = "reload" | ||
| else: | ||
| msg = _( | ||
|
|
@@ -272,29 +276,35 @@ def button_generate_invoices(self): | |
| ########################################################################## | ||
| # PRIVATE METHODS # | ||
| ########################################################################## | ||
| @api.model | ||
| def generate_from_cron(self): | ||
| """Entry point for the daily invoice generation cron.""" | ||
| groups = self.search( | ||
| [ | ||
| "|", | ||
| ("invoice_suspended_until", "=", False), | ||
| ("invoice_suspended_until", "<", fields.Date.today()), | ||
| ("has_active_contracts", "=", True), | ||
| ] | ||
| ) | ||
| groups.generate_invoices() | ||
|
|
||
| def generate_invoices(self): | ||
| invoicer = self.env["recurring.invoicer"].create({}) | ||
| for group in self: | ||
| group.with_delay_sh( | ||
| "_generate_invoices", | ||
| invoicer.id, | ||
| channel="root.accounting", | ||
| priority=100, | ||
| identity_key=self._name + ".generate_invoices." + str(group.id), | ||
| ) | ||
| return invoicer | ||
|
|
||
| def _generate_invoices(self, invoicer_id=False): | ||
| def _generate_invoices(self): | ||
| """Checks all contracts and generate invoices if needed. | ||
| Create an invoice per contract group per date. | ||
| """ | ||
| _logger.info( | ||
| f"Starting generation of invoices for contract groups : {self.ids}" | ||
| ) | ||
| if invoicer_id: | ||
| invoicer = self.env["recurring.invoicer"].browse(invoicer_id) | ||
| else: | ||
| invoicer = self.env["recurring.invoicer"].create({}) | ||
|
|
||
| # Set to track processed invoices to avoid duplication | ||
| processed_invoices = set() | ||
|
|
@@ -325,15 +335,14 @@ def _generate_invoices(self, invoicer_id=False): | |
| if invoice_key not in processed_invoices: | ||
| # Process invoice generation if not already processed | ||
| group.with_company(group.company_id)._process_invoice_generation( | ||
| invoicer, current_invoicing_date | ||
| current_invoicing_date | ||
| ) | ||
| # Add the invoice key to the set of processed invoices | ||
| processed_invoices.add(invoice_key) | ||
|
|
||
| # Refresh state to check whether invoices are missing in some contracts | ||
| self.mapped("active_contract_ids")._compute_missing_invoices() | ||
| _logger.info("Process successfully generated invoices") | ||
| return invoicer | ||
|
|
||
| def _calculate_start_date_and_offset(self): | ||
| """ | ||
|
|
@@ -393,7 +402,7 @@ def _should_skip_invoice_generation( | |
| ) | ||
| return has_all_invoices | ||
|
|
||
| def _process_invoice_generation(self, invoicer, invoicing_date): | ||
| def _process_invoice_generation(self, invoicing_date): | ||
| self.ensure_one() | ||
| active_contracts = self.active_contract_ids | ||
| open_invoices = active_contracts.mapped("open_invoice_ids").filtered( | ||
|
|
@@ -466,7 +475,7 @@ def _process_invoice_generation(self, invoicer, invoicing_date): | |
| open_invoice.action_post() | ||
| else: | ||
| # Building invoices data | ||
| inv_data = self._build_invoice_gen_data(invoicing_date, invoicer) | ||
| inv_data = self._build_invoice_gen_data(invoicing_date) | ||
| # Creating the actual invoice | ||
| _logger.info(f"Generating invoice : {inv_data}") | ||
| invoice = self.env["account.move"].create(inv_data) | ||
|
|
@@ -480,7 +489,7 @@ def _process_invoice_generation(self, invoicer, invoicing_date): | |
| ) | ||
| invoice.unlink() | ||
|
|
||
| def _build_invoice_gen_data(self, invoicing_date, invoicer, gift_wizard=False): | ||
| def _build_invoice_gen_data(self, invoicing_date, gift_wizard=False): | ||
| """Setup a dict with data passed to invoice.create. | ||
| If any custom data is wanted in invoice from contract group, just | ||
| inherit this method. | ||
|
|
@@ -523,7 +532,6 @@ def _build_invoice_gen_data(self, invoicing_date, invoicer, gift_wizard=False): | |
| "journal_id": journal.id, | ||
| "currency_id": self.currency_id.id, | ||
| "invoice_date": invoicing_date, # Accountant date | ||
| "recurring_invoicer_id": invoicer.id, | ||
| "pricelist_id": self.pricelist_id.id, | ||
| "payment_mode_id": self.payment_mode_id.id, | ||
| "company_id": self.company_id.id, | ||
|
|
||
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Odoo,
ir.actions.act_windowinherits fromir.actions.actionsvia_inherits. The parent table isir_actionsand the child table isir_act_window. Deleting directly fromir_act_windowwill leave a stale orphaned row inir_actionsbecause the foreign key cascade only works from parent to child. To clean up both tables properly, you should delete fromir_actionsinstead.