| @ -0,0 +1,49 @@ | |||||
|  | .. image:: https://img.shields.io/badge/license-LGPL--3-green.svg | ||||
|  |     :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html | ||||
|  |     :alt: License: LGPL-3 | ||||
|  | 
 | ||||
|  | Add Multiple Products To Invoice/Bill | ||||
|  | ===================================== | ||||
|  | Easily add multiple products to a customer invoice or vendor bill directly from product kanban, list and from views. | ||||
|  | 
 | ||||
|  | Configuration | ||||
|  | ============= | ||||
|  | No additional configuration is needed to use this module. | ||||
|  | 
 | ||||
|  | License | ||||
|  | ------- | ||||
|  | General Public License, Version 3 (LGPL v3). | ||||
|  | (https://www.gnu.org/licenses/lgpl-3.0-standalone.html) | ||||
|  | 
 | ||||
|  | Company | ||||
|  | ------- | ||||
|  | * `Cybrosys Techno Solutions <https://cybrosys.com/>`__ | ||||
|  | 
 | ||||
|  | Credits | ||||
|  | ------- | ||||
|  | * Developer: (V18) Adarsh K, | ||||
|  |              (V17) Mufeeda Shirin, | ||||
|  |              (V16) Jumana Jabin MP, | ||||
|  |   Contact: odoo@cybrosys.com | ||||
|  | 
 | ||||
|  | Contacts | ||||
|  | -------- | ||||
|  | * Mail Contact : odoo@cybrosys.com | ||||
|  | * Website : https://cybrosys.com | ||||
|  | 
 | ||||
|  | Bug Tracker | ||||
|  | ----------- | ||||
|  | Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. | ||||
|  | 
 | ||||
|  | Maintainer | ||||
|  | ========== | ||||
|  | .. image:: https://cybrosys.com/images/logo.png | ||||
|  |    :target: https://cybrosys.com | ||||
|  | 
 | ||||
|  | This module is maintained by Cybrosys Technologies. | ||||
|  | 
 | ||||
|  | For support and more information, please visit https://www.cybrosys.com | ||||
|  | 
 | ||||
|  | Further information | ||||
|  | =================== | ||||
|  | HTML Description: `<static/description/index.html>`__ | ||||
| @ -0,0 +1,23 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Cybrosys Techno Solutions (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from . import models | ||||
|  | from . import wizard | ||||
| @ -0,0 +1,49 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Cybrosys Techno Solutions (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | { | ||||
|  |     'name': 'Add Multiple Products To Invoice/Bill', | ||||
|  |     'version': '18.0.1.0.0', | ||||
|  |     'category': 'Accounting', | ||||
|  |     'summary': 'Easily add multiple products to a invoice/bill directly from ' | ||||
|  |                'the product views', | ||||
|  |     'description': """This module allow you to add multiple products to the  | ||||
|  |      corresponding invoice/bill. You can see all products in kanban, list and | ||||
|  |      form view.You can also view the recent invoice/bill  history of the  | ||||
|  |      selected product along with the option to update the quantity,  | ||||
|  |      Change price, Add Multiple Products""", | ||||
|  |     'author': 'Cybrosys Techno Solutions', | ||||
|  |     'company': 'Cybrosys Techno Solutions', | ||||
|  |     'maintainer': 'Cybrosys Techno Solutions', | ||||
|  |     'website': "https://www.cybrosys.com", | ||||
|  |     'depends': ['base', 'account'], | ||||
|  |     'data': [ | ||||
|  |         'security/ir.model.access.csv', | ||||
|  |         'views/account_move_views.xml', | ||||
|  |         'views/product_product_views.xml', | ||||
|  |         'wizard/invoice_product_details_views.xml' | ||||
|  |     ], | ||||
|  |     'images': ['static/description/banner.png'], | ||||
|  |     'license': 'LGPL-3', | ||||
|  |     'installable': True, | ||||
|  |     'application': False, | ||||
|  |     'auto_install': False | ||||
|  | } | ||||
| @ -0,0 +1,6 @@ | |||||
|  | ## Module <products_to_invoice> | ||||
|  | 
 | ||||
|  | #### 10.09.2024 | ||||
|  | #### Version 18.0.1.0.0 | ||||
|  | ##### ADD | ||||
|  | - Initial commit for Add Multiple Products To Invoice/Bill | ||||
| @ -0,0 +1,23 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Cybrosys Techno Solutions (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from . import account_move | ||||
|  | from . import product_product | ||||
| @ -0,0 +1,40 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Cybrosys Techno Solutions (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from odoo import models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class AccountMove(models.Model): | ||||
|  |     """Inherits the account_move model to add custom functionality.""" | ||||
|  |     _inherit = 'account.move' | ||||
|  | 
 | ||||
|  |     def action_add_product(self): | ||||
|  |         """Action method to open the product_product view and add products | ||||
|  |         to the invoice.""" | ||||
|  |         self.ensure_one() | ||||
|  |         return { | ||||
|  |             'name': 'Product Variants', | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |             'res_model': 'product.product', | ||||
|  |             'view_mode': 'kanban,list,form', | ||||
|  |             'target': 'current', | ||||
|  |             'context': {'add_to_invoice': True}, | ||||
|  |         } | ||||
| @ -0,0 +1,117 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Cybrosys Techno Solutions (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from odoo import api, fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ProductProduct(models.Model): | ||||
|  |     """This class extends the 'product.product' model in Odoo and adds | ||||
|  |        additional functionalities related to invoice handling.""" | ||||
|  |     _inherit = 'product.product' | ||||
|  | 
 | ||||
|  |     @api.depends_context('add_to_invoice') | ||||
|  |     def _compute_add_to_invoice(self): | ||||
|  |         """Compute the 'add_to_invoice' field based on the context. | ||||
|  |         The 'add_to_invoice' field is set to True when the context | ||||
|  |         variable 'add_to_invoice' is present and has a truthy value. | ||||
|  |         Otherwise, it is set to False.""" | ||||
|  |         for record in self: | ||||
|  |             record.add_to_invoice = bool(self.env.context.get('add_to_invoice') | ||||
|  |                                          ) | ||||
|  | 
 | ||||
|  |     add_to_invoice = fields.Boolean( | ||||
|  |         string='Add to Invoice', | ||||
|  |         compute='_compute_add_to_invoice', | ||||
|  |         help='Whether to show the "Add to Invoice" button in the tree view.') | ||||
|  | 
 | ||||
|  |     def _get_invoice_taxes(self, move_id, account_id): | ||||
|  |         """Get invoice taxes based on move type and account.""" | ||||
|  |         self.ensure_one() | ||||
|  |         tax_ids = self.taxes_id.filtered( | ||||
|  |             lambda tax: tax.company_id == move_id.company_id) if \ | ||||
|  |             move_id.move_type == 'out_invoice' else \ | ||||
|  |             self.supplier_taxes_id.filtered( | ||||
|  |                 lambda tax: tax.company_id == move_id.company_id) if \ | ||||
|  |                 move_id.move_type == 'in_invoice' else \ | ||||
|  |                 account_id.tax_ids | ||||
|  |         if not tax_ids: | ||||
|  |             tax_ids = move_id.company_id.account_sale_tax_id if \ | ||||
|  |                 move_id.move_type == 'out_invoice' else \ | ||||
|  |                 move_id.company_id.account_purchase_tax_id if \ | ||||
|  |                     move_id.move_type == 'in_invoice' else \ | ||||
|  |                     self.env['account.tax'] | ||||
|  |         if self.company_id and tax_ids: | ||||
|  |             tax_ids = tax_ids.filtered(lambda tax: tax.company_id == | ||||
|  |                                                    self.company_id) | ||||
|  |         return tax_ids | ||||
|  | 
 | ||||
|  |     def _get_invoice_account(self, move_id): | ||||
|  |         """Return the income/expense account of the selected product.""" | ||||
|  |         self.ensure_one() | ||||
|  |         self = self.with_company(move_id.journal_id.company_id) | ||||
|  |         accounts = self.product_tmpl_id.get_product_accounts \ | ||||
|  |             (fiscal_pos=move_id.fiscal_position_id) | ||||
|  |         return accounts['income'] if move_id.move_type == 'out_invoice' \ | ||||
|  |             else accounts['expense'] | ||||
|  | 
 | ||||
|  |     def action_add_to_invoice(self): | ||||
|  |         """Add the product to the invoice. | ||||
|  |         This method is triggered when the "Add to Invoice" button is clicked. | ||||
|  |         It creates an invoice line and adds it to the invoice.""" | ||||
|  |         invoice_id = self.env['account.move']. \ | ||||
|  |             browse(self._context.get('active_id')) | ||||
|  |         account_id = self._get_invoice_account(invoice_id) | ||||
|  |         tax_ids = self._get_invoice_taxes(invoice_id, account_id) | ||||
|  |         invoice_line_vals = { | ||||
|  |             'product_id': self.id, | ||||
|  |             'product_uom_id': self.uom_id.id, | ||||
|  |             'quantity': 1, | ||||
|  |             'price_unit': self.lst_price if invoice_id.move_type == | ||||
|  |                                             'out_invoice' | ||||
|  |             else self.standard_price, | ||||
|  |             'account_id': account_id.id, | ||||
|  |             'tax_ids': [(fields.Command.set(tax_ids.ids))] | ||||
|  |         } | ||||
|  |         invoice_id.write({ | ||||
|  |             'invoice_line_ids': [(fields.Command.create(invoice_line_vals))] | ||||
|  |         }) | ||||
|  | 
 | ||||
|  |     def action_change_qty(self): | ||||
|  |         """Open the product details wizard. | ||||
|  |         This method is triggered when the "Change Qty" button is clicked. | ||||
|  |         It opens a wizard to modify the quantity and other details of | ||||
|  |         the product. """ | ||||
|  |         invoice_id = self.env['account.move'] \ | ||||
|  |             .browse(self._context.get('active_id')) | ||||
|  |         return { | ||||
|  |             'name': 'Product Details', | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |             'res_model': 'invoice.product.details', | ||||
|  |             'view_mode': 'form', | ||||
|  |             'target': 'new', | ||||
|  |             'context': { | ||||
|  |                 'default_account_move_id': invoice_id.id, | ||||
|  |                 'default_product_id': self.id, | ||||
|  |                 'default_price_unit': self.lst_price if invoice_id.move_type | ||||
|  |                                                         == 'out_invoice' | ||||
|  |                 else self.standard_price, | ||||
|  |             }, | ||||
|  |         } | ||||
| 
 | 
| After Width: | Height: | Size: 2.2 KiB | 
| After Width: | Height: | Size: 28 KiB | 
| After Width: | Height: | Size: 628 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 210 KiB | 
| After Width: | Height: | Size: 209 KiB | 
| After Width: | Height: | Size: 109 KiB | 
| After Width: | Height: | Size: 495 B | 
| After Width: | Height: | Size: 1.0 KiB | 
| After Width: | Height: | Size: 624 B | 
| After Width: | Height: | Size: 136 KiB | 
| After Width: | Height: | Size: 214 KiB | 
| After Width: | Height: | Size: 36 KiB | 
| After Width: | Height: | Size: 3.6 KiB | 
| After Width: | Height: | Size: 310 B | 
| After Width: | Height: | Size: 929 B | 
| After Width: | Height: | Size: 1.3 KiB | 
| After Width: | Height: | Size: 3.3 KiB | 
| After Width: | Height: | Size: 1.4 KiB | 
| After Width: | Height: | Size: 17 KiB | 
| After Width: | Height: | Size: 542 B | 
| After Width: | Height: | Size: 576 B | 
| After Width: | Height: | Size: 733 B | 
| After Width: | Height: | Size: 4.3 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 4.0 KiB | 
| After Width: | Height: | Size: 1.7 KiB | 
| After Width: | Height: | Size: 275 KiB | 
| After Width: | Height: | Size: 2.2 KiB | 
| After Width: | Height: | Size: 911 B | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 600 B | 
| After Width: | Height: | Size: 673 B | 
| After Width: | Height: | Size: 2.0 KiB | 
| After Width: | Height: | Size: 462 B | 
| After Width: | Height: | Size: 2.1 KiB | 
| After Width: | Height: | Size: 926 B | 
| After Width: | Height: | Size: 9.0 KiB | 
| After Width: | Height: | Size: 23 KiB | 
| After Width: | Height: | Size: 7.0 KiB | 
| After Width: | Height: | Size: 878 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 653 B | 
| After Width: | Height: | Size: 800 B | 
| After Width: | Height: | Size: 905 B | 
| After Width: | Height: | Size: 189 KiB | 
| After Width: | Height: | Size: 4.3 KiB | 
| After Width: | Height: | Size: 839 B | 
| After Width: | Height: | Size: 1.7 KiB | 
| After Width: | Height: | Size: 5.9 KiB | 
| After Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 34 KiB | 
| After Width: | Height: | Size: 26 KiB | 
| After Width: | Height: | Size: 3.8 KiB | 
| After Width: | Height: | Size: 23 KiB | 
| After Width: | Height: | Size: 1.9 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 427 B | 
| After Width: | Height: | Size: 627 B | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 988 B | 
| After Width: | Height: | Size: 3.7 KiB | 
| After Width: | Height: | Size: 5.0 KiB | 
| After Width: | Height: | Size: 875 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 912 KiB | 
| After Width: | Height: | Size: 1.3 MiB | 
| After Width: | Height: | Size: 46 KiB | 
| After Width: | Height: | Size: 44 KiB | 
| After Width: | Height: | Size: 46 KiB | 
| After Width: | Height: | Size: 85 KiB | 
| After Width: | Height: | Size: 54 KiB | 
| After Width: | Height: | Size: 57 KiB | 
| After Width: | Height: | Size: 163 KiB | 
| After Width: | Height: | Size: 105 KiB | 
| After Width: | Height: | Size: 75 KiB | 
| After Width: | Height: | Size: 79 KiB | 
| After Width: | Height: | Size: 78 KiB | 
| After Width: | Height: | Size: 880 KiB | 
| After Width: | Height: | Size: 90 KiB | 
| After Width: | Height: | Size: 9.9 KiB | 
| @ -0,0 +1,21 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <!-- Override the account move form view --> | ||||
|  |     <record id="view_move_form" model="ir.ui.view"> | ||||
|  |         <field name="name">account.move.view.form.inherit.product.to.invoice | ||||
|  |         </field> | ||||
|  |         <field name="model">account.move</field> | ||||
|  |         <field name="inherit_id" ref="account.view_move_form"/> | ||||
|  |         <field name="arch" type="xml"> | ||||
|  |             <!-- Insert button inside the button_box div --> | ||||
|  |             <xpath expr="//div[@name='button_box']" position="inside"> | ||||
|  |                 <!-- Add Products button --> | ||||
|  |                 <button name="action_add_product" type="object" | ||||
|  |                         class="oe_stat_button" icon="fa-plus" | ||||
|  |                         invisible="state != 'draft' or move_type not in ['in_invoice','out_invoice']"> | ||||
|  |                     <span>Add Products</span> | ||||
|  |                 </button> | ||||
|  |             </xpath> | ||||
|  |         </field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,72 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <!-- Override the product_product tree view --> | ||||
|  |     <record id="product_product_tree_view" model="ir.ui.view"> | ||||
|  |         <field name="name"> | ||||
|  |             product.product.view.tree.inherit.product.to.invoice | ||||
|  |         </field> | ||||
|  |         <field name="model">product.product</field> | ||||
|  |         <field name="inherit_id" ref="product.product_product_tree_view"/> | ||||
|  |         <field name="arch" type="xml"> | ||||
|  |             <!-- Insert buttons before the default_code field --> | ||||
|  |             <xpath expr="//field[@name='default_code']" position="before"> | ||||
|  |                 <button class="o_field_cell" name="action_add_to_invoice" | ||||
|  |                         type="object" icon="fa-plus" | ||||
|  |                         invisible="add_to_invoice == False" | ||||
|  |                         /> | ||||
|  |                 <button name="action_change_qty" type="object" icon="fa-list" | ||||
|  |                         invisible="add_to_invoice == False" | ||||
|  |                         /> | ||||
|  |                 <field name="add_to_invoice" invisible="1"/> | ||||
|  |             </xpath> | ||||
|  |         </field> | ||||
|  |     </record> | ||||
|  |     <!-- Override the product_product kanban view --> | ||||
|  |     <record id="product_kanban_view" model="ir.ui.view"> | ||||
|  |         <field name="name"> | ||||
|  |             product.product.view.kanban.inherit.product.to.invoice | ||||
|  |         </field> | ||||
|  |         <field name="model">product.product</field> | ||||
|  |         <field name="inherit_id" ref="product.product_kanban_view"/> | ||||
|  |         <field name="arch" type="xml"> | ||||
|  |             <!-- Insert custom div after --> | ||||
|  |             <xpath expr="//aside" | ||||
|  |                    position="after"> | ||||
|  |                 <t t-if="context.add_to_invoice"> | ||||
|  |                     <div class="o_kanban_record_bottom" style="width: 100%;"> | ||||
|  |                         <div class="oe_kanban_bottom_left"> | ||||
|  |                             <a name="action_add_to_invoice" type="object"> | ||||
|  |                                 <i class="fa fa-plus"/>Add to Invoice/Bill | ||||
|  |                             </a> | ||||
|  |                         </div> | ||||
|  |                         <div class="oe_kanban_bottom_right"> | ||||
|  |                             <a name="action_change_qty" type="object"> | ||||
|  |                                 <i class="fa fa-list"/>Change Quantity | ||||
|  |                             </a> | ||||
|  |                         </div> | ||||
|  |                     </div> | ||||
|  |                 </t> | ||||
|  |             </xpath> | ||||
|  |         </field> | ||||
|  |     </record> | ||||
|  |     <!-- Override the product_product form view --> | ||||
|  |     <record id="product_normal_form_view" model="ir.ui.view"> | ||||
|  |         <field name="name"> | ||||
|  |             product.product.view.form.inherit.product.to.invoice | ||||
|  |         </field> | ||||
|  |         <field name="model">product.product</field> | ||||
|  |         <field name="inherit_id" ref="product.product_normal_form_view"/> | ||||
|  |         <field name="arch" type="xml"> | ||||
|  |             <!-- Insert buttons inside the header section --> | ||||
|  |             <xpath expr="//header" position="inside"> | ||||
|  |                 <button name="action_add_to_invoice" type="object" | ||||
|  |                         string="Add to Invoice/Bill" class="oe_highlight" | ||||
|  |                         icon="fa-plus" | ||||
|  |                         invisible="not context.get('add_to_invoice')"/> | ||||
|  |                 <button name="action_change_qty" type="object" icon="fa-list" | ||||
|  |                         help="Update Quantity" | ||||
|  |                         invisible="not context.get('add_to_invoice')"/> | ||||
|  |             </xpath> | ||||
|  |         </field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,23 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Cybrosys Techno Solutions (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from . import invoice_product_details | ||||
|  | from . import product_invoice_history | ||||
| @ -0,0 +1,99 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Cybrosys Techno Solutions (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from datetime import timedelta | ||||
|  | from odoo import api, fields, models, _ | ||||
|  | from odoo.exceptions import UserError | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class InvoiceProductDetails(models.TransientModel): | ||||
|  |     """ Wizard model to display invoice product details.""" | ||||
|  |     _name = 'invoice.product.details' | ||||
|  |     _description = 'Invoice Product Details' | ||||
|  | 
 | ||||
|  |     product_id = fields.Many2one('product.product', string='Product', | ||||
|  |                                  readonly=True, | ||||
|  |                                  help="Select the product for this record.") | ||||
|  |     qty = fields.Float(string='Quantity', default=1, | ||||
|  |                        help="Enter the quantity of the selected product.") | ||||
|  |     account_move_id = fields.Many2one('account.move', readonly=True, | ||||
|  |                                       help="Link to the corresponding " | ||||
|  |                                            "account move.") | ||||
|  |     price_unit = fields.Float(string='Unit Price', | ||||
|  |                               help="Enter the unit price of the product.") | ||||
|  |     invoice_history_ids = fields.One2many('product.invoice.history', | ||||
|  |                                           'product_details_id', readonly=True, | ||||
|  |                                           help="History of invoices related" | ||||
|  |                                                " to this product.") | ||||
|  |     date_from = fields.Date(default=fields.Date.today() - timedelta(days=30), | ||||
|  |                             help="Default date from which a record is " | ||||
|  |                                  "created.") | ||||
|  |     limit = fields.Integer(string='Limit', default=20, | ||||
|  |                            help="Set the limit for product") | ||||
|  | 
 | ||||
|  |     @api.onchange('date_from', 'limit') | ||||
|  |     def _onchange_date_from(self): | ||||
|  |         """Update invoice history based on selected date range and limit. | ||||
|  |         This method is triggered when the 'date_from' or 'limit' field changes. | ||||
|  |         It retrieves invoice lines matching the specified criteria and | ||||
|  |          updates the invoice history. """ | ||||
|  |         invoice_lines = self.env['account.move.line'].search([ | ||||
|  |             ('product_id', '=', self.product_id.id), | ||||
|  |             ('move_id.state', '=', 'posted'), | ||||
|  |             ('move_id.invoice_date', '>=', self.date_from), | ||||
|  |             ('move_id.move_type', 'in', ('out_invoice', 'in_invoice')) | ||||
|  |         ], limit=self.limit) | ||||
|  |         vals = [fields.Command.clear()] | ||||
|  |         for line in invoice_lines: | ||||
|  |             vals.append(fields.Command.create({ | ||||
|  |                 'date': line.move_id.invoice_date, | ||||
|  |                 'partner_id': line.move_id.partner_id.id, | ||||
|  |                 'qty': line.quantity, | ||||
|  |                 'account_move_number': line.move_id.name, | ||||
|  |                 'price_unit': line.price_unit, | ||||
|  |                 'total': line.price_subtotal, | ||||
|  |                 'type': line.move_id.move_type, | ||||
|  |                 'move_id': line.move_id.id | ||||
|  |             })) | ||||
|  |         self.invoice_history_ids = vals | ||||
|  | 
 | ||||
|  |     def action_add_to_invoice(self): | ||||
|  |         """Add the product to the invoice. | ||||
|  |          This method is used to add the current product to the associated | ||||
|  |          invoice.It creates an invoice line and adds it to the invoice.""" | ||||
|  |         account_id = self.product_id._get_invoice_account(self.account_move_id) | ||||
|  |         tax_ids = self.product_id._get_invoice_taxes \ | ||||
|  |             (self.account_move_id, account_id) | ||||
|  |         invoice_line_vals = { | ||||
|  |             'product_id': self.product_id.id, | ||||
|  |             'product_uom_id': self.product_id.uom_id.id, | ||||
|  |             'quantity': self.qty, | ||||
|  |             'price_unit': self.price_unit, | ||||
|  |             'account_id': account_id.id, | ||||
|  |             'tax_ids': tax_ids, | ||||
|  |             'move_id': self.account_move_id.id, | ||||
|  |         } | ||||
|  |         invoice_line = self.env['account.move.line'].create(invoice_line_vals) | ||||
|  |         if invoice_line: | ||||
|  |             self.account_move_id.write( | ||||
|  |                 {'invoice_line_ids': [fields.Command.link(invoice_line.id)]}) | ||||
|  |         else: | ||||
|  |             raise UserError(_("Failed to create invoice line.")) | ||||
| @ -0,0 +1,73 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <!-- Define the view for the invoice product details wizard --> | ||||
|  |     <record id="invoice_product_details_view_form" model="ir.ui.view"> | ||||
|  |         <field name="name">invoice.product.details.view.form</field> | ||||
|  |         <field name="model">invoice.product.details</field> | ||||
|  |         <field name="arch" type="xml"> | ||||
|  |             <!-- Form view for the product details --> | ||||
|  |             <form string="Product Details"> | ||||
|  |                 <group> | ||||
|  |                     <group> | ||||
|  |                         <field name="product_id"/> | ||||
|  |                         <field name="qty"/> | ||||
|  |                     </group> | ||||
|  |                     <group> | ||||
|  |                         <field name="account_move_id"/> | ||||
|  |                         <field name="price_unit"/> | ||||
|  |                     </group> | ||||
|  |                 </group> | ||||
|  |                 <group/> | ||||
|  |                 <group string="Recent Invoice/Bill History"/> | ||||
|  |                 <group> | ||||
|  |                     <group> | ||||
|  |                         <field name="date_from"/> | ||||
|  |                     </group> | ||||
|  |                     <group> | ||||
|  |                         <field name="limit"/> | ||||
|  |                     </group> | ||||
|  |                 </group> | ||||
|  |                 <notebook> | ||||
|  |                     <page string="History"> | ||||
|  |                         <field name="invoice_history_ids" widget="on2many" | ||||
|  |                                nolabel="1"> | ||||
|  |                             <list> | ||||
|  |                                 <field name="type"/> | ||||
|  |                                 <field name="date"/> | ||||
|  |                                 <field name="account_move_number"/> | ||||
|  |                                 <field name="partner_id"/> | ||||
|  |                                 <field name="qty"/> | ||||
|  |                                 <field name="price_unit"/> | ||||
|  |                                 <field name="total"/> | ||||
|  |                             </list> | ||||
|  |                             <form> | ||||
|  |                                 <group> | ||||
|  |                                     <group> | ||||
|  |                                         <field name="type" readonly="1"/> | ||||
|  |                                         <field name="move_id" readonly="1"/> | ||||
|  |                                         <field name="partner_id" readonly="1"/> | ||||
|  |                                         <field name="date" readonly="1"/> | ||||
|  |                                     </group> | ||||
|  |                                     <group> | ||||
|  |                                         <field name="qty" readonly="1"/> | ||||
|  |                                         <field name="price_unit" readonly="1"/> | ||||
|  |                                         <field name="total" readonly="1"/> | ||||
|  |                                     </group> | ||||
|  |                                 </group> | ||||
|  |                                 <footer> | ||||
|  |                                     <button string="Close" class="oe_highlight" | ||||
|  |                                             special="cancel"/> | ||||
|  |                                 </footer> | ||||
|  |                             </form> | ||||
|  |                         </field> | ||||
|  |                     </page> | ||||
|  |                 </notebook> | ||||
|  |                 <footer> | ||||
|  |                     <button name="action_add_to_invoice" string="Add to Invoice" | ||||
|  |                             type="object" class="oe_highlight"/> | ||||
|  |                     <button string="Cancel" special="cancel"/> | ||||
|  |                 </footer> | ||||
|  |             </form> | ||||
|  |         </field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,53 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Cybrosys Techno Solutions (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU LESSER | ||||
|  | #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | ||||
|  | # | ||||
|  | #    This program is distributed in the hope that it will be useful, | ||||
|  | #    but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  | #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | ||||
|  | #    (LGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################# | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ProductInvoiceHistory(models.TransientModel): | ||||
|  |     """Product Invoice History model for storing invoice line details.""" | ||||
|  |     _name = 'product.invoice.history' | ||||
|  |     _description = 'Product Invoice History' | ||||
|  | 
 | ||||
|  |     product_details_id = fields.Many2one('invoice.product.details', | ||||
|  |                                          string='Product Details', | ||||
|  |                                          help='The associated product' | ||||
|  |                                               ' details for the invoice') | ||||
|  |     date = fields.Datetime(string='Date', help='The date of the invoice') | ||||
|  |     move_id = fields.Many2one('account.move', string='Invoice/Bill', | ||||
|  |                               help='The associated account move for the ' | ||||
|  |                                    'invoice') | ||||
|  |     account_move_number = fields.Char(string='Invoice/Bill No', | ||||
|  |                                       help='The number of the invoice/bill') | ||||
|  |     partner_id = fields.Many2one('res.partner', string='Customer/Vendor', | ||||
|  |                                  help='The customer or vendor associated ' | ||||
|  |                                       'with the invoice') | ||||
|  |     price_unit = fields.Float(string='Unit Price', | ||||
|  |                               help='The unit price of the product or service') | ||||
|  |     total = fields.Float(string='Total', | ||||
|  |                          help='The total amount for the invoice') | ||||
|  |     qty = fields.Float(string='Quantity', | ||||
|  |                        help='The quantity of the product or service') | ||||
|  |     type = fields.Selection([ | ||||
|  |         ('out_invoice', 'Customer Invoice'), | ||||
|  |         ('in_invoice', 'Vendor Bill') | ||||
|  |     ], string='Type', | ||||
|  |         help='The type of the invoice (customer invoice or vendor bill)') | ||||