fix bugs
This commit is contained in:
parent
7e5a51fa2d
commit
e279e84501
124
README.md
124
README.md
@ -1,63 +1,63 @@
|
||||
# Web Direct Print Module for Odoo 18
|
||||
|
||||
This module enables direct printing of reports to local printers connected to the user's computer without downloading PDF files. It uses browser printing capabilities for a seamless printing experience.
|
||||
|
||||
## Features
|
||||
|
||||
- Direct print from web interface to local printer
|
||||
- Integration with existing report actions
|
||||
- Browser-based printing without downloads
|
||||
- Support for all standard Odoo reports
|
||||
- Direct print button in report dialogs
|
||||
|
||||
## Installation
|
||||
|
||||
1. Place the `web_direct_print` folder in your Odoo addons directory
|
||||
2. Update your Odoo configuration to include this directory in `addons_path`
|
||||
3. Restart your Odoo server
|
||||
4. Install the module from Apps menu (search for "Web Direct Print")
|
||||
|
||||
## Usage
|
||||
|
||||
Once installed, the module works automatically with existing reports:
|
||||
|
||||
1. When viewing a document (Invoice, Sale Order, Purchase Order, etc.), click the print button
|
||||
2. Instead of downloading a PDF, you'll see options to print directly
|
||||
3. Select "Direct Print" to send the report directly to your default printer
|
||||
4. The browser's print dialog will appear, allowing you to select your printer and print settings
|
||||
|
||||
## Technical Details
|
||||
|
||||
The module works by:
|
||||
|
||||
1. Intercepting report generation requests
|
||||
2. Converting reports to PDF in the backend
|
||||
3. Sending the PDF data to the browser as a blob
|
||||
4. Using JavaScript to create a temporary iframe with the PDF
|
||||
5. Calling the browser's print function on the iframe
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
This module relies on browser printing capabilities, which are available in all modern browsers (Chrome, Firefox, Safari, Edge). For best results, use the latest version of your preferred browser.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Browser Settings
|
||||
Make sure your browser allows popups from your Odoo instance, as some browsers may block the print dialog.
|
||||
|
||||
### Printer Access
|
||||
The module sends print jobs to the browser's default printer. Users can change printer settings in the browser's print dialog.
|
||||
|
||||
### Security Restrictions
|
||||
Some browsers may have security restrictions that prevent direct printing. If direct print doesn't work, the module will fall back to opening the report in a new tab where users can manually print using Ctrl+P.
|
||||
|
||||
## Limitations
|
||||
|
||||
- Requires user to have a local printer configured
|
||||
- Browser-dependent functionality
|
||||
- May not work in all network configurations
|
||||
- Users need to confirm print dialog (cannot print silently)
|
||||
|
||||
## Security
|
||||
|
||||
# Web Direct Print Module for Odoo 18
|
||||
|
||||
This module enables direct printing of reports to local printers connected to the user's computer without downloading PDF files. It uses browser printing capabilities for a seamless printing experience.
|
||||
|
||||
## Features
|
||||
|
||||
- Direct print from web interface to local printer
|
||||
- Integration with existing report actions
|
||||
- Browser-based printing without downloads
|
||||
- Support for all standard Odoo reports
|
||||
- Direct print button in report dialogs
|
||||
|
||||
## Installation
|
||||
|
||||
1. Place the `web_direct_print` folder in your Odoo addons directory
|
||||
2. Update your Odoo configuration to include this directory in `addons_path`
|
||||
3. Restart your Odoo server
|
||||
4. Install the module from Apps menu (search for "Web Direct Print")
|
||||
|
||||
## Usage
|
||||
|
||||
Once installed, the module works automatically with existing reports:
|
||||
|
||||
1. When viewing a document (Invoice, Sale Order, Purchase Order, etc.), click the print button
|
||||
2. Instead of downloading a PDF, you'll see options to print directly
|
||||
3. Select "Direct Print" to send the report directly to your default printer
|
||||
4. The browser's print dialog will appear, allowing you to select your printer and print settings
|
||||
|
||||
## Technical Details
|
||||
|
||||
The module works by:
|
||||
|
||||
1. Intercepting report generation requests
|
||||
2. Converting reports to PDF in the backend
|
||||
3. Sending the PDF data to the browser as a blob
|
||||
4. Using JavaScript to create a temporary iframe with the PDF
|
||||
5. Calling the browser's print function on the iframe
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
This module relies on browser printing capabilities, which are available in all modern browsers (Chrome, Firefox, Safari, Edge). For best results, use the latest version of your preferred browser.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Browser Settings
|
||||
Make sure your browser allows popups from your Odoo instance, as some browsers may block the print dialog.
|
||||
|
||||
### Printer Access
|
||||
The module sends print jobs to the browser's default printer. Users can change printer settings in the browser's print dialog.
|
||||
|
||||
### Security Restrictions
|
||||
Some browsers may have security restrictions that prevent direct printing. If direct print doesn't work, the module will fall back to opening the report in a new tab where users can manually print using Ctrl+P.
|
||||
|
||||
## Limitations
|
||||
|
||||
- Requires user to have a local printer configured
|
||||
- Browser-dependent functionality
|
||||
- May not work in all network configurations
|
||||
- Users need to confirm print dialog (cannot print silently)
|
||||
|
||||
## Security
|
||||
|
||||
The module follows Odoo's security model and only allows users to print documents they have access to.
|
||||
@ -1,2 +1,2 @@
|
||||
from . import models
|
||||
from . import models
|
||||
from . import controllers
|
||||
114
__manifest__.py
114
__manifest__.py
@ -1,58 +1,58 @@
|
||||
{
|
||||
'name': 'Web Direct Print',
|
||||
'version': '18.0.1.0.0',
|
||||
'category': 'Extra Tools',
|
||||
'summary': 'Enable direct printing from web browser to local printers',
|
||||
'description': """
|
||||
This module enables direct printing of reports to local printers
|
||||
connected to the user's computer without downloading PDF files.
|
||||
Uses browser printing capabilities for seamless printing experience.
|
||||
|
||||
Features:
|
||||
• Sales: Direct print quotations and sales orders
|
||||
• Purchase: Direct print purchase orders and vendor bills
|
||||
• Inventory: Direct print delivery slips, picking operations, internal transfers, receipts
|
||||
• Accounting: Direct print customer invoices, vendor bills, payment receipts, account statements
|
||||
• Stock Management: Direct print stock moves, inventory valuation, package contents
|
||||
|
||||
Supported Reports:
|
||||
- Sales Orders & Quotations
|
||||
- Purchase Orders & RFQs
|
||||
- Customer Invoices & Credit Notes
|
||||
- Vendor Bills & Credit Notes
|
||||
- Delivery Orders & Picking Lists
|
||||
- Internal Transfers & Receipts
|
||||
- Payment Receipts & Statements
|
||||
- Stock Moves & Inventory Reports
|
||||
- Package & Lot Tracking Labels
|
||||
""",
|
||||
'author': 'Suherdy Yacob',
|
||||
'depends': [
|
||||
'base',
|
||||
'web',
|
||||
'account',
|
||||
'sale',
|
||||
'purchase',
|
||||
'stock',
|
||||
],
|
||||
'data': [
|
||||
'data/ir_actions_server.xml',
|
||||
'views/direct_print_templates.xml',
|
||||
'views/sale_order_views.xml',
|
||||
'views/sale_order_form_views.xml',
|
||||
'views/purchase_order_views.xml',
|
||||
'views/purchase_order_form_views.xml',
|
||||
'views/stock_picking_views.xml',
|
||||
'views/stock_picking_form_views.xml',
|
||||
'views/account_move_views.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'web_direct_print/static/src/js/direct_print.js',
|
||||
'web_direct_print/static/src/xml/direct_print.xml',
|
||||
],
|
||||
},
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'license': 'LGPL-3',
|
||||
{
|
||||
'name': 'Web Direct Print',
|
||||
'version': '18.0.1.0.0',
|
||||
'category': 'Extra Tools',
|
||||
'summary': 'Enable direct printing from web browser to local printers',
|
||||
'description': """
|
||||
This module enables direct printing of reports to local printers
|
||||
connected to the user's computer without downloading PDF files.
|
||||
Uses browser printing capabilities for seamless printing experience.
|
||||
|
||||
Features:
|
||||
• Sales: Direct print quotations and sales orders
|
||||
• Purchase: Direct print purchase orders and vendor bills
|
||||
• Inventory: Direct print delivery slips, picking operations, internal transfers, receipts
|
||||
• Accounting: Direct print customer invoices, vendor bills, payment receipts, account statements
|
||||
• Stock Management: Direct print stock moves, inventory valuation, package contents
|
||||
|
||||
Supported Reports:
|
||||
- Sales Orders & Quotations
|
||||
- Purchase Orders & RFQs
|
||||
- Customer Invoices & Credit Notes
|
||||
- Vendor Bills & Credit Notes
|
||||
- Delivery Orders & Picking Lists
|
||||
- Internal Transfers & Receipts
|
||||
- Payment Receipts & Statements
|
||||
- Stock Moves & Inventory Reports
|
||||
- Package & Lot Tracking Labels
|
||||
""",
|
||||
'author': 'Suherdy Yacob',
|
||||
'depends': [
|
||||
'base',
|
||||
'web',
|
||||
'account',
|
||||
'sale',
|
||||
'purchase',
|
||||
'stock',
|
||||
],
|
||||
'data': [
|
||||
'data/ir_actions_server.xml',
|
||||
'views/direct_print_templates.xml',
|
||||
'views/sale_order_views.xml',
|
||||
'views/sale_order_form_views.xml',
|
||||
'views/purchase_order_views.xml',
|
||||
'views/purchase_order_form_views.xml',
|
||||
'views/stock_picking_views.xml',
|
||||
'views/stock_picking_form_views.xml',
|
||||
'views/account_move_views.xml',
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'web_direct_print/static/src/js/direct_print.js',
|
||||
'web_direct_print/static/src/xml/direct_print.xml',
|
||||
],
|
||||
},
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
BIN
__pycache__/__init__.cpython-310.pyc
Normal file
BIN
__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
controllers/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
controllers/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
controllers/__pycache__/main.cpython-310.pyc
Normal file
BIN
controllers/__pycache__/main.cpython-310.pyc
Normal file
Binary file not shown.
@ -1,90 +1,90 @@
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
import json
|
||||
import base64
|
||||
|
||||
|
||||
class DirectPrintController(http.Controller):
|
||||
|
||||
@http.route('/web/direct_print', type='json', auth='user')
|
||||
def direct_print(self, report_name, docids, data=None):
|
||||
"""
|
||||
Controller method to handle direct print requests
|
||||
:param report_name: Name of the report to print
|
||||
:param docids: IDs of documents to print
|
||||
:param data: Additional data for the report
|
||||
:return: JSON response with print data
|
||||
"""
|
||||
try:
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger.info(f"Controller received: report_name={report_name} (type: {type(report_name)}), docids={docids} (type: {type(docids)}), data={data}")
|
||||
|
||||
# Handle parameters that might come as different types
|
||||
if isinstance(report_name, list):
|
||||
report_name = report_name[0] if report_name else ''
|
||||
|
||||
if isinstance(docids, str):
|
||||
try:
|
||||
# Try to convert string to list of integers
|
||||
if ',' in docids:
|
||||
docids = [int(x.strip()) for x in docids.split(',') if x.strip()]
|
||||
else:
|
||||
docids = [int(docids)]
|
||||
except ValueError:
|
||||
docids = []
|
||||
elif not isinstance(docids, list):
|
||||
docids = [docids] if docids else []
|
||||
|
||||
_logger.info(f"Processed parameters: report_name={report_name}, docids={docids}")
|
||||
|
||||
# Call the direct print model method with proper context
|
||||
result = request.env['web.direct.print'].sudo().direct_print_action(
|
||||
report_name, docids, data, context=request.context
|
||||
)
|
||||
return result
|
||||
except Exception as e:
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger.error(f"Controller error: {str(e)}")
|
||||
_logger.exception("Full traceback:")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@http.route('/web/direct_print/get_reports', type='json', auth='user')
|
||||
def get_available_reports(self):
|
||||
"""
|
||||
Controller method to get available reports for direct printing
|
||||
:return: JSON response with available reports
|
||||
"""
|
||||
try:
|
||||
result = request.env['web.direct.print'].sudo().get_available_reports()
|
||||
return result
|
||||
except Exception as e:
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@http.route('/web/direct_print/test', type='http', auth='user', website=True)
|
||||
def test_direct_print(self, **kwargs):
|
||||
"""
|
||||
Test endpoint for direct printing functionality
|
||||
"""
|
||||
# This could be used for testing purposes
|
||||
html_content = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Direct Print Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Direct Print Test Page</h1>
|
||||
<p>This page demonstrates the direct print functionality.</p>
|
||||
<button onclick="window.print()">Print this page</button>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
import json
|
||||
import base64
|
||||
|
||||
|
||||
class DirectPrintController(http.Controller):
|
||||
|
||||
@http.route('/web/direct_print', type='json', auth='user')
|
||||
def direct_print(self, report_name, docids, data=None):
|
||||
"""
|
||||
Controller method to handle direct print requests
|
||||
:param report_name: Name of the report to print
|
||||
:param docids: IDs of documents to print
|
||||
:param data: Additional data for the report
|
||||
:return: JSON response with print data
|
||||
"""
|
||||
try:
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger.info(f"Controller received: report_name={report_name} (type: {type(report_name)}), docids={docids} (type: {type(docids)}), data={data}")
|
||||
|
||||
# Handle parameters that might come as different types
|
||||
if isinstance(report_name, list):
|
||||
report_name = report_name[0] if report_name else ''
|
||||
|
||||
if isinstance(docids, str):
|
||||
try:
|
||||
# Try to convert string to list of integers
|
||||
if ',' in docids:
|
||||
docids = [int(x.strip()) for x in docids.split(',') if x.strip()]
|
||||
else:
|
||||
docids = [int(docids)]
|
||||
except ValueError:
|
||||
docids = []
|
||||
elif not isinstance(docids, list):
|
||||
docids = [docids] if docids else []
|
||||
|
||||
_logger.info(f"Processed parameters: report_name={report_name}, docids={docids}")
|
||||
|
||||
# Call the direct print model method with proper context
|
||||
result = request.env['web.direct.print'].sudo().direct_print_action(
|
||||
report_name, docids, data, context=request.context
|
||||
)
|
||||
return result
|
||||
except Exception as e:
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger.error(f"Controller error: {str(e)}")
|
||||
_logger.exception("Full traceback:")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@http.route('/web/direct_print/get_reports', type='json', auth='user')
|
||||
def get_available_reports(self):
|
||||
"""
|
||||
Controller method to get available reports for direct printing
|
||||
:return: JSON response with available reports
|
||||
"""
|
||||
try:
|
||||
result = request.env['web.direct.print'].sudo().get_available_reports()
|
||||
return result
|
||||
except Exception as e:
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@http.route('/web/direct_print/test', type='http', auth='user', website=True)
|
||||
def test_direct_print(self, **kwargs):
|
||||
"""
|
||||
Test endpoint for direct printing functionality
|
||||
"""
|
||||
# This could be used for testing purposes
|
||||
html_content = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Direct Print Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Direct Print Test Page</h1>
|
||||
<p>This page demonstrates the direct print functionality.</p>
|
||||
<button onclick="window.print()">Print this page</button>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return html_content
|
||||
@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- Server Action to trigger direct print -->
|
||||
<record id="action_direct_print" model="ir.actions.server">
|
||||
<field name="name">Direct Print</field>
|
||||
<field name="model_id" ref="base.model_ir_actions_report"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if object:
|
||||
action = env['web.direct.print'].direct_print_action(object.report_name, env.context.get('active_ids', []), context=env.context)
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- Server Action to trigger direct print -->
|
||||
<record id="action_direct_print" model="ir.actions.server">
|
||||
<field name="name">Direct Print</field>
|
||||
<field name="model_id" ref="base.model_ir_actions_report"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if object:
|
||||
action = env['web.direct.print'].direct_print_action(object.report_name, env.context.get('active_ids', []), context=env.context)
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@ -1,4 +1,4 @@
|
||||
from . import direct_print
|
||||
from . import stock_picking
|
||||
from . import sale_order
|
||||
from . import direct_print
|
||||
from . import stock_picking
|
||||
from . import sale_order
|
||||
from . import purchase_order
|
||||
BIN
models/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
models/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/direct_print.cpython-310.pyc
Normal file
BIN
models/__pycache__/direct_print.cpython-310.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/purchase_order.cpython-310.pyc
Normal file
BIN
models/__pycache__/purchase_order.cpython-310.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/sale_order.cpython-310.pyc
Normal file
BIN
models/__pycache__/sale_order.cpython-310.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/stock_picking.cpython-310.pyc
Normal file
BIN
models/__pycache__/stock_picking.cpython-310.pyc
Normal file
Binary file not shown.
@ -1,212 +1,212 @@
|
||||
from odoo import models, fields, api
|
||||
import base64
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DirectPrint(models.Model):
|
||||
_name = 'web.direct.print'
|
||||
_description = 'Web Direct Print'
|
||||
|
||||
@api.model
|
||||
def get_report_data(self, report_name, docids, data=None):
|
||||
"""
|
||||
Generate report data for direct printing
|
||||
:param report_name: Name of the report
|
||||
:param docids: Document IDs to print
|
||||
:param data: Additional report data
|
||||
:return: Report content in base64
|
||||
"""
|
||||
try:
|
||||
_logger.info(f"get_report_data called with report_name={report_name} (type: {type(report_name)}), docids={docids} (type: {type(docids)})")
|
||||
|
||||
# Handle report_name parameter - it could be a string, list, or ID
|
||||
if isinstance(report_name, list):
|
||||
if report_name and isinstance(report_name[0], int):
|
||||
# It's a list of IDs, get the report by ID
|
||||
report = self.env['ir.actions.report'].browse(report_name[0])
|
||||
else:
|
||||
# It's a list with string names
|
||||
report_name_str = report_name[0] if report_name else ''
|
||||
report = self.env['ir.actions.report'].search([('report_name', '=', report_name_str)], limit=1)
|
||||
elif isinstance(report_name, int):
|
||||
# It's an ID
|
||||
report = self.env['ir.actions.report'].browse(report_name)
|
||||
elif isinstance(report_name, str):
|
||||
# It's a string name - try to find by report_name or use env.ref
|
||||
if '.' in report_name:
|
||||
# It looks like a module.xml_id format, try env.ref first
|
||||
try:
|
||||
ref_obj = self.env.ref(report_name)
|
||||
# Check if the referenced object is actually a report
|
||||
if hasattr(ref_obj, '_name') and ref_obj._name == 'ir.actions.report':
|
||||
report = ref_obj
|
||||
else:
|
||||
# It's not a report (probably a view), search by report_name instead
|
||||
report = self.env['ir.actions.report'].search([('report_name', '=', report_name)], limit=1)
|
||||
except ValueError:
|
||||
# If env.ref fails, try searching by report_name
|
||||
report = self.env['ir.actions.report'].search([('report_name', '=', report_name)], limit=1)
|
||||
else:
|
||||
# Search by report_name
|
||||
report = self.env['ir.actions.report'].search([('report_name', '=', report_name)], limit=1)
|
||||
else:
|
||||
report = None
|
||||
|
||||
# Generate the report content
|
||||
if report:
|
||||
# Generate the pdf content with proper context
|
||||
current_context = self.env.context.copy()
|
||||
|
||||
# Handle docids parameter - ensure it's a list of integers
|
||||
if isinstance(docids, str):
|
||||
# If it's a string, try to convert to int
|
||||
try:
|
||||
docids = [int(docids)]
|
||||
except ValueError:
|
||||
# If it contains commas, split and convert
|
||||
if ',' in docids:
|
||||
docids = [int(d.strip()) for d in docids.split(',') if d.strip()]
|
||||
else:
|
||||
docids = [int(docids)]
|
||||
elif isinstance(docids, int):
|
||||
docids = [docids]
|
||||
elif isinstance(docids, list):
|
||||
# Ensure all elements are integers
|
||||
processed_ids = []
|
||||
for d in docids:
|
||||
if isinstance(d, str):
|
||||
try:
|
||||
processed_ids.append(int(d))
|
||||
except ValueError:
|
||||
continue
|
||||
elif isinstance(d, int):
|
||||
processed_ids.append(d)
|
||||
docids = processed_ids
|
||||
else:
|
||||
docids = []
|
||||
|
||||
_logger.info(f"Processed docids: {docids}")
|
||||
|
||||
if not docids:
|
||||
return {
|
||||
'success': False,
|
||||
'error': 'No valid document IDs provided'
|
||||
}
|
||||
|
||||
# Use the standard Odoo report rendering approach
|
||||
# Ensure report_name is a string, not a list
|
||||
report_name_str = str(report.report_name) if report.report_name else report.name
|
||||
_logger.info(f"Using report_name_str: {report_name_str} (type: {type(report_name_str)})")
|
||||
|
||||
# Generate PDF using the standard method
|
||||
pdf_content, report_format = self.env['ir.actions.report'].with_context(**current_context)._render_qweb_pdf(report_name_str, docids, data or {})
|
||||
|
||||
# Encode the content in base64 for transmission
|
||||
encoded_content = base64.b64encode(pdf_content).decode('utf-8')
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'content': encoded_content,
|
||||
'report_name': report_name,
|
||||
'docids': docids,
|
||||
'content_type': 'application/pdf'
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'success': False,
|
||||
'error': f'Report "{report_name}" not found'
|
||||
}
|
||||
except Exception as e:
|
||||
_logger.error(f"Error generating report for direct print: {str(e)}")
|
||||
_logger.exception("Full traceback:")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@api.model
|
||||
def prepare_print_data(self, report_name, docids, data=None):
|
||||
"""
|
||||
Prepare data for direct printing
|
||||
:param report_name: Name of the report to print
|
||||
:param docids: IDs of documents to print
|
||||
:param data: Additional data for the report
|
||||
:return: Dictionary with report data
|
||||
"""
|
||||
try:
|
||||
result = self.get_report_data(report_name, docids, data)
|
||||
return result
|
||||
except Exception as e:
|
||||
_logger.error(f"Error preparing print data: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@api.model
|
||||
def get_available_reports(self):
|
||||
"""
|
||||
Get list of available reports for direct printing
|
||||
:return: List of available reports
|
||||
"""
|
||||
try:
|
||||
reports = self.env['ir.actions.report'].search([
|
||||
('active', '=', True),
|
||||
('report_type', 'in', ['qweb-pdf', 'qweb-html'])
|
||||
])
|
||||
|
||||
report_list = []
|
||||
for report in reports:
|
||||
report_list.append({
|
||||
'id': report.id,
|
||||
'name': report.name,
|
||||
'report_name': report.report_name,
|
||||
'model': report.model,
|
||||
})
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'reports': report_list
|
||||
}
|
||||
except Exception as e:
|
||||
_logger.error(f"Error getting available reports: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@api.model
|
||||
def direct_print_action(self, report_name, docids, data=None, context=None):
|
||||
"""
|
||||
Execute direct print action for a given report
|
||||
:param report_name: Name of the report to print
|
||||
:param docids: IDs of documents to print
|
||||
:param data: Additional data for the report
|
||||
:param context: Context data
|
||||
:return: Result of the print action
|
||||
"""
|
||||
try:
|
||||
# Update the environment context if provided
|
||||
if context:
|
||||
self = self.with_context(**context)
|
||||
|
||||
# Prepare the print data
|
||||
print_data = self.prepare_print_data(report_name, docids, data)
|
||||
|
||||
if print_data['success']:
|
||||
# In a real implementation, we might want to add additional
|
||||
# processing here, such as tracking print jobs or handling
|
||||
# special printer configurations
|
||||
|
||||
# Return the print data for client-side processing
|
||||
return print_data
|
||||
else:
|
||||
return print_data
|
||||
except Exception as e:
|
||||
_logger.error(f"Error in direct print action: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
from odoo import models, fields, api
|
||||
import base64
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DirectPrint(models.Model):
|
||||
_name = 'web.direct.print'
|
||||
_description = 'Web Direct Print'
|
||||
|
||||
@api.model
|
||||
def get_report_data(self, report_name, docids, data=None):
|
||||
"""
|
||||
Generate report data for direct printing
|
||||
:param report_name: Name of the report
|
||||
:param docids: Document IDs to print
|
||||
:param data: Additional report data
|
||||
:return: Report content in base64
|
||||
"""
|
||||
try:
|
||||
_logger.info(f"get_report_data called with report_name={report_name} (type: {type(report_name)}), docids={docids} (type: {type(docids)})")
|
||||
|
||||
# Handle report_name parameter - it could be a string, list, or ID
|
||||
if isinstance(report_name, list):
|
||||
if report_name and isinstance(report_name[0], int):
|
||||
# It's a list of IDs, get the report by ID
|
||||
report = self.env['ir.actions.report'].browse(report_name[0])
|
||||
else:
|
||||
# It's a list with string names
|
||||
report_name_str = report_name[0] if report_name else ''
|
||||
report = self.env['ir.actions.report'].search([('report_name', '=', report_name_str)], limit=1)
|
||||
elif isinstance(report_name, int):
|
||||
# It's an ID
|
||||
report = self.env['ir.actions.report'].browse(report_name)
|
||||
elif isinstance(report_name, str):
|
||||
# It's a string name - try to find by report_name or use env.ref
|
||||
if '.' in report_name:
|
||||
# It looks like a module.xml_id format, try env.ref first
|
||||
try:
|
||||
ref_obj = self.env.ref(report_name)
|
||||
# Check if the referenced object is actually a report
|
||||
if hasattr(ref_obj, '_name') and ref_obj._name == 'ir.actions.report':
|
||||
report = ref_obj
|
||||
else:
|
||||
# It's not a report (probably a view), search by report_name instead
|
||||
report = self.env['ir.actions.report'].search([('report_name', '=', report_name)], limit=1)
|
||||
except ValueError:
|
||||
# If env.ref fails, try searching by report_name
|
||||
report = self.env['ir.actions.report'].search([('report_name', '=', report_name)], limit=1)
|
||||
else:
|
||||
# Search by report_name
|
||||
report = self.env['ir.actions.report'].search([('report_name', '=', report_name)], limit=1)
|
||||
else:
|
||||
report = None
|
||||
|
||||
# Generate the report content
|
||||
if report:
|
||||
# Generate the pdf content with proper context
|
||||
current_context = self.env.context.copy()
|
||||
|
||||
# Handle docids parameter - ensure it's a list of integers
|
||||
if isinstance(docids, str):
|
||||
# If it's a string, try to convert to int
|
||||
try:
|
||||
docids = [int(docids)]
|
||||
except ValueError:
|
||||
# If it contains commas, split and convert
|
||||
if ',' in docids:
|
||||
docids = [int(d.strip()) for d in docids.split(',') if d.strip()]
|
||||
else:
|
||||
docids = [int(docids)]
|
||||
elif isinstance(docids, int):
|
||||
docids = [docids]
|
||||
elif isinstance(docids, list):
|
||||
# Ensure all elements are integers
|
||||
processed_ids = []
|
||||
for d in docids:
|
||||
if isinstance(d, str):
|
||||
try:
|
||||
processed_ids.append(int(d))
|
||||
except ValueError:
|
||||
continue
|
||||
elif isinstance(d, int):
|
||||
processed_ids.append(d)
|
||||
docids = processed_ids
|
||||
else:
|
||||
docids = []
|
||||
|
||||
_logger.info(f"Processed docids: {docids}")
|
||||
|
||||
if not docids:
|
||||
return {
|
||||
'success': False,
|
||||
'error': 'No valid document IDs provided'
|
||||
}
|
||||
|
||||
# Use the standard Odoo report rendering approach
|
||||
# Ensure report_name is a string, not a list
|
||||
report_name_str = str(report.report_name) if report.report_name else report.name
|
||||
_logger.info(f"Using report_name_str: {report_name_str} (type: {type(report_name_str)})")
|
||||
|
||||
# Generate PDF using the standard method
|
||||
pdf_content, report_format = self.env['ir.actions.report'].with_context(**current_context)._render_qweb_pdf(report_name_str, docids, data or {})
|
||||
|
||||
# Encode the content in base64 for transmission
|
||||
encoded_content = base64.b64encode(pdf_content).decode('utf-8')
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'content': encoded_content,
|
||||
'report_name': report_name,
|
||||
'docids': docids,
|
||||
'content_type': 'application/pdf'
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'success': False,
|
||||
'error': f'Report "{report_name}" not found'
|
||||
}
|
||||
except Exception as e:
|
||||
_logger.error(f"Error generating report for direct print: {str(e)}")
|
||||
_logger.exception("Full traceback:")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@api.model
|
||||
def prepare_print_data(self, report_name, docids, data=None):
|
||||
"""
|
||||
Prepare data for direct printing
|
||||
:param report_name: Name of the report to print
|
||||
:param docids: IDs of documents to print
|
||||
:param data: Additional data for the report
|
||||
:return: Dictionary with report data
|
||||
"""
|
||||
try:
|
||||
result = self.get_report_data(report_name, docids, data)
|
||||
return result
|
||||
except Exception as e:
|
||||
_logger.error(f"Error preparing print data: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@api.model
|
||||
def get_available_reports(self):
|
||||
"""
|
||||
Get list of available reports for direct printing
|
||||
:return: List of available reports
|
||||
"""
|
||||
try:
|
||||
reports = self.env['ir.actions.report'].search([
|
||||
('active', '=', True),
|
||||
('report_type', 'in', ['qweb-pdf', 'qweb-html'])
|
||||
])
|
||||
|
||||
report_list = []
|
||||
for report in reports:
|
||||
report_list.append({
|
||||
'id': report.id,
|
||||
'name': report.name,
|
||||
'report_name': report.report_name,
|
||||
'model': report.model,
|
||||
})
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'reports': report_list
|
||||
}
|
||||
except Exception as e:
|
||||
_logger.error(f"Error getting available reports: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
@api.model
|
||||
def direct_print_action(self, report_name, docids, data=None, context=None):
|
||||
"""
|
||||
Execute direct print action for a given report
|
||||
:param report_name: Name of the report to print
|
||||
:param docids: IDs of documents to print
|
||||
:param data: Additional data for the report
|
||||
:param context: Context data
|
||||
:return: Result of the print action
|
||||
"""
|
||||
try:
|
||||
# Update the environment context if provided
|
||||
if context:
|
||||
self = self.with_context(**context)
|
||||
|
||||
# Prepare the print data
|
||||
print_data = self.prepare_print_data(report_name, docids, data)
|
||||
|
||||
if print_data['success']:
|
||||
# In a real implementation, we might want to add additional
|
||||
# processing here, such as tracking print jobs or handling
|
||||
# special printer configurations
|
||||
|
||||
# Return the print data for client-side processing
|
||||
return print_data
|
||||
else:
|
||||
return print_data
|
||||
except Exception as e:
|
||||
_logger.error(f"Error in direct print action: {str(e)}")
|
||||
return {
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}
|
||||
@ -1,18 +1,18 @@
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class PurchaseOrder(models.Model):
|
||||
_inherit = 'purchase.order'
|
||||
|
||||
def action_direct_print_purchase_order(self):
|
||||
"""
|
||||
Direct print action for purchase orders and RFQs
|
||||
"""
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print Purchase Order',
|
||||
'report_name': 'purchase.report_purchaseorder',
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class PurchaseOrder(models.Model):
|
||||
_inherit = 'purchase.order'
|
||||
|
||||
def action_direct_print_purchase_order(self):
|
||||
"""
|
||||
Direct print action for purchase orders and RFQs
|
||||
"""
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print Purchase Order',
|
||||
'report_name': 'purchase.report_purchaseorder',
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
}
|
||||
@ -1,18 +1,18 @@
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
def action_direct_print_quotation(self):
|
||||
"""
|
||||
Direct print action for sale orders and quotations
|
||||
"""
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print Quotation/Order',
|
||||
'report_name': 'sale.report_saleorder',
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
def action_direct_print_quotation(self):
|
||||
"""
|
||||
Direct print action for sale orders and quotations
|
||||
"""
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print Quotation/Order',
|
||||
'report_name': 'sale.report_saleorder',
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
}
|
||||
@ -1,56 +1,56 @@
|
||||
from odoo import models, fields, api
|
||||
import json
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
def action_direct_print_receipt(self):
|
||||
"""
|
||||
Direct print action for stock picking receipts
|
||||
"""
|
||||
# Determine the appropriate report based on picking type
|
||||
if self.picking_type_id.code == 'incoming':
|
||||
report_name = 'stock.action_report_delivery'
|
||||
elif self.picking_type_id.code == 'outgoing':
|
||||
report_name = 'stock.action_report_delivery'
|
||||
elif self.picking_type_id.code == 'internal':
|
||||
report_name = 'stock.action_report_picking'
|
||||
else:
|
||||
report_name = 'stock.action_report_picking'
|
||||
|
||||
# Return client action for direct printing
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print',
|
||||
'report_name': report_name,
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
}
|
||||
|
||||
def action_direct_print_delivery(self):
|
||||
"""
|
||||
Direct print delivery slip
|
||||
"""
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print Delivery',
|
||||
'report_name': 'stock.action_report_delivery',
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
}
|
||||
|
||||
def action_direct_print_picking_operations(self):
|
||||
"""
|
||||
Direct print picking operations
|
||||
"""
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print Operations',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
from odoo import models, fields, api
|
||||
import json
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
def action_direct_print_receipt(self):
|
||||
"""
|
||||
Direct print action for stock picking receipts
|
||||
"""
|
||||
# Determine the appropriate report based on picking type
|
||||
if self.picking_type_id.code == 'incoming':
|
||||
report_name = 'stock.action_report_delivery'
|
||||
elif self.picking_type_id.code == 'outgoing':
|
||||
report_name = 'stock.action_report_delivery'
|
||||
elif self.picking_type_id.code == 'internal':
|
||||
report_name = 'stock.action_report_picking'
|
||||
else:
|
||||
report_name = 'stock.action_report_picking'
|
||||
|
||||
# Return client action for direct printing
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print',
|
||||
'report_name': report_name,
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
}
|
||||
|
||||
def action_direct_print_delivery(self):
|
||||
"""
|
||||
Direct print delivery slip
|
||||
"""
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print Delivery',
|
||||
'report_name': 'stock.action_report_delivery',
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
}
|
||||
|
||||
def action_direct_print_picking_operations(self):
|
||||
"""
|
||||
Direct print picking operations
|
||||
"""
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'name': 'Direct Print Operations',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': self.ids,
|
||||
'context': self.env.context,
|
||||
}
|
||||
@ -1,216 +1,216 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { Component } from "@odoo/owl";
|
||||
|
||||
const actionRegistry = registry.category("actions");
|
||||
|
||||
// Direct Print Action Handler
|
||||
class DirectPrintAction extends Component {
|
||||
static template = "web_direct_print.DirectPrintAction";
|
||||
|
||||
async setup() {
|
||||
// This action will handle direct print requests
|
||||
const action = this.props.action;
|
||||
console.log("DirectPrintAction received action:", action);
|
||||
|
||||
const report_name = action.report_name || action.context?.report_name || '';
|
||||
const docids = action.docids || action.context?.active_ids || [];
|
||||
const data = action.data || {};
|
||||
|
||||
console.log("Extracted params:", { report_name, docids, data });
|
||||
await this.directPrint(report_name, docids, data);
|
||||
}
|
||||
|
||||
async directPrint(reportName, docIds, data) {
|
||||
try {
|
||||
// Call the controller endpoint to get report data
|
||||
const result = await rpc("/web/direct_print", {
|
||||
report_name: reportName,
|
||||
docids: docIds,
|
||||
data: data || {}
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
this.printReport(result);
|
||||
} else {
|
||||
this.env.services.notification.add(
|
||||
_t("Error: ") + (result.error || _t("Unknown error occurred")),
|
||||
{ type: "danger" }
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Direct print error:", error);
|
||||
this.env.services.notification.add(
|
||||
_t("Error occurred while preparing print: ") + (error.message || error),
|
||||
{ type: "danger" }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
printReport(printData) {
|
||||
// Create a blob from the base64 content
|
||||
const binaryString = atob(printData.content);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
const blob = new Blob([bytes], { type: printData.content_type });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Create a new window with HTML that embeds the PDF and has print functionality
|
||||
const printWindow = window.open('', '_blank', 'width=800,height=600');
|
||||
if (!printWindow) {
|
||||
// If popup is blocked, show download option
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = printData.report_name + '.pdf';
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
return;
|
||||
}
|
||||
|
||||
// Write HTML content that will embed the PDF and automatically trigger print
|
||||
var htmlContent = '<!DOCTYPE html>' +
|
||||
'<html>' +
|
||||
'<head>' +
|
||||
'<title>Printing Document</title>' +
|
||||
'<style>' +
|
||||
'body, html {' +
|
||||
'margin: 0;' +
|
||||
'padding: 0;' +
|
||||
'height: 100%;' +
|
||||
'overflow: hidden;' +
|
||||
'}' +
|
||||
'#pdfContainer {' +
|
||||
'width: 100%;' +
|
||||
'height: 100vh;' +
|
||||
'border: none;' +
|
||||
'}' +
|
||||
'</style>' +
|
||||
'</head>' +
|
||||
'<body>' +
|
||||
'<div id="pdfContainer">' +
|
||||
'<embed id="pdfEmbed" src="' + url + '" type="application/pdf" width="100%" height="100%">' +
|
||||
'</div>' +
|
||||
'<script>' +
|
||||
'var pdfEmbed = document.getElementById("pdfEmbed");' +
|
||||
'var printWindow = window;' +
|
||||
'' +
|
||||
'// Wait for the PDF to load and then print' +
|
||||
'function attemptPrint() {' +
|
||||
'try {' +
|
||||
'// Method 1: Try to print directly' +
|
||||
'if (printWindow.print) {' +
|
||||
'printWindow.print();' +
|
||||
'}' +
|
||||
'} catch (e) {' +
|
||||
'console.log("Direct print failed:", e);' +
|
||||
'' +
|
||||
'// Method 2: Try to access the embedded PDF\'s print functionality' +
|
||||
'try {' +
|
||||
'if (pdfEmbed && pdfEmbed.print) {' +
|
||||
'pdfEmbed.print();' +
|
||||
'} else {' +
|
||||
'// Method 3: Try to print using document.execCommand (older method)' +
|
||||
'if (document.execCommand) {' +
|
||||
'document.execCommand("print", false, null);' +
|
||||
'}' +
|
||||
'}' +
|
||||
'} catch (e2) {' +
|
||||
'console.log("Alternative print methods failed:", e2);' +
|
||||
'// As a last resort, show user instructions' +
|
||||
'printWindow.document.body.innerHTML = \'<div style="padding: 20px;"><p>PDF loaded. Press Ctrl+P to print.</p><embed src="' + url + '" type="application/pdf" width="100%" height="90%"></div>\';' +
|
||||
'}' +
|
||||
'}' +
|
||||
'}' +
|
||||
'' +
|
||||
'// Try to print immediately and at intervals' +
|
||||
'setTimeout(attemptPrint, 1000); // Wait 1 second then try to print' +
|
||||
'setTimeout(attemptPrint, 3000); // Try again after 3 seconds' +
|
||||
'setTimeout(attemptPrint, 5000); // Try again after 5 seconds' +
|
||||
'' +
|
||||
'// Also try to print when the window is focused' +
|
||||
'printWindow.onfocus = function() {' +
|
||||
'setTimeout(attemptPrint, 500);' +
|
||||
'};' +
|
||||
'' +
|
||||
'// Listen for afterprint to close the window if possible' +
|
||||
'if (window.matchMedia) {' +
|
||||
'var mediaQueryList = window.matchMedia("print");' +
|
||||
'mediaQueryList.onchange = function(mql) {' +
|
||||
'if (!mql.matches) {' +
|
||||
'// Print dialog was closed, close the window after a delay' +
|
||||
'setTimeout(function() {' +
|
||||
'window.close();' +
|
||||
'}, 1000);' +
|
||||
'}' +
|
||||
'};' +
|
||||
'}' +
|
||||
'' +
|
||||
'</scr' + 'ipt>' + // Split to avoid issues with closing script tag
|
||||
'</body>' +
|
||||
'</html>';
|
||||
|
||||
printWindow.document.write(htmlContent);
|
||||
printWindow.document.close(); // Important: Close the document to finish loading
|
||||
|
||||
// Clean up the URL object after some time
|
||||
setTimeout(() => {
|
||||
URL.revokeObjectURL(url);
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// Register the action
|
||||
actionRegistry.add("direct_print", DirectPrintAction);
|
||||
|
||||
// Global function for backward compatibility
|
||||
window.directPrint = async function(reportName, docIds, data) {
|
||||
try {
|
||||
const result = await rpc("/web/direct_print", {
|
||||
report_name: reportName,
|
||||
docids: docIds,
|
||||
data: data || {}
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
// Create a blob from the base64 content
|
||||
const binaryString = atob(result.content);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
const blob = new Blob([bytes], { type: result.content_type });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Create a new window for printing
|
||||
const printWindow = window.open('', '_blank', 'width=800,height=600');
|
||||
if (printWindow) {
|
||||
printWindow.document.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Print</title></head>
|
||||
<body style="margin:0;">
|
||||
<embed src="${url}" type="application/pdf" width="100%" height="100%">
|
||||
<script>
|
||||
setTimeout(() => { window.print(); }, 1000);
|
||||
setTimeout(() => { window.close(); }, 5000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
}
|
||||
|
||||
// Clean up
|
||||
setTimeout(() => URL.revokeObjectURL(url), 10000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Direct print error:", error);
|
||||
}
|
||||
/** @odoo-module **/
|
||||
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { Component } from "@odoo/owl";
|
||||
|
||||
const actionRegistry = registry.category("actions");
|
||||
|
||||
// Direct Print Action Handler
|
||||
class DirectPrintAction extends Component {
|
||||
static template = "web_direct_print.DirectPrintAction";
|
||||
|
||||
async setup() {
|
||||
// This action will handle direct print requests
|
||||
const action = this.props.action;
|
||||
console.log("DirectPrintAction received action:", action);
|
||||
|
||||
const report_name = action.report_name || action.context?.report_name || '';
|
||||
const docids = action.docids || action.context?.active_ids || [];
|
||||
const data = action.data || {};
|
||||
|
||||
console.log("Extracted params:", { report_name, docids, data });
|
||||
await this.directPrint(report_name, docids, data);
|
||||
}
|
||||
|
||||
async directPrint(reportName, docIds, data) {
|
||||
try {
|
||||
// Call the controller endpoint to get report data
|
||||
const result = await rpc("/web/direct_print", {
|
||||
report_name: reportName,
|
||||
docids: docIds,
|
||||
data: data || {}
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
this.printReport(result);
|
||||
} else {
|
||||
this.env.services.notification.add(
|
||||
_t("Error: ") + (result.error || _t("Unknown error occurred")),
|
||||
{ type: "danger" }
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Direct print error:", error);
|
||||
this.env.services.notification.add(
|
||||
_t("Error occurred while preparing print: ") + (error.message || error),
|
||||
{ type: "danger" }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
printReport(printData) {
|
||||
// Create a blob from the base64 content
|
||||
const binaryString = atob(printData.content);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
const blob = new Blob([bytes], { type: printData.content_type });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Create a new window with HTML that embeds the PDF and has print functionality
|
||||
const printWindow = window.open('', '_blank', 'width=800,height=600');
|
||||
if (!printWindow) {
|
||||
// If popup is blocked, show download option
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = printData.report_name + '.pdf';
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
return;
|
||||
}
|
||||
|
||||
// Write HTML content that will embed the PDF and automatically trigger print
|
||||
var htmlContent = '<!DOCTYPE html>' +
|
||||
'<html>' +
|
||||
'<head>' +
|
||||
'<title>Printing Document</title>' +
|
||||
'<style>' +
|
||||
'body, html {' +
|
||||
'margin: 0;' +
|
||||
'padding: 0;' +
|
||||
'height: 100%;' +
|
||||
'overflow: hidden;' +
|
||||
'}' +
|
||||
'#pdfContainer {' +
|
||||
'width: 100%;' +
|
||||
'height: 100vh;' +
|
||||
'border: none;' +
|
||||
'}' +
|
||||
'</style>' +
|
||||
'</head>' +
|
||||
'<body>' +
|
||||
'<div id="pdfContainer">' +
|
||||
'<embed id="pdfEmbed" src="' + url + '" type="application/pdf" width="100%" height="100%">' +
|
||||
'</div>' +
|
||||
'<script>' +
|
||||
'var pdfEmbed = document.getElementById("pdfEmbed");' +
|
||||
'var printWindow = window;' +
|
||||
'' +
|
||||
'// Wait for the PDF to load and then print' +
|
||||
'function attemptPrint() {' +
|
||||
'try {' +
|
||||
'// Method 1: Try to print directly' +
|
||||
'if (printWindow.print) {' +
|
||||
'printWindow.print();' +
|
||||
'}' +
|
||||
'} catch (e) {' +
|
||||
'console.log("Direct print failed:", e);' +
|
||||
'' +
|
||||
'// Method 2: Try to access the embedded PDF\'s print functionality' +
|
||||
'try {' +
|
||||
'if (pdfEmbed && pdfEmbed.print) {' +
|
||||
'pdfEmbed.print();' +
|
||||
'} else {' +
|
||||
'// Method 3: Try to print using document.execCommand (older method)' +
|
||||
'if (document.execCommand) {' +
|
||||
'document.execCommand("print", false, null);' +
|
||||
'}' +
|
||||
'}' +
|
||||
'} catch (e2) {' +
|
||||
'console.log("Alternative print methods failed:", e2);' +
|
||||
'// As a last resort, show user instructions' +
|
||||
'printWindow.document.body.innerHTML = \'<div style="padding: 20px;"><p>PDF loaded. Press Ctrl+P to print.</p><embed src="' + url + '" type="application/pdf" width="100%" height="90%"></div>\';' +
|
||||
'}' +
|
||||
'}' +
|
||||
'}' +
|
||||
'' +
|
||||
'// Try to print immediately and at intervals' +
|
||||
'setTimeout(attemptPrint, 1000); // Wait 1 second then try to print' +
|
||||
'setTimeout(attemptPrint, 3000); // Try again after 3 seconds' +
|
||||
'setTimeout(attemptPrint, 5000); // Try again after 5 seconds' +
|
||||
'' +
|
||||
'// Also try to print when the window is focused' +
|
||||
'printWindow.onfocus = function() {' +
|
||||
'setTimeout(attemptPrint, 500);' +
|
||||
'};' +
|
||||
'' +
|
||||
'// Listen for afterprint to close the window if possible' +
|
||||
'if (window.matchMedia) {' +
|
||||
'var mediaQueryList = window.matchMedia("print");' +
|
||||
'mediaQueryList.onchange = function(mql) {' +
|
||||
'if (!mql.matches) {' +
|
||||
'// Print dialog was closed, close the window after a delay' +
|
||||
'setTimeout(function() {' +
|
||||
'window.close();' +
|
||||
'}, 1000);' +
|
||||
'}' +
|
||||
'};' +
|
||||
'}' +
|
||||
'' +
|
||||
'</scr' + 'ipt>' + // Split to avoid issues with closing script tag
|
||||
'</body>' +
|
||||
'</html>';
|
||||
|
||||
printWindow.document.write(htmlContent);
|
||||
printWindow.document.close(); // Important: Close the document to finish loading
|
||||
|
||||
// Clean up the URL object after some time
|
||||
setTimeout(() => {
|
||||
URL.revokeObjectURL(url);
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// Register the action
|
||||
actionRegistry.add("direct_print", DirectPrintAction);
|
||||
|
||||
// Global function for backward compatibility
|
||||
window.directPrint = async function(reportName, docIds, data) {
|
||||
try {
|
||||
const result = await rpc("/web/direct_print", {
|
||||
report_name: reportName,
|
||||
docids: docIds,
|
||||
data: data || {}
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
// Create a blob from the base64 content
|
||||
const binaryString = atob(result.content);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
const blob = new Blob([bytes], { type: result.content_type });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Create a new window for printing
|
||||
const printWindow = window.open('', '_blank', 'width=800,height=600');
|
||||
if (printWindow) {
|
||||
printWindow.document.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Print</title></head>
|
||||
<body style="margin:0;">
|
||||
<embed src="${url}" type="application/pdf" width="100%" height="100%">
|
||||
<script>
|
||||
setTimeout(() => { window.print(); }, 1000);
|
||||
setTimeout(() => { window.close(); }, 5000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
}
|
||||
|
||||
// Clean up
|
||||
setTimeout(() => URL.revokeObjectURL(url), 10000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Direct print error:", error);
|
||||
}
|
||||
};
|
||||
@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="web_direct_print.DirectPrintAction">
|
||||
<div class="o_direct_print_action">
|
||||
<!-- This template is minimal as the printing happens in setup() -->
|
||||
<div class="text-center">
|
||||
<i class="fa fa-spinner fa-spin fa-2x"/>
|
||||
<div class="mt-2">Preparing print...</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="web_direct_print.DirectPrintAction">
|
||||
<div class="o_direct_print_action">
|
||||
<!-- This template is minimal as the printing happens in setup() -->
|
||||
<div class="text-center">
|
||||
<i class="fa fa-spinner fa-spin fa-2x"/>
|
||||
<div class="mt-2">Preparing print...</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@ -1,115 +1,115 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Customer Invoice Direct Print -->
|
||||
<record id="action_direct_print_customer_invoice" model="ir.actions.server">
|
||||
<field name="name">Direct Print Customer Invoice</field>
|
||||
<field name="model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for customer invoices
|
||||
invoices = records.filtered(lambda r: r.move_type in ['out_invoice', 'out_refund'])
|
||||
if invoices:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.report_invoice',
|
||||
'docids': invoices.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Vendor Bill Direct Print -->
|
||||
<record id="action_direct_print_vendor_bill" model="ir.actions.server">
|
||||
<field name="name">Direct Print Vendor Bill</field>
|
||||
<field name="model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for vendor bills
|
||||
bills = records.filtered(lambda r: r.move_type in ['in_invoice', 'in_refund'])
|
||||
if bills:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.report_invoice',
|
||||
'docids': bills.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Invoice with Payment Receipt Direct Print -->
|
||||
<record id="action_direct_print_invoice_with_payments" model="ir.actions.server">
|
||||
<field name="name">Direct Print Invoice with Payments</field>
|
||||
<field name="model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for customer invoices
|
||||
invoices = records.filtered(lambda r: r.move_type in ['out_invoice'])
|
||||
if invoices:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.report_invoice_with_payments',
|
||||
'docids': invoices.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Payment Receipt Direct Print -->
|
||||
<record id="action_direct_print_payment_receipt" model="ir.actions.server">
|
||||
<field name="name">Direct Print Payment Receipt</field>
|
||||
<field name="model_id" ref="account.model_account_payment"/>
|
||||
<field name="binding_model_id" ref="account.model_account_payment"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for payments
|
||||
payments = records.filtered(lambda r: r.state == 'posted')
|
||||
if payments:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.action_report_payment_receipt',
|
||||
'docids': payments.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Account Statement Direct Print -->
|
||||
<record id="action_direct_print_account_statement" model="ir.actions.server">
|
||||
<field name="name">Direct Print Account Statement</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="binding_model_id" ref="base.model_res_partner"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for partners with accounting entries
|
||||
partners = records.filtered(lambda r: r.customer_rank > 0 or r.supplier_rank > 0)
|
||||
if partners:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.report_partnerledger',
|
||||
'docids': partners.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Customer Invoice Direct Print -->
|
||||
<record id="action_direct_print_customer_invoice" model="ir.actions.server">
|
||||
<field name="name">Direct Print Customer Invoice</field>
|
||||
<field name="model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for customer invoices
|
||||
invoices = records.filtered(lambda r: r.move_type in ['out_invoice', 'out_refund'])
|
||||
if invoices:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.report_invoice',
|
||||
'docids': invoices.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Vendor Bill Direct Print -->
|
||||
<record id="action_direct_print_vendor_bill" model="ir.actions.server">
|
||||
<field name="name">Direct Print Vendor Bill</field>
|
||||
<field name="model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for vendor bills
|
||||
bills = records.filtered(lambda r: r.move_type in ['in_invoice', 'in_refund'])
|
||||
if bills:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.report_invoice',
|
||||
'docids': bills.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Invoice with Payment Receipt Direct Print -->
|
||||
<record id="action_direct_print_invoice_with_payments" model="ir.actions.server">
|
||||
<field name="name">Direct Print Invoice with Payments</field>
|
||||
<field name="model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_model_id" ref="account.model_account_move"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for customer invoices
|
||||
invoices = records.filtered(lambda r: r.move_type in ['out_invoice'])
|
||||
if invoices:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.report_invoice_with_payments',
|
||||
'docids': invoices.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Payment Receipt Direct Print -->
|
||||
<record id="action_direct_print_payment_receipt" model="ir.actions.server">
|
||||
<field name="name">Direct Print Payment Receipt</field>
|
||||
<field name="model_id" ref="account.model_account_payment"/>
|
||||
<field name="binding_model_id" ref="account.model_account_payment"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for payments
|
||||
payments = records.filtered(lambda r: r.state == 'posted')
|
||||
if payments:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.action_report_payment_receipt',
|
||||
'docids': payments.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Account Statement Direct Print -->
|
||||
<record id="action_direct_print_account_statement" model="ir.actions.server">
|
||||
<field name="name">Direct Print Account Statement</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="binding_model_id" ref="base.model_res_partner"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for partners with accounting entries
|
||||
partners = records.filtered(lambda r: r.customer_rank > 0 or r.supplier_rank > 0)
|
||||
if partners:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'account.report_partnerledger',
|
||||
'docids': partners.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@ -1,3 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
</odoo>
|
||||
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Template for direct print button that can be added to forms -->
|
||||
<template id="direct_print_button" name="Direct Print Button">
|
||||
<button type="button" class="btn btn-primary o_direct_print_btn"
|
||||
title="Print directly to local printer">
|
||||
<i class="fa fa-print"/> Direct Print
|
||||
</button>
|
||||
</template>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Template for direct print button that can be added to forms -->
|
||||
<template id="direct_print_button" name="Direct Print Button">
|
||||
<button type="button" class="btn btn-primary o_direct_print_btn"
|
||||
title="Print directly to local printer">
|
||||
<i class="fa fa-print"/> Direct Print
|
||||
</button>
|
||||
</template>
|
||||
</odoo>
|
||||
@ -1,21 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Add Direct Print button to Purchase Order form view -->
|
||||
<record id="purchase_order_form_direct_print" model="ir.ui.view">
|
||||
<field name="name">purchase.order.form.direct.print</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button name="action_direct_print_purchase_order"
|
||||
type="object"
|
||||
string="Direct Print"
|
||||
class="btn-primary"
|
||||
invisible="state == 'cancel'"
|
||||
groups="purchase.group_purchase_user"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Add Direct Print button to Purchase Order form view -->
|
||||
<record id="purchase_order_form_direct_print" model="ir.ui.view">
|
||||
<field name="name">purchase.order.form.direct.print</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button name="action_direct_print_purchase_order"
|
||||
type="object"
|
||||
string="Direct Print"
|
||||
class="btn-primary"
|
||||
invisible="state == 'cancel'"
|
||||
groups="purchase.group_purchase_user"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@ -1,22 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_direct_print_purchase_order" model="ir.actions.server">
|
||||
<field name="name">Direct Print Request for Quotation / Order</field>
|
||||
<field name="model_id" ref="purchase.model_purchase_order"/>
|
||||
<field name="binding_model_id" ref="purchase.model_purchase_order"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'purchase.report_purchaseorder',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_direct_print_purchase_order" model="ir.actions.server">
|
||||
<field name="name">Direct Print Request for Quotation / Order</field>
|
||||
<field name="model_id" ref="purchase.model_purchase_order"/>
|
||||
<field name="binding_model_id" ref="purchase.model_purchase_order"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'purchase.report_purchaseorder',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@ -1,21 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Add Direct Print button to Sale Order form view -->
|
||||
<record id="view_order_form_direct_print" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.direct.print</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button name="action_direct_print_quotation"
|
||||
type="object"
|
||||
string="Direct Print"
|
||||
class="btn-primary"
|
||||
invisible="state == 'cancel'"
|
||||
groups="sales_team.group_sale_salesman"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Add Direct Print button to Sale Order form view -->
|
||||
<record id="view_order_form_direct_print" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.direct.print</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button name="action_direct_print_quotation"
|
||||
type="object"
|
||||
string="Direct Print"
|
||||
class="btn-primary"
|
||||
invisible="state == 'cancel'"
|
||||
groups="sales_team.group_sale_salesman"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@ -1,22 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_direct_print_sale_order" model="ir.actions.server">
|
||||
<field name="name">Direct Print Quotation / Order</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
<field name="binding_model_id" ref="sale.model_sale_order"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'sale.report_saleorder',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_direct_print_sale_order" model="ir.actions.server">
|
||||
<field name="name">Direct Print Quotation / Order</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
<field name="binding_model_id" ref="sale.model_sale_order"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'sale.report_saleorder',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@ -1,22 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Add Direct Print button to Stock Picking form view -->
|
||||
<record id="view_picking_form_direct_print" model="ir.ui.view">
|
||||
<field name="name">stock.picking.form.direct.print</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button name="action_direct_print_receipt"
|
||||
type="object"
|
||||
string="Direct Print"
|
||||
class="btn-primary"
|
||||
invisible="state not in ['done', 'assigned']"
|
||||
groups="stock.group_stock_user"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Add Direct Print button to Stock Picking form view -->
|
||||
<record id="view_picking_form_direct_print" model="ir.ui.view">
|
||||
<field name="name">stock.picking.form.direct.print</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header" position="inside">
|
||||
<button name="action_direct_print_receipt"
|
||||
type="object"
|
||||
string="Direct Print"
|
||||
class="btn-primary"
|
||||
invisible="state not in ['done', 'assigned']"
|
||||
groups="stock.group_stock_user"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@ -1,160 +1,160 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_direct_print_delivery_slip" model="ir.actions.server">
|
||||
<field name="name">Direct Print Delivery Slip</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_delivery',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_direct_print_picking_operations" model="ir.actions.server">
|
||||
<field name="name">Direct Print Picking Operations</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Internal Transfer Direct Print -->
|
||||
<record id="action_direct_print_internal_transfer" model="ir.actions.server">
|
||||
<field name="name">Direct Print Internal Transfer</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for internal transfers
|
||||
internal_transfers = records.filtered(lambda r: r.picking_type_id.code == 'internal')
|
||||
if internal_transfers:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': internal_transfers.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
else:
|
||||
# All records if none are internal transfers
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Receipt/Incoming Shipment Direct Print -->
|
||||
<record id="action_direct_print_receipt" model="ir.actions.server">
|
||||
<field name="name">Direct Print Receipt</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for incoming/receipt operations
|
||||
receipts = records.filtered(lambda r: r.picking_type_id.code == 'incoming')
|
||||
if receipts:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': receipts.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
else:
|
||||
# All records if none are receipts
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Stock Move Direct Print -->
|
||||
<record id="action_direct_print_stock_move" model="ir.actions.server">
|
||||
<field name="name">Direct Print Stock Move</field>
|
||||
<field name="model_id" ref="stock.model_stock_move"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_move"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.report_stock_move',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Inventory Valuation Direct Print -->
|
||||
<record id="action_direct_print_inventory_valuation" model="ir.actions.server">
|
||||
<field name="name">Direct Print Inventory Valuation</field>
|
||||
<field name="model_id" ref="stock.model_stock_quant"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_quant"/>
|
||||
<field name="binding_view_types">list</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_inventory',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Package/Lot Tracking Direct Print -->
|
||||
<record id="action_direct_print_package_content" model="ir.actions.server">
|
||||
<field name="name">Direct Print Package Content</field>
|
||||
<field name="model_id" ref="stock.model_stock_quant_package"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_quant_package"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_quant_package_barcode',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="action_direct_print_delivery_slip" model="ir.actions.server">
|
||||
<field name="name">Direct Print Delivery Slip</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_delivery',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_direct_print_picking_operations" model="ir.actions.server">
|
||||
<field name="name">Direct Print Picking Operations</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Internal Transfer Direct Print -->
|
||||
<record id="action_direct_print_internal_transfer" model="ir.actions.server">
|
||||
<field name="name">Direct Print Internal Transfer</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for internal transfers
|
||||
internal_transfers = records.filtered(lambda r: r.picking_type_id.code == 'internal')
|
||||
if internal_transfers:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': internal_transfers.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
else:
|
||||
# All records if none are internal transfers
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Receipt/Incoming Shipment Direct Print -->
|
||||
<record id="action_direct_print_receipt" model="ir.actions.server">
|
||||
<field name="name">Direct Print Receipt</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
# Filter for incoming/receipt operations
|
||||
receipts = records.filtered(lambda r: r.picking_type_id.code == 'incoming')
|
||||
if receipts:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': receipts.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
else:
|
||||
# All records if none are receipts
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_picking',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Stock Move Direct Print -->
|
||||
<record id="action_direct_print_stock_move" model="ir.actions.server">
|
||||
<field name="name">Direct Print Stock Move</field>
|
||||
<field name="model_id" ref="stock.model_stock_move"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_move"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.report_stock_move',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Inventory Valuation Direct Print -->
|
||||
<record id="action_direct_print_inventory_valuation" model="ir.actions.server">
|
||||
<field name="name">Direct Print Inventory Valuation</field>
|
||||
<field name="model_id" ref="stock.model_stock_quant"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_quant"/>
|
||||
<field name="binding_view_types">list</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_inventory',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Package/Lot Tracking Direct Print -->
|
||||
<record id="action_direct_print_package_content" model="ir.actions.server">
|
||||
<field name="name">Direct Print Package Content</field>
|
||||
<field name="model_id" ref="stock.model_stock_quant_package"/>
|
||||
<field name="binding_model_id" ref="stock.model_stock_quant_package"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
action = {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'direct_print',
|
||||
'report_name': 'stock.action_report_quant_package_barcode',
|
||||
'docids': records.ids,
|
||||
'context': env.context,
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue
Block a user