Date: 2025-11-07 Feature: Generate PDF after successful fiscalization Final Version: 16.0.2.6.22
User Request:
- Generate PDF after successful fiscalization
- Option name: "Generate PDF after fiscalization" (default: false)
- Should be user-configurable
- After "Process Now" activates fiscalization and receives fiscal number, print invoice to PDF
Source Document: input/PDF_AFTER_SUCCESS_FISCALIZATION.md
Actions:
- Analyzed current fiscalization workflow in
account_edi_format.py:_ba_edi_post_invoice() - Identified successful fiscalization returns
{"success": True, "attachment": attachment} - Found existing PDF generation mechanism:
account_move.py:_get_edi_pdf_from_server() - Added user option fields to:
res_users.py- Field definitionres_config_settings.py- Settings integrationres_config_settings_views.xml- UI checkbox
First Implementation Attempt:
# WRONG: Used EDI server PDF endpoint (only for OFS driver)
if user_for_config.l10n_ba_edi_generate_pdf_after_fiscalization:
pdf_data = invoice._get_edi_pdf_from_server() # ❌ Wrong approachIssue Identified: User wanted standard Odoo invoice PDF, not EDI server PDF
Correction:
# Attempted to use standard Odoo report
report = self.env.ref('account.account_invoices')
pdf_content, _ = report._render_qweb_pdf(invoice.ids) # ❌ Wrong signatureIssues Encountered:
-
Error:
'list' object has no attribute 'split'- Root cause:
_render_qweb_pdf()expectsreport_refas first parameter - Was passing
[invoice.id]as positional instead of keyword argument
- Root cause:
-
Multiple attempts to fix method signature:
report._render_qweb_pdf([invoice.id])❌report._render_qweb_pdf(res_ids=[invoice.id])❌report._render_qweb_pdf(report.id, res_ids=[invoice.id])✓ (but created duplicates)
Discovery: Invoice print action has built-in PDF attachment generation logic
Attempted Solutions:
- Check for existing PDFs first:
existing_pdf = self.env["ir.attachment"].search([
("res_model", "=", "account.move"),
("res_id", "=", invoice.id),
("mimetype", "=", "application/pdf"),
], limit=1)-
Try different approaches:
invoice.action_invoice_print()- Only returns action dict, doesn't create attachmentreport.report_action(invoice.ids)- Same issuereport._render_qweb_pdf()with various parameters - Created duplicates
-
Added detailed logging:
_logger.info(f"Report object: {report}, Report ID: {report.id}")
_logger.info(f"Rendering PDF for invoice ID: {invoice.id}")
_logger.info(f"PDF content length: {len(pdf_content)}")Consultation with GPT-5:
Question: How to generate invoice PDF in Odoo 16 without duplicates?
GPT-5 Response Summary:
_render_qweb_pdf()does NOT auto-create attachments- Auto-creation happens via
_render_qweb_pdf_prepare_streams() - Manual attachment creation required
- Use
datasfield with base64 encoding instead ofraw - Get filename from
report.print_report_nameexpression
Recommended Solution:
report = self.env.ref('account.account_invoices')
pdf_content, _ = report._render_qweb_pdf('account.account_invoices', res_ids=invoice.ids)
pdf_name = safe_eval(report.print_report_name, {'object': invoice, 'time': time})
attachment = self.env["ir.attachment"].create({
"name": pdf_name,
"type": "binary",
"datas": base64.b64encode(pdf_content),
"res_model": "account.move",
"res_id": invoice.id,
"mimetype": "application/pdf",
})Critical Log Analysis:
Found in logs:
2025-11-07 12:31:36,861 INFO The PDF documents 'INV_2025_00229.pdf' are now saved in the database
2025-11-07 12:31:36,862 INFO Invoice PDF created: INV_2025_00229.pdf, ID: 620
Revelation:
_render_qweb_pdf()DOES auto-create attachments (contrary to GPT-5's statement)- In Odoo 16, it calls
_render_qweb_pdf_prepare_streams()which creates attachments - Manual creation was causing the duplicate!
Final Working Solution:
# Check if user wants PDF generation after fiscalization
_logger.info(f"Checking PDF generation setting for user {user_for_config.name}: {user_for_config.l10n_ba_edi_generate_pdf_after_fiscalization}")
if user_for_config.l10n_ba_edi_generate_pdf_after_fiscalization:
try:
_logger.info(f"Auto-generating standard invoice PDF after successful fiscalization for {invoice.name}")
# Check if ANY PDF already exists for this invoice to avoid duplicates
existing_pdf = self.env["ir.attachment"].search([
("res_model", "=", "account.move"),
("res_id", "=", invoice.id),
("mimetype", "=", "application/pdf"),
], limit=1)
if existing_pdf:
_logger.info(f"Invoice PDF already exists (name: {existing_pdf.name}), skipping automatic generation")
else:
# Generate PDF using Odoo's standard report
# NOTE: _render_qweb_pdf DOES auto-create attachments via _render_qweb_pdf_prepare_streams
_logger.info(f"Generating invoice PDF for {invoice.name}")
report = self.env.ref('account.account_invoices')
# This will automatically create and save the PDF attachment
pdf_content, _ = report._render_qweb_pdf('account.account_invoices', res_ids=invoice.ids)
# The attachment was already created automatically - just verify it exists
created_pdf = self.env["ir.attachment"].search([
("res_model", "=", "account.move"),
("res_id", "=", invoice.id),
("mimetype", "=", "application/pdf"),
], limit=1, order="id desc")
if created_pdf:
_logger.info(f"Invoice PDF auto-created by Odoo: {created_pdf.name}, ID: {created_pdf.id}")
else:
_logger.warning(f"Expected auto-created PDF not found for {invoice.name}")
except Exception as e:
# Log error but don't fail the fiscalization - PDF is optional
_logger.error(f"Failed to generate PDF after fiscalization for {invoice.name}: {str(e)}", exc_info=True)User Feedback: "Settings is not accessible for standard user"
Solution: Added option to User Fiscal Configuration Wizard
Files Modified:
wizard/user_fiscal_config_wizard.py- Added field and methodsviews/user_fiscal_config_wizard_views.xml- Added UI checkbox
Wizard Integration:
# In wizard model
l10n_ba_edi_generate_pdf_after_fiscalization = fields.Boolean(
string="Generate PDF after fiscalization",
help="When checked, automatically generate and attach PDF after successful fiscalization"
)
# In default_get
'l10n_ba_edi_generate_pdf_after_fiscalization': current_user.l10n_ba_edi_generate_pdf_after_fiscalization,
# In action_save
'l10n_ba_edi_generate_pdf_after_fiscalization': self.l10n_ba_edi_generate_pdf_after_fiscalization,Setup for Testing:
Added PostgreSQL service configuration for odoo_demo_web database:
# ~/.pg_service.conf
[odoo-demo-web]
host=localhost
port=54320
user=odoo_dev
password=odoo_dev
dbname=odoo_demo_webUsage:
PGSERVICE=odoo-demo-web psql -c "SELECT id, login, l10n_ba_edi_generate_pdf_after_fiscalization FROM res_users"-
l10n_ba_edi/models/account_edi_format.py
- Added imports:
base64,time,safe_eval - Modified
_ba_edi_post_invoice()method - Added PDF generation logic after successful fiscalization
- Added duplicate prevention check
- Added imports:
-
l10n_ba_edi/models/res_users.py
- Added
l10n_ba_edi_generate_pdf_after_fiscalizationfield - Default:
False - Security:
groups="l10n_ba_edi.group_l10n_ba_edi_user"
- Added
-
l10n_ba_edi/models/res_config_settings.py
- Added transient field for settings
- Updated
get_values()method - Updated
set_values()method
-
l10n_ba_edi/views/res_config_settings_views.xml
- Added checkbox after "Request Timeout" field
- Label: "Generate PDF after fiscalization"
-
l10n_ba_edi/wizard/user_fiscal_config_wizard.py
- Added field to wizard model
- Updated
default_get()method - Updated
action_save()method
-
l10n_ba_edi/views/user_fiscal_config_wizard_views.xml
- Added field to wizard form view
- Positioned in "Podešavanja" group after timeout
-
l10n_ba_edi/manifest.py
- Version:
16.0.2.6.5→16.0.2.6.22
- Version:
-
pyproject.toml
- Version:
16.0.2.6.5→16.0.2.6.22
- Version:
- input/PDF_AFTER_SUCCESS_FISCALIZATION.md
- Original requirement document (committed)
-
Odoo Report Rendering:
_render_qweb_pdf(report_ref, res_ids=None, data=None)- Main rendering method- Internally calls
_render_qweb_pdf_prepare_streams()which DOES create attachments - Attachment creation happens automatically when report has proper configuration
-
Method Signature Pitfalls:
- Must pass
report_refas first parameter (can be XML ID or report ID) res_idsshould be passed as keyword argument- Passing wrong parameter types causes confusing errors
- Must pass
-
Attachment Creation:
- In Odoo 16,
_render_qweb_pdf()auto-creates attachments - Manual creation after rendering causes duplicates
- Check for existing attachments to prevent duplicates
- In Odoo 16,
-
User Context in EDI:
- EDI processing often runs as system user (
__system__) - Must extract actual user from invoice:
invoice.invoice_user_idorinvoice.create_uid - Use invoice user's settings, not system user's
- EDI processing often runs as system user (
-
Version Management:
- Use automated version script:
scripts/update_version.py --increment patch - Always sync
__manifest__.pyandpyproject.toml
- Use automated version script:
-
Logging Strategy:
- Add comprehensive logging for debugging
- Use different log levels:
info,warning,error - Include context: user name, invoice name, settings values
-
Error Handling:
- Wrap optional features in try/except
- Don't fail main process (fiscalization) if optional feature (PDF) fails
- Log errors with
exc_info=Truefor full stack trace
-
Testing Approach:
- Test in demo database first (
odoo_demo_web) - Check database directly with psql for verification
- Monitor logs in real-time during testing
- Test in demo database first (
| Version | Change | Issue |
|---|---|---|
| 16.0.2.6.6 | Initial implementation with EDI server PDF | Wrong approach - user wanted standard PDF |
| 16.0.2.6.7 | Switch to standard Odoo PDF | Signature error: 'list' has no 'split' |
| 16.0.2.6.8 | Fix method signature | Still errors with report_ref |
| 16.0.2.6.9 | Add duplicate check | Duplicate check didn't prevent doubles |
| 16.0.2.6.10 | Try different rendering approach | Still creating duplicates |
| 16.0.2.6.11 | Check for any existing PDF | Duplicates persist |
| 16.0.2.6.12 | Try action_invoice_print() | No PDF generated |
| 16.0.2.6.13 | Try report_action() | No PDF generated |
| 16.0.2.6.14 | Add wizard integration | PDF generation still broken |
| 16.0.2.6.15 | Manual attachment creation | Duplicates again |
| 16.0.2.6.16 | Add detailed logging | Helped diagnose issue |
| 16.0.2.6.17 | Consult GPT-5 | Recommended manual creation |
| 16.0.2.6.18 | Implement GPT-5 solution | Duplicates! |
| 16.0.2.6.19 | Analyze logs for auto-creation | Discovered truth |
| 16.0.2.6.20 | GPT-5 final recommendation | Still duplicates |
| 16.0.2.6.21 | Fix report_ref parameter | Duplicates |
| 16.0.2.6.22 | Remove manual creation | ✅ SUCCESS! |
# After successful fiscalization:
if user_for_config.l10n_ba_edi_generate_pdf_after_fiscalization:
# 1. Check if PDF already exists (skip if true)
existing_pdf = search_for_pdf_attachment()
if not existing_pdf:
# 2. Call _render_qweb_pdf (auto-creates attachment)
report._render_qweb_pdf('account.account_invoices', res_ids=invoice.ids)
# 3. Verify it was created (logging only)
verify_pdf_created()- ✅ Only ONE PDF created per invoice
- ✅ Uses standard Odoo invoice report
- ✅ Works for both FPrint and OFS drivers
- ✅ Accessible to standard users via wizard
- ✅ Optional feature (default: disabled)
- ✅ Error-safe (doesn't break fiscalization if PDF fails)
- Total versions: 17 iterations (16.0.2.6.6 → 16.0.2.6.22)
- Files modified: 9
- Lines added: 86
- Lines removed: 3
- Time spent: ~2 hours
- Main challenge: Understanding Odoo's automatic attachment creation in
_render_qweb_pdf()
- Option appears in Settings for admin users
- Option appears in User Fiscal Config Wizard for standard users
- PDF generated when option enabled and invoice fiscalized
- No PDF generated when option disabled
- No duplicate PDFs created
- Existing PDF detection works
- Fiscalization succeeds even if PDF generation fails
- Works with both FPrint and OFS drivers
- Database field properly stores user preference
- PDF has correct filename from report template
- Performance: Consider async PDF generation for large batches
- Customization: Allow users to select different report templates
- Notifications: Notify user when PDF generation fails
- Batch Processing: Handle multiple invoice fiscalizations efficiently
- PDF Preview: Option to preview PDF before saving
After 17 iterations and exploring multiple approaches, the solution was surprisingly simple: let Odoo's _render_qweb_pdf() do its job automatically. The main challenge was understanding that in Odoo 16, this method DOES create attachments automatically, contrary to some documentation and even GPT-5's initial guidance.
The key insight came from careful log analysis showing the automatic attachment creation happening before our manual creation attempt. Once we removed the manual creation and just let Odoo handle it, everything worked perfectly.
Status: ✅ Feature implemented, tested, committed, and pushed to production.
Prompt: Can you create markdown of all conversations of today's session so I can analyze it