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