| @ -0,0 +1,46 @@ | |||||
|  | .. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg | ||||
|  |     :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html | ||||
|  |     :alt: License: AGPL-3 | ||||
|  | 
 | ||||
|  | All In One Purchase Kit | ||||
|  | ======================= | ||||
|  | This module combines a verity of Purchase features. By Installing this module a user can get features like Product brand, Merge sale order, Purchase Order Line View, Amount in company currency, Amount in words, Employee Purchase requisition, Product recommendation etc.. | ||||
|  | 
 | ||||
|  | Configuration | ||||
|  | ============= | ||||
|  | - No additional configuration is required | ||||
|  | 
 | ||||
|  | Company | ||||
|  | ------- | ||||
|  | * `Cybrosys Techno Solutions <https://cybrosys.com/>`__ | ||||
|  | 
 | ||||
|  | License | ||||
|  | ------- | ||||
|  | GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (AGPL v3) | ||||
|  | (https://www.gnu.org/licenses/agpl-3.0-standalone.html) | ||||
|  | 
 | ||||
|  | Credits | ||||
|  | ------- | ||||
|  | Developer: (V15) Swaraj R, 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 `Our Website <https://cybrosys.com/>`__ | ||||
|  | 
 | ||||
|  | Further information | ||||
|  | =================== | ||||
|  | HTML Description: `<static/description/index.html>`__ | ||||
| @ -0,0 +1,25 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from . import controllers | ||||
|  | from . import models | ||||
|  | from . import report | ||||
|  | from . import wizard | ||||
| @ -0,0 +1,93 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | { | ||||
|  |     'name': 'All In One Purchase Kit', | ||||
|  |     'version': '15.0.1.0.0', | ||||
|  |     'category': 'Purchases', | ||||
|  |     'summary': 'An integrated module offering streamlined purchase management', | ||||
|  |     'description': 'Product Brand for products, Purchase Order Line View,' | ||||
|  |                    'Company Currency Total in Purchase,' | ||||
|  |                    'Employee Purchase Requisition,' | ||||
|  |                    'Purchase All In One Report Generator,' | ||||
|  |                    'Previous Purchase Product Rates,' | ||||
|  |                    'Barcode scanning support for Purchase,' | ||||
|  |                    'Amount in Words in Invoice for Purchase Order,' | ||||
|  |                    'Multiple Purchase Order Confirm And Cancel,' | ||||
|  |                    'Merge Same Product Line, Product image in order-line,' | ||||
|  |                    'Purchase discount from Purchase order line,' | ||||
|  |                    'Product Recommendation', | ||||
|  |     'author': 'Cybrosys Techno Solutions', | ||||
|  |     'company': 'Cybrosys Techno Solutions', | ||||
|  |     'maintainer': 'Cybrosys Techno Solutions', | ||||
|  |     'website': 'https://www.cybrosys.com', | ||||
|  |     'depends': ['base', 'hr', 'stock', 'purchase'], | ||||
|  |     'data': [ | ||||
|  |         'security/all_in_one_purchase_kit_groups.xml', | ||||
|  |         'security/all_in_one_purchase_kit_security.xml', | ||||
|  |         'security/ir.model.access.csv', | ||||
|  |         'data/ir_sequence_data.xml', | ||||
|  |         'data/mail_template_data.xml', | ||||
|  |         'views/employee_purchase_requisition_views.xml', | ||||
|  |         'views/hr_employee_views.xml', | ||||
|  |         'views/hr_department_views.xml', | ||||
|  |         'views/purchase_order_views.xml', | ||||
|  |         'views/stock_picking_views.xml', | ||||
|  |         'views/employee_purchase_requisition_action.xml', | ||||
|  |         'views/product_brand_views.xml', | ||||
|  |         'views/product_template_views.xml', | ||||
|  |         'views/purchase_report_views.xml', | ||||
|  |         'views/purchase_order_line_views.xml', | ||||
|  |         'views/rfq_line_views.xml', | ||||
|  |         'views/purchase_report.xml', | ||||
|  |         'views/account_move_views.xml', | ||||
|  |         'views/product_product_views.xml', | ||||
|  |         'views/res_config_settings_views.xml', | ||||
|  |         'views/product_supplier_views.xml', | ||||
|  |         'views/res_partner_views.xml', | ||||
|  |         'views/purchase_dashboard.xml', | ||||
|  |         'report/purchase_order_report_templates.xml', | ||||
|  |         'report/all_in_one_purchase_kit_report_views.xml', | ||||
|  |         'report/purchase_requisition_templates.xml', | ||||
|  |         'report/purchase_order_templates.xml', | ||||
|  |         'report/dynamic_purchase_report_action.xml', | ||||
|  |         'wizard/product_recommendation_views.xml', | ||||
|  |         'views/all_in_one_purchase_kit_menus.xml', | ||||
|  |     ], | ||||
|  |     'assets': { | ||||
|  |         'web.assets_backend': [ | ||||
|  |             'all_in_one_purchase_kit/static/src/js/purchase_report.js', | ||||
|  |             'all_in_one_purchase_kit/static/src/js/PurchaseDashboard.js', | ||||
|  |             'all_in_one_purchase_kit/static/src/css' | ||||
|  |             '/all_in_one_purchase_kit_purchase_report.css', | ||||
|  |             'all_in_one_purchase_kit/static/src/scss/purchase_dashboard.scss', | ||||
|  |             'https://cdn.jsdelivr.net/npm/chart.js', | ||||
|  |         ], | ||||
|  |         'web.assets_qweb': [ | ||||
|  |             'all_in_one_purchase_kit/static/src/xml/**/*', | ||||
|  |         ], | ||||
|  |     }, | ||||
|  |     'images': ['static/description/banner.jpg'], | ||||
|  |     'license': 'AGPL-3', | ||||
|  |     'installable': True, | ||||
|  |     'auto_install': False, | ||||
|  |     'application': False, | ||||
|  | } | ||||
| @ -0,0 +1,22 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from . import all_in_one_purchase_kit | ||||
| @ -0,0 +1,57 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | import json | ||||
|  | from odoo import http | ||||
|  | from odoo.http import content_disposition, request | ||||
|  | from odoo.tools import html_escape | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class PurchaseReportController(http.Controller): | ||||
|  |     """Controller to generate excel report""" | ||||
|  |     @http.route('/purchase_dynamic_xlsx_reports', type='http', auth='user', | ||||
|  |                 methods=['POST'], csrf=False) | ||||
|  |     def get_report_xlsx(self, model, options, output_format, report_data, | ||||
|  |                         report_name, dfr_data): | ||||
|  |         """ Method to generate and return an Excel report.""" | ||||
|  |         token = 'dummy-because-api-expects-one' | ||||
|  |         try: | ||||
|  |             if output_format == 'xlsx': | ||||
|  |                 response = request.make_response( | ||||
|  |                     None, | ||||
|  |                     headers=[ | ||||
|  |                         ('Content-Type', 'application/vnd.ms-excel'), | ||||
|  |                         ('Content-Disposition', content_disposition( | ||||
|  |                             report_name + '.xlsx')) | ||||
|  |                     ] | ||||
|  |                 ) | ||||
|  |                 request.env[model].with_user( | ||||
|  |                     request.session.uid).get_purchase_xlsx_report( | ||||
|  |                     options, response, report_data, dfr_data) | ||||
|  |             response.set_cookie('fileToken', token) | ||||
|  |             return response | ||||
|  |         except Exception: | ||||
|  |             error = { | ||||
|  |                 'code': 200, | ||||
|  |                 'message': 'Odoo Server Error', | ||||
|  |                 'data': 0, | ||||
|  |             } | ||||
|  |             return request.make_response(html_escape(json.dumps(error))) | ||||
| @ -0,0 +1,14 @@ | |||||
|  | <odoo> | ||||
|  |     <!-- Sequence for employee purchase requisition --> | ||||
|  |     <data noupdate="1"> | ||||
|  |         <record id="sequence_purchase_requisition" model="ir.sequence"> | ||||
|  |             <field name="name">Employee Purchase Requisition</field> | ||||
|  |             <field name="code">employee.purchase.requisition</field> | ||||
|  |             <field name="prefix">EPR</field> | ||||
|  |             <field name="padding">5</field> | ||||
|  |             <field eval="1" name="number_next"/> | ||||
|  |             <field eval="1" name="number_increment"/> | ||||
|  |             <field eval="False" name="company_id"/> | ||||
|  |         </record> | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,62 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <data noupdate="1"> | ||||
|  |     <!--Function to set noupdate to False--> | ||||
|  |         <function name="write" model="ir.model.data"> | ||||
|  |             <function name="search" model="ir.model.data"> | ||||
|  |                 <value eval="[('name', '=', 'email_template_edi_purchase_done'), ('module', '=', 'purchase')]"/> | ||||
|  |             </function> | ||||
|  |             <value eval="{'noupdate': False}"/> | ||||
|  |         </function> | ||||
|  |         <!--Confirmed po send mail data--> | ||||
|  |         <record id="purchase.email_template_edi_purchase_done" | ||||
|  |                 model="mail.template"> | ||||
|  |             <field name="body_html" type="html"> | ||||
|  |                 <div style="margin: 0px; padding: 0px;"> | ||||
|  |                     <p style="margin: 0px; padding: 0px; font-size: 13px;"> | ||||
|  |                         Dear | ||||
|  |                         <t t-out="object.partner_id.name or ''">Brandon Freeman</t> | ||||
|  |                         <t t-if="object.partner_id.parent_id"> | ||||
|  |                             (<t t-out="object.partner_id.parent_id.name or ''"> | ||||
|  |                             Azure Interior</t>) | ||||
|  |                         </t> | ||||
|  |                         <br/> | ||||
|  |                         <br/> | ||||
|  |                         Here is in attachment a purchase order | ||||
|  |                         <strong t-out="object.name or ''">P00015</strong> | ||||
|  |                         <t t-if="object.partner_ref"> | ||||
|  |                             with reference: | ||||
|  |                             <t t-out="object.partner_ref or ''">REF_XXX</t> | ||||
|  |                         </t> | ||||
|  |                         amounting in | ||||
|  |                         <strong t-out="format_amount(object.amount_total, object.currency_id) or ''"> | ||||
|  |                             $ 10.00 | ||||
|  |                         </strong> | ||||
|  |                         <span> | ||||
|  |                             <strong t-out="object.number_to_words"/> | ||||
|  |                         </span> | ||||
|  |                         from <t t-out="object.company_id.name or ''"> | ||||
|  |                         YourCompany</t>. | ||||
|  |                         <br/> | ||||
|  |                         <br/> | ||||
|  |                         <t t-if="object.date_planned"> | ||||
|  |                             The receipt is expected for <strong | ||||
|  |                                 t-out="format_date(object.date_planned) or ''"> | ||||
|  |                             05/05/2021</strong>. | ||||
|  |                             <br/> | ||||
|  |                             <br/> | ||||
|  |                             Could you please acknowledge the receipt of this order? | ||||
|  |                         </t> | ||||
|  |                     </p> | ||||
|  |                 </div> | ||||
|  |             </field> | ||||
|  |         </record> | ||||
|  | <!--        Function to set noupdate to True--> | ||||
|  |         <function name="write" model="ir.model.data"> | ||||
|  |             <function name="search" model="ir.model.data"> | ||||
|  |                 <value eval="[('name', '=', 'email_template_edi_purchase_done'), ('module', '=', 'purchase')]"/> | ||||
|  |             </function> | ||||
|  |             <value eval="{'noupdate': True}"/> | ||||
|  |         </function> | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,7 @@ | |||||
|  | ## Module <all_in_one_purchase_kit> | ||||
|  | 
 | ||||
|  | #### 02.07.2024 | ||||
|  | #### Version 15.0.1.0.0 | ||||
|  | #### ADD | ||||
|  | 
 | ||||
|  | - Initial Commit for All In One Purchase Kit | ||||
| @ -0,0 +1,37 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from . import account_move | ||||
|  | from . import dynamic_purchase_report | ||||
|  | from . import employee_purchase_requisition | ||||
|  | from . import hr_department | ||||
|  | from . import hr_employee | ||||
|  | from . import product_brand | ||||
|  | from . import product_product | ||||
|  | from . import product_supplierinfo | ||||
|  | from . import product_template | ||||
|  | from . import purchase_order | ||||
|  | from . import purchase_order_line | ||||
|  | from . import purchase_report | ||||
|  | from . import requisition_order | ||||
|  | from . import res_config_settings | ||||
|  | from . import res_partner | ||||
|  | from . import stock_picking | ||||
| @ -0,0 +1,64 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class AccountMove(models.Model): | ||||
|  |     """Inherit account.move to add fields and methods""" | ||||
|  |     _inherit = 'account.move' | ||||
|  | 
 | ||||
|  |     amount_total_company_signed = fields.Float( | ||||
|  |         string='Company Currency Total', | ||||
|  |         compute='_compute_amount_total_company_signed', | ||||
|  |         help="Total amount in company currency") | ||||
|  |     number_to_words = fields.Char( | ||||
|  |         string="Amount in Words (Total) : ", | ||||
|  |         compute='_compute_number_to_words', help="Amount in words") | ||||
|  | 
 | ||||
|  |     def _compute_amount_total_company_signed(self): | ||||
|  |         """Compute the total amount in company currency for each record.""" | ||||
|  |         for amount in self: | ||||
|  |             amount.amount_total_company_signed = self.env[ | ||||
|  |                 'res.currency']._compute( | ||||
|  |                 amount.currency_id, amount.company_id.currency_id, | ||||
|  |                 amount.amount_total) | ||||
|  | 
 | ||||
|  |     def _compute_number_to_words(self): | ||||
|  |         """Compute the amount to words in Invoice for each record.""" | ||||
|  |         for rec in self: | ||||
|  |             rec.number_to_words = rec.currency_id.amount_to_text( | ||||
|  |                 rec.amount_total) | ||||
|  | 
 | ||||
|  |     def action_post(self): | ||||
|  |         """Override the default post action to merge order lines with the same | ||||
|  |          product and price.""" | ||||
|  |         for line in self.invoice_line_ids: | ||||
|  |             if line.id in self.invoice_line_ids.ids: | ||||
|  |                 line_ids = self.invoice_line_ids.filtered( | ||||
|  |                     lambda m: m.product_id.id == line.product_id.id and m. | ||||
|  |                     price_unit == line.price_unit) | ||||
|  |                 quantity = line_ids.mapped('quantity') | ||||
|  |                 line_ids.write({'quantity': sum(quantity), | ||||
|  |                                 'price_unit': line.price_unit}) | ||||
|  |                 line_ids[1:].unlink() | ||||
|  |         res = super(AccountMove, self).action_post() | ||||
|  |         return res | ||||
| @ -0,0 +1,498 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | import io | ||||
|  | import re | ||||
|  | import json | ||||
|  | from odoo import api, fields, models | ||||
|  | from odoo.exceptions import ValidationError | ||||
|  | try: | ||||
|  |     from odoo.tools.misc import xlsxwriter | ||||
|  | except ImportError: | ||||
|  |     import xlsxwriter | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class DynamicPurchaseReport(models.Model): | ||||
|  |     """Model for generating dynamic purchase reports""" | ||||
|  |     _name = "dynamic.purchase.report" | ||||
|  |     _description = 'Dynamic Purchase Report' | ||||
|  | 
 | ||||
|  |     purchase_report = fields.Char( | ||||
|  |         string="Purchase Report", help="Purchase Report" | ||||
|  |     ) | ||||
|  |     date_from = fields.Datetime( | ||||
|  |         string="Date From", help="From which date report needed" | ||||
|  |     ) | ||||
|  |     date_to = fields.Datetime( | ||||
|  |         string="Date to", help="Till which date report needs to print" | ||||
|  |     ) | ||||
|  |     report_type = fields.Selection([ | ||||
|  |         ('report_by_order', 'Report By Order'), | ||||
|  |         ('report_by_order_detail', 'Report By Order Detail'), | ||||
|  |         ('report_by_product', 'Report By Product'), | ||||
|  |         ('report_by_categories', 'Report By Categories'), | ||||
|  |         ('report_by_purchase_representative', | ||||
|  |          'Report By Purchase Representative'), | ||||
|  |         ('report_by_state', 'Report By State')], default='report_by_order', | ||||
|  |         string="Report Type", | ||||
|  |         help="Choose the report type need to be printed" | ||||
|  |     ) | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def purchase_report(self, option): | ||||
|  |         """ | ||||
|  |         Generate a dynamic purchase report. | ||||
|  |         """ | ||||
|  |         report_values = self.env['dynamic.purchase.report'].browse(option) | ||||
|  |         data = { | ||||
|  |             'report_type': report_values.report_type, | ||||
|  |             'model': self, | ||||
|  |         } | ||||
|  |         if report_values.date_from: | ||||
|  |             data.update({ | ||||
|  |                 'date_from': report_values.date_from, | ||||
|  |             }) | ||||
|  |         if report_values.date_to: | ||||
|  |             data.update({ | ||||
|  |                 'date_to': report_values.date_to, | ||||
|  |             }) | ||||
|  |         filters = self.get_filter(option) | ||||
|  |         lines = self._get_report_values(data).get('PURCHASE') | ||||
|  |         return { | ||||
|  |             'name': "Purchase Orders", | ||||
|  |             'type': 'ir.actions.client', | ||||
|  |             'tag': 's_r', | ||||
|  |             'orders': data, | ||||
|  |             'filters': filters, | ||||
|  |             'report_lines': lines, | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     def get_filter(self, option): | ||||
|  |         """Get the selected filter type for the report.""" | ||||
|  |         data = self.get_filter_data(option) | ||||
|  |         filters = {} | ||||
|  |         if data.get('report_type') == 'report_by_order': | ||||
|  |             filters['report_type'] = 'Report By Order' | ||||
|  |         elif data.get('report_type') == 'report_by_order_detail': | ||||
|  |             filters['report_type'] = 'Report By Order Detail' | ||||
|  |         elif data.get('report_type') == 'report_by_product': | ||||
|  |             filters['report_type'] = 'Report By Product' | ||||
|  |         elif data.get('report_type') == 'report_by_categories': | ||||
|  |             filters['report_type'] = 'Report By Categories' | ||||
|  |         elif data.get('report_type') == 'report_by_purchase_representative': | ||||
|  |             filters['report_type'] = 'Report By Purchase Representative' | ||||
|  |         elif data.get('report_type') == 'report_by_state': | ||||
|  |             filters['report_type'] = 'Report By State' | ||||
|  |         else: | ||||
|  |             filters['report_type'] = 'report_by_order' | ||||
|  |         return filters | ||||
|  | 
 | ||||
|  |     def get_filter_data(self, option): | ||||
|  |         """Get filter data for the specified report configuration.""" | ||||
|  |         return { | ||||
|  |             'report_type': self.env[ | ||||
|  |                 'dynamic.purchase.report'].browse(option).report_type | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def create(self, vals): | ||||
|  |         """Override the default create method to create a new dynamic purchase | ||||
|  |          report record.""" | ||||
|  |         return super(DynamicPurchaseReport, self).create(vals) | ||||
|  | 
 | ||||
|  |     def write(self, vals): | ||||
|  |         """Override the default write method to update the field values of the | ||||
|  |          dynamic purchase report record.""" | ||||
|  |         if 'date_from' not in vals: | ||||
|  |             vals['date_from'] = False | ||||
|  |         if 'date_to' not in vals: | ||||
|  |             vals['date_to'] = False | ||||
|  |         res = super(DynamicPurchaseReport, self).write(vals) | ||||
|  |         return res | ||||
|  | 
 | ||||
|  |     def _get_report_sub_lines(self, data, report, date_from, date_to): | ||||
|  |         """Getting data for report lines""" | ||||
|  |         if 'date_to' in data: | ||||
|  |             data['date_to'] = data['date_to'].replace(hour=23, minute=59, second=59) | ||||
|  |         if 'date_from' in data: | ||||
|  |             data['date_from'] = data['date_from'].replace(hour=0, minute=0, second=0) | ||||
|  |         report_sub_lines = [] | ||||
|  |         if data.get('report_type') == 'report_by_order': | ||||
|  |             query = ''' | ||||
|  |             select l.name,l.date_order,l.partner_id,l.amount_total, | ||||
|  |             l.notes,l.user_id,res_partner.name as partner, | ||||
|  |             res_users.partner_id as user_partner, | ||||
|  |             sum(purchase_order_line.product_qty),l.id as id, | ||||
|  |             (SELECT res_partner.name as salesman FROM | ||||
|  |             res_partner WHERE res_partner.id = res_users.partner_id) | ||||
|  |             from purchase_order as l | ||||
|  |             left join res_partner on l.partner_id = res_partner.id | ||||
|  |             left join res_users on l.user_id = res_users.id | ||||
|  |             left join purchase_order_line on l.id = | ||||
|  |             purchase_order_line.order_id | ||||
|  |             ''' | ||||
|  |             term = 'Where ' | ||||
|  |             if data.get('date_from') and data.get('date_to') and \ | ||||
|  |                     data.get('date_from') > data.get('date_to'): | ||||
|  |                 raise ValidationError('Start Date cannot be greater than ' | ||||
|  |                                       'End Date') | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += "Where l.date_order >= '%s' " % data.get('date_from') | ||||
|  |                 term = 'AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + "l.date_order <= '%s' " % data.get('date_to') | ||||
|  |             query += "group by l.user_id,res_users.partner_id," \ | ||||
|  |                      "res_partner.name,l.partner_id,l.date_order,l.name," \ | ||||
|  |                      "l.amount_total,l.notes,l.id" | ||||
|  |             self._cr.execute(query) | ||||
|  |             report_by_order = self._cr.dictfetchall() | ||||
|  |             report_sub_lines.append(report_by_order) | ||||
|  |         elif data.get('report_type') == 'report_by_order_detail': | ||||
|  |             query = ''' | ||||
|  |             select l.name,l.date_order,l.partner_id,l.amount_total, | ||||
|  |             l.notes,l.user_id,res_partner.name as partner, | ||||
|  |             res_users.partner_id as user_partner, | ||||
|  |             sum(purchase_order_line.product_qty), | ||||
|  |             purchase_order_line.name as product, | ||||
|  |             purchase_order_line.price_unit,purchase_order_line.price_subtotal, | ||||
|  |             l.amount_total,purchase_order_line.product_id, | ||||
|  |             product_product.default_code, | ||||
|  |             (SELECT res_partner.name as salesman FROM res_partner | ||||
|  |             WHERE res_partner.id = res_users.partner_id) | ||||
|  |             from purchase_order as l | ||||
|  |             left join res_partner on l.partner_id = res_partner.id | ||||
|  |             left join res_users on l.user_id = res_users.id | ||||
|  |             left join purchase_order_line on l.id = | ||||
|  |             purchase_order_line.order_id | ||||
|  |             left join product_product on purchase_order_line.product_id = | ||||
|  |             product_product.id | ||||
|  |             ''' | ||||
|  |             term = 'Where ' | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += "Where l.date_order >= '%s' " % data.get('date_from') | ||||
|  |                 term = 'AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + "l.date_order <= '%s' " % data.get('date_to') | ||||
|  |             query += "group by l.user_id,res_users.partner_id," \ | ||||
|  |                      "res_partner.name,l.partner_id,l.date_order," \ | ||||
|  |                      "l.name,l.amount_total,l.notes," \ | ||||
|  |                      "purchase_order_line.name," \ | ||||
|  |                      "purchase_order_line.price_unit," \ | ||||
|  |                      "purchase_order_line.price_subtotal,l.amount_total," \ | ||||
|  |                      "purchase_order_line.product_id," \ | ||||
|  |                      "product_product.default_code" | ||||
|  |             self._cr.execute(query) | ||||
|  |             report_by_order_details = self._cr.dictfetchall() | ||||
|  |             report_sub_lines.append(report_by_order_details) | ||||
|  |         elif data.get('report_type') == 'report_by_product': | ||||
|  |             query = ''' | ||||
|  |             select l.amount_total,sum(purchase_order_line.product_qty) as qty, | ||||
|  |             purchase_order_line.name as product, | ||||
|  |             purchase_order_line.price_unit,product_product.default_code, | ||||
|  |             product_category.name | ||||
|  |             from purchase_order as l | ||||
|  |             left join purchase_order_line on l.id = | ||||
|  |             purchase_order_line.order_id | ||||
|  |             left join product_product on purchase_order_line.product_id = | ||||
|  |             product_product.id | ||||
|  |             left join product_template on purchase_order_line.product_id = | ||||
|  |             product_template.id | ||||
|  |             left join product_category on product_category.id = | ||||
|  |             product_template.categ_id | ||||
|  |             ''' | ||||
|  |             term = 'Where ' | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += "Where l.date_order >= '%s' " % data.get('date_from') | ||||
|  |                 term = 'AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + "l.date_order <= '%s' " % data.get('date_to') | ||||
|  |             query += "group by l.amount_total,purchase_order_line.name," \ | ||||
|  |                      "purchase_order_line.price_unit," \ | ||||
|  |                      "purchase_order_line.product_id," \ | ||||
|  |                      "product_product.default_code," \ | ||||
|  |                      "product_template.categ_id,product_category.name" | ||||
|  |             self._cr.execute(query) | ||||
|  |             report_by_product = self._cr.dictfetchall() | ||||
|  |             report_sub_lines.append(report_by_product) | ||||
|  |         elif data.get('report_type') == 'report_by_categories': | ||||
|  |             query = ''' | ||||
|  |             select product_category.name,sum(l.product_qty) as qty, | ||||
|  |             sum(l.price_subtotal) as amount_total | ||||
|  |             from purchase_order_line as l | ||||
|  |             left join product_template on l.product_id = product_template.id | ||||
|  |             left join product_category on product_category.id = | ||||
|  |             product_template.categ_id | ||||
|  |             left join purchase_order on l.order_id = purchase_order.id | ||||
|  |             ''' | ||||
|  |             term = 'Where ' | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += "Where pos_order.date_order >= '%s' " % data.get( | ||||
|  |                     'date_from') | ||||
|  |                 term = 'AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + "pos_order.date_order <= '%s' " % data.get( | ||||
|  |                     'date_to') | ||||
|  |             query += "group by product_category.name" | ||||
|  |             self._cr.execute(query) | ||||
|  |             report_by_categories = self._cr.dictfetchall() | ||||
|  |             report_sub_lines.append(report_by_categories) | ||||
|  |         elif data.get('report_type') == 'report_by_purchase_representative': | ||||
|  |             query = ''' | ||||
|  |             select res_partner.name,sum(purchase_order_line.product_qty) as | ||||
|  |             qty,sum(purchase_order_line.price_subtotal) as amount,count(l.id) | ||||
|  |             as order from purchase_order as l | ||||
|  |             left join res_users on l.user_id = res_users.id | ||||
|  |             left join res_partner on res_users.partner_id = res_partner.id | ||||
|  |             left join purchase_order_line on l.id = | ||||
|  |             purchase_order_line.order_id | ||||
|  |             ''' | ||||
|  |             term = 'Where ' | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += "Where l.date_order >= '%s' " % data.get('date_from') | ||||
|  |                 term = 'AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + "l.date_order <= '%s' " % data.get('date_to') | ||||
|  |             query += "group by res_partner.name" | ||||
|  |             self._cr.execute(query) | ||||
|  |             report_by_purchase_representative = self._cr.dictfetchall() | ||||
|  |             report_sub_lines.append(report_by_purchase_representative) | ||||
|  |         elif data.get('report_type') == 'report_by_state': | ||||
|  |             query = ''' | ||||
|  |             select l.state,sum(purchase_order_line.product_qty) as | ||||
|  |             qty,sum(purchase_order_line.price_subtotal) as amount,count(l.id) | ||||
|  |             as order from purchase_order as l | ||||
|  |             left join res_users on l.user_id = res_users.id | ||||
|  |             left join res_partner on res_users.partner_id = res_partner.id | ||||
|  |             left join purchase_order_line on l.id = | ||||
|  |             purchase_order_line.order_id | ||||
|  |             ''' | ||||
|  |             term = 'Where ' | ||||
|  |             if data.get('date_from'): | ||||
|  |                 query += "Where so.date_order >= '%s' " % data.get('date_from') | ||||
|  |                 term = 'AND ' | ||||
|  |             if data.get('date_to'): | ||||
|  |                 query += term + "so.date_order <= '%s' " % data.get('date_to') | ||||
|  |             query += "group by l.state" | ||||
|  |             self._cr.execute(query) | ||||
|  |             report_by_state = self._cr.dictfetchall() | ||||
|  |             report_sub_lines.append(report_by_state) | ||||
|  |         pattern = r'<[^>]*>' | ||||
|  |         for rec in report_sub_lines[0]: | ||||
|  |             if rec.get('notes'): | ||||
|  |                 rec['notes'] = re.sub(pattern, ' ', rec['notes']) | ||||
|  |         return report_sub_lines | ||||
|  | 
 | ||||
|  |     def _get_report_values(self, data): | ||||
|  |         """Get data for the specified type of report lines.""" | ||||
|  |         docs = data['model'] | ||||
|  |         date_from = data.get('date_from') | ||||
|  |         date_to = data.get('date_to') | ||||
|  |         if data['report_type'] == 'report_by_order_detail': | ||||
|  |             report = ['Report By Order Detail'] | ||||
|  |         elif data['report_type'] == 'report_by_product': | ||||
|  |             report = ['Report By Product'] | ||||
|  |         elif data['report_type'] == 'report_by_categories': | ||||
|  |             report = ['Report By Categories'] | ||||
|  |         elif data['report_type'] == 'report_by_purchase_representative': | ||||
|  |             report = ['Report By Purchase Representative'] | ||||
|  |         elif data['report_type'] == 'report_by_state': | ||||
|  |             report = ['Report By State'] | ||||
|  |         else: | ||||
|  |             report = ['Report By Order'] | ||||
|  |         if data.get('report_type'): | ||||
|  |             report_res = \ | ||||
|  |                 self._get_report_sub_lines(data, report, date_from, date_to)[0] | ||||
|  |         else: | ||||
|  |             report_res = self._get_report_sub_lines(data, report, date_from, | ||||
|  |                                                     date_to) | ||||
|  |         return { | ||||
|  |             'doc_ids': self.ids, | ||||
|  |             'docs': docs, | ||||
|  |             'PURCHASE': report_res, | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     def get_purchase_xlsx_report(self, data, response, report_data, dfr_data): | ||||
|  |         """Generate an XLSX report with purchase data based on provided | ||||
|  |          filters.""" | ||||
|  |         report_data_main = json.loads(report_data) | ||||
|  |         output = io.BytesIO() | ||||
|  |         filters = json.loads(data) | ||||
|  |         workbook = xlsxwriter.Workbook(output, {'in_memory': True}) | ||||
|  |         sheet = workbook.add_worksheet() | ||||
|  |         head = workbook.add_format({'align': 'center', 'bold': True, | ||||
|  |                                     'font_size': '20px'}) | ||||
|  |         heading = workbook.add_format( | ||||
|  |             {'align': 'center', 'bold': True, 'font_size': '10px', | ||||
|  |              'border': 2, | ||||
|  |              'border_color': 'black'}) | ||||
|  |         txt_l = workbook.add_format( | ||||
|  |             {'font_size': '10px', 'border': 1, 'bold': True}) | ||||
|  |         sheet.merge_range('A2:H3', 'Purchase Report', head) | ||||
|  |         if filters.get('report_type') == 'report_by_order': | ||||
|  |             sheet.merge_range('B5:D5', 'Report Type: ' + | ||||
|  |                               filters.get('report_type'), txt_l) | ||||
|  |             sheet.write('A7', 'Order', heading) | ||||
|  |             sheet.write('B7', 'Date Order', heading) | ||||
|  |             sheet.write('C7', 'Customer', heading) | ||||
|  |             sheet.write('D7', 'Purchase Representative', heading) | ||||
|  |             sheet.write('E7', 'Total Qty', heading) | ||||
|  |             sheet.write('F7', 'Amount Total', heading) | ||||
|  |             if report_data_main: | ||||
|  |                 row = 6 | ||||
|  |                 col = 0 | ||||
|  |                 sheet.set_column('A:A', 20) | ||||
|  |                 sheet.set_column('B:B', 20) | ||||
|  |                 sheet.set_column('C:C', 20) | ||||
|  |                 sheet.set_column('D:D', 22) | ||||
|  |                 sheet.set_column('E:E', 10) | ||||
|  |                 sheet.set_column('F:F', 15) | ||||
|  |                 for rec_data in report_data_main: | ||||
|  |                     row += 1 | ||||
|  |                     sheet.write(row, col, rec_data['name'], txt_l) | ||||
|  |                     sheet.write(row, col + 1, rec_data['date_order'], txt_l) | ||||
|  |                     sheet.write(row, col + 2, rec_data['partner'], txt_l) | ||||
|  |                     sheet.write(row, col + 3, rec_data['salesman'], txt_l) | ||||
|  |                     sheet.write(row, col + 4, rec_data['sum'], txt_l) | ||||
|  |                     sheet.write(row, col + 5, rec_data['amount_total'], txt_l) | ||||
|  |         if filters.get('report_type') == 'report_by_order_detail': | ||||
|  |             sheet.merge_range('B5:D5', 'Report Type: ' + | ||||
|  |                               filters.get('report_type'), txt_l) | ||||
|  |             sheet.write('A7', 'Order', heading) | ||||
|  |             sheet.write('B7', 'Date Order', heading) | ||||
|  |             sheet.write('C7', 'Customer', heading) | ||||
|  |             sheet.write('D7', 'Purchase Representative', heading) | ||||
|  |             sheet.write('E7', 'Product Code', heading) | ||||
|  |             sheet.write('F7', 'Product Name', heading) | ||||
|  |             sheet.write('G7', 'Price unit', heading) | ||||
|  |             sheet.write('H7', 'Qty', heading) | ||||
|  |             sheet.write('I7', 'Price Total', heading) | ||||
|  |             if report_data_main: | ||||
|  |                 row = 6 | ||||
|  |                 col = 0 | ||||
|  |                 sheet.set_column('A:A', 20) | ||||
|  |                 sheet.set_column('B:B', 20) | ||||
|  |                 sheet.set_column('C:C', 20) | ||||
|  |                 sheet.set_column('D:D', 22) | ||||
|  |                 sheet.set_column('E:E', 20) | ||||
|  |                 sheet.set_column('F:F', 35) | ||||
|  |                 sheet.set_column('G:G', 15) | ||||
|  |                 sheet.set_column('H:H', 15) | ||||
|  |                 sheet.set_column('I:I', 15) | ||||
|  |                 for rec_data in report_data_main: | ||||
|  |                     row += 1 | ||||
|  |                     sheet.write(row, col, rec_data['name'], txt_l) | ||||
|  |                     sheet.write(row, col + 1, rec_data['date_order'], txt_l) | ||||
|  |                     sheet.write(row, col + 2, rec_data['partner'], txt_l) | ||||
|  |                     sheet.write(row, col + 3, rec_data['salesman'], txt_l) | ||||
|  |                     sheet.write(row, col + 4, rec_data['default_code'], txt_l) | ||||
|  |                     sheet.write(row, col + 5, rec_data['product'], txt_l) | ||||
|  |                     sheet.write(row, col + 6, rec_data['price_unit'], txt_l) | ||||
|  |                     sheet.write(row, col + 7, rec_data['sum'], txt_l) | ||||
|  |                     sheet.write(row, col + 8, rec_data['amount_total'], txt_l) | ||||
|  |         if filters.get('report_type') == 'report_by_product': | ||||
|  |             sheet.merge_range('B5:D5', 'Report Type: ' + | ||||
|  |                               filters.get('report_type'), txt_l) | ||||
|  |             sheet.write('A7', 'Category', heading) | ||||
|  |             sheet.write('B7', 'Product Code', heading) | ||||
|  |             sheet.write('C7', 'Product Name', heading) | ||||
|  |             sheet.write('D7', 'Qty', heading) | ||||
|  |             sheet.write('E7', 'Amount Total', heading) | ||||
|  |             if report_data_main: | ||||
|  |                 row = 6 | ||||
|  |                 col = 0 | ||||
|  |                 sheet.set_column('A:A', 20) | ||||
|  |                 sheet.set_column('B:B', 20) | ||||
|  |                 sheet.set_column('C:C', 35) | ||||
|  |                 sheet.set_column('D:D', 15) | ||||
|  |                 sheet.set_column('E:E', 15) | ||||
|  |                 for rec_data in report_data_main: | ||||
|  |                     row += 1 | ||||
|  |                     sheet.write(row, col, rec_data['name'], txt_l) | ||||
|  |                     sheet.write(row, col + 1, rec_data['default_code'], txt_l) | ||||
|  |                     sheet.write(row, col + 2, rec_data['product'], txt_l) | ||||
|  |                     sheet.write(row, col + 3, rec_data['qty'], txt_l) | ||||
|  |                     sheet.write(row, col + 4, rec_data['amount_total'], txt_l) | ||||
|  |         if filters.get('report_type') == 'report_by_categories': | ||||
|  |             sheet.merge_range('B5:D5', 'Report Type: ' + | ||||
|  |                               filters.get('report_type'), txt_l) | ||||
|  |             sheet.write('B7', 'Category', heading) | ||||
|  |             sheet.write('C7', 'Qty', heading) | ||||
|  |             sheet.write('D7', 'Amount Total', heading) | ||||
|  |             if report_data_main: | ||||
|  |                 row = 6 | ||||
|  |                 col = 1 | ||||
|  |                 sheet.set_column('B:B', 25) | ||||
|  |                 sheet.set_column('C:C', 15) | ||||
|  |                 sheet.set_column('D:D', 15) | ||||
|  |                 for rec_data in report_data_main: | ||||
|  |                     row += 1 | ||||
|  |                     sheet.write(row, col, rec_data['name'], txt_l) | ||||
|  |                     sheet.write(row, col + 1, rec_data['qty'], txt_l) | ||||
|  |                     sheet.write(row, col + 2, rec_data['amount_total'], txt_l) | ||||
|  |         if filters.get('report_type') == 'report_by_purchase_representative': | ||||
|  |             sheet.merge_range('B5:D5', 'Report Type: ' + | ||||
|  |                               filters.get('report_type'), txt_l) | ||||
|  |             sheet.write('A7', 'Purchase Representative', heading) | ||||
|  |             sheet.write('B7', 'Total Order', heading) | ||||
|  |             sheet.write('C7', 'Total Qty', heading) | ||||
|  |             sheet.write('D7', 'Total Amount', heading) | ||||
|  |             if report_data_main: | ||||
|  |                 row = 6 | ||||
|  |                 col = 0 | ||||
|  |                 sheet.set_column('A:A', 25) | ||||
|  |                 sheet.set_column(4, 1, 15) | ||||
|  |                 sheet.set_column(5, 2, 15) | ||||
|  |                 sheet.set_column(6, 3, 15) | ||||
|  |                 for rec_data in report_data_main: | ||||
|  |                     row += 1 | ||||
|  |                     sheet.write(row, col, rec_data['name'], txt_l) | ||||
|  |                     sheet.write(row, col + 1, rec_data['order'], txt_l) | ||||
|  |                     sheet.write(row, col + 2, rec_data['qty'], txt_l) | ||||
|  |                     sheet.write(row, col + 3, rec_data['amount'], txt_l) | ||||
|  |         if filters.get('report_type') == 'report_by_state': | ||||
|  |             sheet.merge_range('B5:D5', 'Report Type: ' + | ||||
|  |                               filters.get('report_type'), txt_l) | ||||
|  |             sheet.write('A7', 'State', heading) | ||||
|  |             sheet.write('B7', 'Total Count', heading) | ||||
|  |             sheet.write('C7', 'Quantity', heading) | ||||
|  |             sheet.write('D7', 'Amount', heading) | ||||
|  |             if report_data_main: | ||||
|  |                 row = 6 | ||||
|  |                 col = 0 | ||||
|  |                 sheet.set_column('A:A', 20) | ||||
|  |                 sheet.set_column(4, 1, 15) | ||||
|  |                 sheet.set_column(5, 2, 15) | ||||
|  |                 sheet.set_column(6, 3, 15) | ||||
|  |                 for rec_data in report_data_main: | ||||
|  |                     row += 1 | ||||
|  |                     if rec_data['state'] == 'draft': | ||||
|  |                         sheet.write(row, col, 'Quotation', txt_l) | ||||
|  |                     elif rec_data['state'] == 'sent': | ||||
|  |                         sheet.write(row, col, 'Quotation Sent', txt_l) | ||||
|  |                     elif rec_data['state'] == 'purchase': | ||||
|  |                         sheet.write(row, col, 'Purchase Order', txt_l) | ||||
|  |                     sheet.write(row, col + 1, rec_data['order'], txt_l) | ||||
|  |                     sheet.write(row, col + 2, rec_data['qty'], txt_l) | ||||
|  |                     sheet.write(row, col + 3, rec_data['amount'], txt_l) | ||||
|  |         workbook.close() | ||||
|  |         output.seek(0) | ||||
|  |         response.stream.write(output.read()) | ||||
|  |         output.close() | ||||
| @ -0,0 +1,260 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import api, fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class EmployeePurchaseRequisition(models.Model): | ||||
|  |     """ Model for storing purchase requisition """ | ||||
|  |     _name = 'employee.purchase.requisition' | ||||
|  |     _description = 'Purchase Requisition' | ||||
|  |     _inherit = "mail.thread", "mail.activity.mixin" | ||||
|  | 
 | ||||
|  |     name = fields.Char( | ||||
|  |         string="Reference No", help="Reference Number", readonly=True | ||||
|  |     ) | ||||
|  |     employee_id = fields.Many2one( | ||||
|  |         'hr.employee', string='Employee', required=True, | ||||
|  |         help='Choose the employee' | ||||
|  |     ) | ||||
|  |     dept_id = fields.Many2one( | ||||
|  |         'hr.department', related='employee_id.department_id', store=True, | ||||
|  |         help='Choose Department', string='Department' | ||||
|  |     ) | ||||
|  |     user_id = fields.Many2one( | ||||
|  |         'res.users', string='Requisition Responsible', required=True, | ||||
|  |         help='Requisition responsible user' | ||||
|  |     ) | ||||
|  |     requisition_date = fields.Date( | ||||
|  |         string="Requisition Date", default=lambda self: fields.Date.today(), | ||||
|  |         help='Date of Requisition' | ||||
|  |     ) | ||||
|  |     receive_date = fields.Date( | ||||
|  |         string="Received Date", readonly=True, help='Receive Date' | ||||
|  |     ) | ||||
|  |     requisition_deadline = fields.Date( | ||||
|  |         string="Requisition Deadline", help="End date of Purchase requisition" | ||||
|  |     ) | ||||
|  |     company_id = fields.Many2one( | ||||
|  |         'res.company', string='Company', default=lambda self: self.env.company, | ||||
|  |         help='Select the company' | ||||
|  |     ) | ||||
|  |     requisition_order_ids = fields.One2many( | ||||
|  |         'requisition.order', 'requisition_product_id', required=True, | ||||
|  |         string="Requisition Order", help="Requisition order") | ||||
|  |     confirm_id = fields.Many2one( | ||||
|  |         'res.users', string='Confirmed By', default=lambda self: self.env.uid, | ||||
|  |         readonly=True, help='User who Confirmed the requisition.' | ||||
|  |     ) | ||||
|  |     manager_id = fields.Many2one( | ||||
|  |         'res.users', string='Department Manager', readonly=True, | ||||
|  |         help='Department Manager' | ||||
|  |     ) | ||||
|  |     requisition_head_id = fields.Many2one( | ||||
|  |         'res.users', string='Approved By', readonly=True, | ||||
|  |         help='User who approved the requisition.' | ||||
|  |     ) | ||||
|  |     rejected_user_id = fields.Many2one( | ||||
|  |         'res.users', string='Rejected By', readonly=True, | ||||
|  |         help='user who rejected the requisition' | ||||
|  |     ) | ||||
|  |     confirmed_date = fields.Date( | ||||
|  |         string='Confirmed Date', readonly=True, | ||||
|  |         help='Date of Requisition Confirmation' | ||||
|  |     ) | ||||
|  |     department_approval_date = fields.Date( | ||||
|  |         string='Department Approval Date', readonly=True, | ||||
|  |         help='Department Approval Date' | ||||
|  |     ) | ||||
|  |     approval_date = fields.Date( | ||||
|  |         string='Approved Date', readonly=True, help='Requisition Approval Date' | ||||
|  |     ) | ||||
|  |     reject_date = fields.Date( | ||||
|  |         string='Rejection Date', readonly=True, | ||||
|  |         help='Requisition Rejected Date' | ||||
|  |     ) | ||||
|  |     source_location_id = fields.Many2one( | ||||
|  |         'stock.location', string='Source Location', | ||||
|  |         help='Source location of requisition.' | ||||
|  |     ) | ||||
|  |     destination_location_id = fields.Many2one( | ||||
|  |         'stock.location', string="Destination Location", | ||||
|  |         help='Destination location of requisition.' | ||||
|  |     ) | ||||
|  |     delivery_type_id = fields.Many2one( | ||||
|  |         'stock.picking.type', string='Delivery To', help='Type of Delivery.' | ||||
|  |     ) | ||||
|  |     internal_picking_id = fields.Many2one( | ||||
|  |         'stock.picking.type', string="Internal Picking", | ||||
|  |         help="Choose picking type" | ||||
|  |     ) | ||||
|  |     requisition_description = fields.Text( | ||||
|  |         string="Reason For Requisition", help="Write description" | ||||
|  |     ) | ||||
|  |     purchase_count = fields.Integer( | ||||
|  |         string='Purchase Count', help="Count of purchase order" | ||||
|  |     ) | ||||
|  |     internal_transfer_count = fields.Integer( | ||||
|  |         string='Internal Transfer count', help="Internal transfer count" | ||||
|  |     ) | ||||
|  |     state = fields.Selection( | ||||
|  |         [('new', 'New'), | ||||
|  |          ('waiting_department_approval', 'Waiting Department Approval'), | ||||
|  |          ('waiting_head_approval', 'Waiting Head Approval'), | ||||
|  |          ('approved', 'Approved'), | ||||
|  |          ('purchase_order_created', 'Purchase Order Created'), | ||||
|  |          ('received', 'Received'), | ||||
|  |          ('cancelled', 'Cancelled')], string="State", default='new', | ||||
|  |         copy=False, tracking=True, help="State of the record" | ||||
|  |     ) | ||||
|  |     is_has_internal = fields.Boolean(string='Has Internal Transfer', | ||||
|  |                                      help="Will become true if this purchase " | ||||
|  |                                           "requisition has internal transfer", | ||||
|  |                                      compute="_compute_is_has_internal") | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def create(self, vals): | ||||
|  |         """Generate purchase requisition sequence""" | ||||
|  |         if vals.get('name', 'New') == 'New': | ||||
|  |             vals['name'] = self.env['ir.sequence'].next_by_code( | ||||
|  |                 'employee.purchase.requisition') or 'New' | ||||
|  |         return super(EmployeePurchaseRequisition, self).create(vals) | ||||
|  | 
 | ||||
|  |     @api.depends('requisition_order_ids') | ||||
|  |     def _compute_is_has_internal(self): | ||||
|  |         """Method to compute whether there is any internal transfer in the | ||||
|  |         purchase requisition""" | ||||
|  |         for rec in self: | ||||
|  |             has_internal_transfer = False | ||||
|  |             for order in rec.requisition_order_ids: | ||||
|  |                 if order.requisition_type == 'internal_transfer': | ||||
|  |                     has_internal_transfer = True | ||||
|  |                     break | ||||
|  |             if has_internal_transfer: | ||||
|  |                 rec.is_has_internal = True | ||||
|  |             else: | ||||
|  |                 rec.is_has_internal = False | ||||
|  | 
 | ||||
|  |     def action_confirm_requisition(self): | ||||
|  |         """Confirm purchase requisition""" | ||||
|  |         self.source_location_id = self.employee_id.department_id.department_location_id.id | ||||
|  |         self.destination_location_id = self.employee_id.employee_location_id.id | ||||
|  |         self.delivery_type_id = self.source_location_id.warehouse_id.in_type_id.id | ||||
|  |         self.internal_picking_id = self.source_location_id.warehouse_id.int_type_id.id | ||||
|  |         self.write({'state': 'waiting_department_approval'}) | ||||
|  |         self.confirm_id = self.env.uid | ||||
|  |         self.confirmed_date = fields.Date.today() | ||||
|  | 
 | ||||
|  |     def action_department_approval(self): | ||||
|  |         """Approval from the department""" | ||||
|  |         self.write({'state': 'waiting_head_approval'}) | ||||
|  |         self.manager_id = self.env.uid | ||||
|  |         self.department_approval_date = fields.Date.today() | ||||
|  | 
 | ||||
|  |     def action_department_cancel(self): | ||||
|  |         """Cancellation from department """ | ||||
|  |         self.write({'state': 'cancelled'}) | ||||
|  |         self.rejected_user_id = self.env.uid | ||||
|  |         self.reject_date = fields.Date.today() | ||||
|  | 
 | ||||
|  |     def action_head_approval(self): | ||||
|  |         """Approval from department head""" | ||||
|  |         self.write({'state': 'approved'}) | ||||
|  |         self.requisition_head_id = self.env.uid | ||||
|  |         self.approval_date = fields.Date.today() | ||||
|  | 
 | ||||
|  |     def action_head_cancel(self): | ||||
|  |         """Cancellation from department head""" | ||||
|  |         self.write({'state': 'cancelled'}) | ||||
|  |         self.rejected_user_id = self.env.uid | ||||
|  |         self.reject_date = fields.Date.today() | ||||
|  | 
 | ||||
|  |     def action_create_purchase_order(self): | ||||
|  |         """Create purchase order and internal transfer""" | ||||
|  |         for rec in self.requisition_order_ids: | ||||
|  |             if rec.requisition_type == 'internal_transfer': | ||||
|  |                 self.env['stock.picking'].create({ | ||||
|  |                     'location_id': self.source_location_id.id, | ||||
|  |                     'location_dest_id': self.destination_location_id.id, | ||||
|  |                     'picking_type_id': self.internal_picking_id.id, | ||||
|  |                     'requisition_order': self.name, | ||||
|  |                     'move_ids_without_package': [(0, 0, { | ||||
|  |                         'name': rec.product_id.name, | ||||
|  |                         'product_id': rec.product_id.id, | ||||
|  |                         'product_uom': rec.product_id.uom_id, | ||||
|  |                         'product_uom_qty': rec.quantity, | ||||
|  |                         'location_id': self.source_location_id.id, | ||||
|  |                         'location_dest_id': self.destination_location_id.id, | ||||
|  |                     })] | ||||
|  |                 }) | ||||
|  |             else: | ||||
|  |                 self.env['purchase.order'].create({ | ||||
|  |                     'partner_id': self.employee_id.user_partner_id.id, | ||||
|  |                     'requisition_order': self.name, | ||||
|  |                     "order_line": [(0, 0, { | ||||
|  |                         'product_id': rec.product_id.id, | ||||
|  |                         'product_qty': rec.quantity, | ||||
|  |                     })]}) | ||||
|  |         self.write({'state': 'purchase_order_created'}) | ||||
|  |         self.purchase_count = self.env['purchase.order'].search_count([ | ||||
|  |             ('requisition_order', '=', self.name)]) | ||||
|  |         self.internal_transfer_count = self.env['stock.picking'].search_count([ | ||||
|  |             ('requisition_order', '=', self.name)]) | ||||
|  | 
 | ||||
|  |     def action_receive(self): | ||||
|  |         """Receive purchase requisition""" | ||||
|  |         self.write({'state': 'received'}) | ||||
|  |         self.receive_date = fields.Date.today() | ||||
|  | 
 | ||||
|  |     def get_purchase_order(self): | ||||
|  |         """Purchase order smart button, when click on the smart button it | ||||
|  |          gives the purchase order of the user""" | ||||
|  |         self.ensure_one() | ||||
|  |         return { | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |             'name': 'Purchase Order', | ||||
|  |             'view_mode': 'tree,form', | ||||
|  |             'res_model': 'purchase.order', | ||||
|  |             'domain': [('requisition_order', '=', self.name)], | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     def get_internal_transfer(self): | ||||
|  |         """Internal transfer smart button, when click on the smart button it | ||||
|  |          gives the internal transfer of the user""" | ||||
|  |         self.ensure_one() | ||||
|  |         return { | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |             'name': 'Internal Transfers', | ||||
|  |             'view_mode': 'tree,form', | ||||
|  |             'res_model': 'stock.picking', | ||||
|  |             'domain': [('requisition_order', '=', self.name)], | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     def action_print_report(self): | ||||
|  |         """Print purchase requisition report""" | ||||
|  |         data = { | ||||
|  |             'employee': self.employee_id.name, | ||||
|  |             'records': self.read(), | ||||
|  |             'order_ids': self.requisition_order_ids.read(), | ||||
|  |         } | ||||
|  |         return self.env.ref( | ||||
|  |             'all_in_one_purchase_kit.report_purchase_requisition_action' | ||||
|  |         ).report_action(self, data=data) | ||||
| @ -0,0 +1,32 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class HrDepartment(models.Model): | ||||
|  |     """ Inherit the hr.department model add department location field""" | ||||
|  |     _inherit = 'hr.department' | ||||
|  | 
 | ||||
|  |     department_location_id = fields.Many2one( | ||||
|  |         'stock.location', string='Destination Location', | ||||
|  |         help='Department location' | ||||
|  |     ) | ||||
| @ -0,0 +1,33 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class HrEmployee(models.Model): | ||||
|  |     """ inherit hr.employee model add employee location field""" | ||||
|  | 
 | ||||
|  |     _inherit = 'hr.employee' | ||||
|  | 
 | ||||
|  |     employee_location_id = fields.Many2one( | ||||
|  |         'stock.location', string="Destination Location", | ||||
|  |         help='Employee location' | ||||
|  |     ) | ||||
| @ -0,0 +1,44 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import api, fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ProductBrand(models.Model): | ||||
|  |     """Model to add brand for products""" | ||||
|  |     _name = 'product.brand' | ||||
|  |     _description = 'Product Brand' | ||||
|  | 
 | ||||
|  |     name = fields.Char(string="Name", help="Brand name") | ||||
|  |     brand_image = fields.Binary(string="Brand Logo", help="Brand Logo") | ||||
|  |     product_ids = fields.One2many( | ||||
|  |         'product.template', 'brand_id', string="Product", help="Add product" | ||||
|  |     ) | ||||
|  |     product_count = fields.Char( | ||||
|  |         string='Product Count', compute='_compute_count_products', store=True, | ||||
|  |         help="Count of Products" | ||||
|  |     ) | ||||
|  | 
 | ||||
|  |     @api.depends('product_ids') | ||||
|  |     def _compute_count_products(self): | ||||
|  |         """Methode to get the count of products in brand""" | ||||
|  |         for rec in self: | ||||
|  |             rec.product_count = len(rec.product_ids) | ||||
| @ -0,0 +1,92 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import api, fields, models, _ | ||||
|  | from odoo.exceptions import UserError | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ProductProduct(models.Model): | ||||
|  |     """Inherit model and add fields and methods""" | ||||
|  |     _inherit = "product.product" | ||||
|  | 
 | ||||
|  |     order_partner_id = fields.Many2one( | ||||
|  |         'res.partner', string="Partner", help="Choose partner" | ||||
|  |     ) | ||||
|  | 
 | ||||
|  |     def action_purchase_product_prices(self): | ||||
|  |         """Display the purchase history of a product.""" | ||||
|  |         rel_view_id = self.env.ref( | ||||
|  |             'all_in_one_purchase_kit.last_product_purchase_prices_view') | ||||
|  |         if self.order_partner_id.id: | ||||
|  |             purchase_lines = self.env['purchase.order.line'].search( | ||||
|  |                 [('product_id', '=', self.id), | ||||
|  |                  ('partner_id', '=', self.order_partner_id.id)], | ||||
|  |                 order='create_date DESC').mapped('id') | ||||
|  |         else: | ||||
|  |             purchase_lines = self.env['purchase.order.line'].search( | ||||
|  |                 [('product_id', '=', self.id)], | ||||
|  |                 order='create_date DESC').mapped('id') | ||||
|  |         if not purchase_lines: | ||||
|  |             raise UserError("No purchase history found.!") | ||||
|  |         return { | ||||
|  |             'domain': [('id', 'in', purchase_lines)], | ||||
|  |             'views': [(rel_view_id.id, 'tree')], | ||||
|  |             'name': 'Purchase History', | ||||
|  |             'res_model': 'purchase.order.line', | ||||
|  |             'view_id': False, | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def most_purchased_product(self): | ||||
|  |         """Method returns most purchased products""" | ||||
|  |         purchased_qty = self.search_read([], ['name', 'purchased_product_qty']) | ||||
|  |         product_qty = {count['name']: count['purchased_product_qty'] for count | ||||
|  |                        in purchased_qty if count['purchased_product_qty'] > 0} | ||||
|  |         sorted_qty = {key: val for key, val in sorted( | ||||
|  |             product_qty.items(), key=lambda ele: ele[1], reverse=True) | ||||
|  |                       } | ||||
|  |         return {'purchased_qty': sorted_qty} | ||||
|  | 
 | ||||
|  |     def add_to_rfq(self): | ||||
|  |         """When click on add to RFQ button product added to RFQ""" | ||||
|  |         order_id = self.env.context.get('order_id') | ||||
|  |         sale_order_id = self.env['purchase.order.line'].search( | ||||
|  |             [('order_id', '=', order_id)]) | ||||
|  |         lst = [rec.product_id for rec in sale_order_id] | ||||
|  |         if self in lst: | ||||
|  |             order_line_id = self.env['purchase.order.line'].search( | ||||
|  |                 [('order_id', '=', order_id), ('product_id', '=', self.id)]) | ||||
|  |             order_line_id.product_uom_qty += 1 | ||||
|  |         else: | ||||
|  |             self.env['purchase.order.line'].create({ | ||||
|  |                 'product_id': self.id, | ||||
|  |                 'order_id': order_id, | ||||
|  |             }) | ||||
|  |         return { | ||||
|  |             'type': 'ir.actions.client', | ||||
|  |             'tag': 'display_notification', | ||||
|  |             'params': { | ||||
|  |                 'type': 'success', | ||||
|  |                 'title': _("Added"), | ||||
|  |                 'message': "Product Added to RFQ" | ||||
|  |             } | ||||
|  |         } | ||||
| @ -0,0 +1,42 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import api, fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ProductSupplierInfo(models.Model): | ||||
|  |     """Inherit the model to add fields and methods""" | ||||
|  |     _inherit = "product.supplierinfo" | ||||
|  | 
 | ||||
|  |     discount = fields.Float(string="Discount (%)", help="Discount in %") | ||||
|  |     _sql_constraints = [ | ||||
|  |         ( | ||||
|  |             "maximum_discount", | ||||
|  |             "CHECK (discount <= 100.0)", | ||||
|  |             "Discount must be lower than 100%.", | ||||
|  |         ) | ||||
|  |     ] | ||||
|  | 
 | ||||
|  |     @api.onchange("partner_id") | ||||
|  |     def _onchange_discount(self): | ||||
|  |         """Add default discount to order line""" | ||||
|  |         for supplier in self.filtered("partner_id"): | ||||
|  |             supplier.write({'discount': supplier.partner_id.discount}) | ||||
| @ -0,0 +1,31 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ProductTemplate(models.Model): | ||||
|  |     """Add brand field in product.template""" | ||||
|  |     _inherit = 'product.template' | ||||
|  | 
 | ||||
|  |     brand_id = fields.Many2one( | ||||
|  |         'product.brand', string='Brand', help="Choose brand" | ||||
|  |     ) | ||||
| @ -0,0 +1,278 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | import datetime | ||||
|  | import calendar | ||||
|  | from odoo import api, fields, models, _ | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class PurchaseOrder(models.Model): | ||||
|  |     """ Inherit purchase.order model and add fields and methods """ | ||||
|  |     _inherit = 'purchase.order' | ||||
|  | 
 | ||||
|  |     requisition_order = fields.Char( | ||||
|  |         string='Requisition Order', help='Requisition Order' | ||||
|  |     ) | ||||
|  |     company_currency_amount = fields.Float( | ||||
|  |         string='Company Currency Total', compute='_compute_amount', | ||||
|  |         help="Total amount in company currency" | ||||
|  |     ) | ||||
|  |     number_to_words = fields.Char( | ||||
|  |         string="Amount in Words (Total) : ", | ||||
|  |         compute='_compute_number_to_words', help="Total amount in words" | ||||
|  |     ) | ||||
|  | 
 | ||||
|  |     def add_catalog_control(self): | ||||
|  |         """Method to call product.product model when click on catalog | ||||
|  |         button in purchase order line""" | ||||
|  |         return { | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |             'name': _('Products'), | ||||
|  |             'context': { | ||||
|  |                 'tree_view_ref': 'all_in_one_purchase_kit.product_product_view_tree', | ||||
|  |                 'form_view_ref': 'all_in_one_purchase_kit.product_template_form_view', | ||||
|  |                 'kanban_view_ref': 'all_in_one_purchase_kit.product_product_view_kanban', | ||||
|  |                 'order_id': self.id}, | ||||
|  |             'res_model': 'product.product', | ||||
|  |             'view_mode': 'kanban,tree,form', | ||||
|  |             'target': 'current', | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     def _compute_amount(self): | ||||
|  |         """Total amount in company currency""" | ||||
|  |         for amount in self: | ||||
|  |             amount.company_currency_amount = self.env['res.currency']._compute( | ||||
|  |                 amount.currency_id, amount.company_id.currency_id, | ||||
|  |                 amount.amount_total) | ||||
|  | 
 | ||||
|  |     def _compute_number_to_words(self): | ||||
|  |         """Compute the amount to words in Purchase Order""" | ||||
|  |         for rec in self: | ||||
|  |             rec.number_to_words = rec.currency_id.amount_to_text( | ||||
|  |                 rec.amount_total) | ||||
|  | 
 | ||||
|  |     def action_multi_confirm(self): | ||||
|  |         """Confirm multiple order by a single click""" | ||||
|  |         for order in self.env['purchase.order'].browse( | ||||
|  |                 self.env.context.get('active_ids')).filtered( | ||||
|  |             lambda o: o.state in ['draft', 'sent']): | ||||
|  |             order.button_confirm() | ||||
|  | 
 | ||||
|  |     def action_multi_cancel(self): | ||||
|  |         """Cancel multiple order by a single click""" | ||||
|  |         for order in self.env['purchase.order'].browse( | ||||
|  |                 self.env.context.get('active_ids')): | ||||
|  |             order.button_cancel() | ||||
|  | 
 | ||||
|  |     def button_confirm(self): | ||||
|  |         """The same order line merges when the confirmation button is | ||||
|  |          clicked""" | ||||
|  |         line_groups = {} | ||||
|  |         for line in self.order_line: | ||||
|  |             key = (line.product_id.id, line.price_unit) | ||||
|  |             line_groups.setdefault(key, []).append(line) | ||||
|  |         for lines in line_groups.values(): | ||||
|  |             if len(lines) > 1: | ||||
|  |                 lines[0].product_qty = sum(line.product_qty for line in lines) | ||||
|  |                 lines[0]._compute_amount() | ||||
|  |                 for line in lines[1:]: | ||||
|  |                     line.unlink() | ||||
|  |         res = super(PurchaseOrder, self).button_confirm() | ||||
|  |         return res | ||||
|  | 
 | ||||
|  |     @api.onchange('partner_id') | ||||
|  |     def _recompute_discount(self): | ||||
|  |         """Calculate the discount""" | ||||
|  |         self.order_line.calculate_discount_percentage() | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_data(self): | ||||
|  |         """Get various counts and total amounts related to different states | ||||
|  |          of purchase-related records.""" | ||||
|  |         return { | ||||
|  |             'rfq': self.search_count([('state', '=', 'draft')]), | ||||
|  |             'rfq_sent': self.search_count([('state', '=', 'sent')]), | ||||
|  |             'rfq_to_approve': self.search_count([('state', '=', 'to approve')]), | ||||
|  |             'purchase_order': self.search_count([('state', '=', 'purchase')]), | ||||
|  |             'cancelled_order': self.search_count([('state', '=', 'cancel')]), | ||||
|  |             'amount_total': sum(self.search([ | ||||
|  |                 ('state', '=', 'purchase')]).mapped('amount_total')), | ||||
|  |             'amount_rfq': sum(self.search([ | ||||
|  |                 ('state', '=', 'draft')]).mapped('amount_total')), | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_value(self, start_date, end_date): | ||||
|  |         """It is to pass values according to start and end date to the | ||||
|  |         dashboard.""" | ||||
|  |         if start_date and end_date: | ||||
|  |             rfq = self.search_count( | ||||
|  |                 [('state', '=', 'draft'), ('date_order', '>=', start_date), | ||||
|  |                  ('date_order', '<=', end_date)]) | ||||
|  |             rfq_sent = self.search_count( | ||||
|  |                 [('state', '=', 'sent'), ('date_order', '>=', start_date), | ||||
|  |                  ('date_order', '<=', end_date)]) | ||||
|  |             rfq_to_approve = self.search_count( | ||||
|  |                 [('state', '=', 'to approve'), | ||||
|  |                  ('date_order', '>=', start_date), | ||||
|  |                  ('date_order', '<=', end_date)]) | ||||
|  |             purchase_order = self.search_count( | ||||
|  |                 [('state', '=', 'purchase'), ('date_order', '>=', start_date), | ||||
|  |                  ('date_order', '<=', end_date)]) | ||||
|  |             cancelled_order = self.search_count( | ||||
|  |                 [('state', '=', 'cancel'), ('date_order', '>=', start_date), | ||||
|  |                  ('date_order', '<=', end_date)]) | ||||
|  |             amount_total = sum(self.search([ | ||||
|  |                 ('state', '=', 'purchase'), ('date_order', '>=', start_date), | ||||
|  |                 ('date_order', '<=', end_date)]).mapped('amount_total')) | ||||
|  |             amount_rfq = sum(self.search([ | ||||
|  |                 ('state', '=', 'draft'), ('date_order', '>=', start_date), | ||||
|  |                 ('date_order', '<=', end_date)]).mapped('amount_total')) | ||||
|  |         elif start_date: | ||||
|  |             rfq = self.search_count([('state', '=', 'draft'), | ||||
|  |                                      ('date_order', '>=', start_date)]) | ||||
|  |             rfq_sent = self.search_count([('state', '=', 'sent'), | ||||
|  |                                           ('date_order', '>=', start_date)]) | ||||
|  |             rfq_to_approve = self.search_count( | ||||
|  |                 [('state', '=', 'to approve'), | ||||
|  |                  ('date_order', '>=', start_date), | ||||
|  |                  ]) | ||||
|  |             purchase_order = self.search_count( | ||||
|  |                 [('state', '=', 'purchase'), ('date_order', '>=', start_date)]) | ||||
|  |             cancelled_order = self.search_count( | ||||
|  |                 [('state', '=', 'cancel'), ('date_order', '>=', start_date)]) | ||||
|  |             amount_total = sum(self.search([ | ||||
|  |                 ('state', '=', 'purchase'), ('date_order', '>=', start_date) | ||||
|  |             ]).mapped('amount_total')) | ||||
|  |             amount_rfq = sum(self.search([ | ||||
|  |                 ('state', '=', 'draft'), ('date_order', '>=', start_date) | ||||
|  |             ]).mapped('amount_total')) | ||||
|  |         elif end_date: | ||||
|  |             rfq = self.search_count( | ||||
|  |                 [('state', '=', 'draft'), ('date_order', '<=', end_date)]) | ||||
|  |             rfq_sent = self.search_count( | ||||
|  |                 [('state', '=', 'sent'), | ||||
|  |                  ('date_order', '<=', end_date)]) | ||||
|  |             rfq_to_approve = self.search_count( | ||||
|  |                 [('state', '=', 'to approve'), | ||||
|  |                  ('date_order', '<=', end_date), | ||||
|  |                  ]) | ||||
|  |             purchase_order = self.search_count( | ||||
|  |                 [('state', '=', 'purchase'), ('date_order', '<=', end_date)]) | ||||
|  |             cancelled_order = self.search_count( | ||||
|  |                 [('state', '=', 'cancel'), ('date_order', '<=', end_date)]) | ||||
|  |             amount_total = sum(self.search([ | ||||
|  |                 ('state', '=', 'purchase'), ('date_order', '<=', end_date) | ||||
|  |             ]).mapped('amount_total')) | ||||
|  |             amount_rfq = sum(self.search([ | ||||
|  |                 ('state', '=', 'draft'), ('date_order', '>=', start_date) | ||||
|  |             ]).mapped('amount_total')) | ||||
|  |         return { | ||||
|  |             'rfq': rfq, | ||||
|  |             'rfq_sent': rfq_sent, | ||||
|  |             'rfq_to_approve': rfq_to_approve, | ||||
|  |             'purchase_order': purchase_order, | ||||
|  |             'cancelled_order': cancelled_order, | ||||
|  |             'amount_total': amount_total, | ||||
|  |             'amount_rfq': amount_rfq, | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_current_month_purchase(self): | ||||
|  |         """Returns current month purchase""" | ||||
|  |         date = fields.Datetime.today() | ||||
|  |         start_date = datetime.datetime(date.year, date.month, 1) | ||||
|  |         purchase_order = self.search_count( | ||||
|  |             [('create_date', '<', date), ('create_date', '>', start_date), | ||||
|  |              ('state', '=', 'purchase')] | ||||
|  |         ) | ||||
|  |         current_month_count = { | ||||
|  |             calendar.month_name[date.month]: purchase_order | ||||
|  |         } | ||||
|  |         return { | ||||
|  |             'current_month_count': current_month_count | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_monthly_purchase_order(self): | ||||
|  |         """Returns monthly purchase count data to the graph of dashboard""" | ||||
|  |         monthly_purchase = {} | ||||
|  |         purchase_order = self.search([('state', '=', 'purchase')]) | ||||
|  |         lst = [rec.create_date.month for rec in purchase_order] | ||||
|  |         for i in range(1, 13): | ||||
|  |             count = lst.count(i) | ||||
|  |             monthly_purchase.update({ | ||||
|  |                 calendar.month_name[i]: count | ||||
|  |             }) | ||||
|  |         return { | ||||
|  |             'monthly_purchase_count': monthly_purchase, | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_monthly_order(self): | ||||
|  |         """Returns complete monthly data includes rfq, purchase order, | ||||
|  |         canceled order,to approve order etc. of to the graph of dashboard""" | ||||
|  |         monthly_count = {} | ||||
|  |         purchase_order = self.search([]) | ||||
|  |         lst = [rec.create_date.month for rec in purchase_order] | ||||
|  |         for i in range(1, 13): | ||||
|  |             count = lst.count(i) | ||||
|  |             monthly_count.update({ | ||||
|  |                 calendar.month_name[i]: count | ||||
|  |             }) | ||||
|  |         return { | ||||
|  |             'monthly_count': monthly_count, | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def total_amount_spend(self): | ||||
|  |         """Returns total amount spend for purchase""" | ||||
|  |         total_amount = sum(self.search([ | ||||
|  |             ('state', '=', 'purchase')]).mapped('amount_total')) | ||||
|  |         return { | ||||
|  |             'amount_total': total_amount | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     def recommendation_wizard(self): | ||||
|  |         """Add data to wizard""" | ||||
|  |         orders = self.search([('partner_id', '=', self.partner_id.id)]) | ||||
|  |         pro_id = [] | ||||
|  |         for order in orders: | ||||
|  |             for product in order.order_line.product_id: | ||||
|  |                 val = (0, 0, { | ||||
|  |                     'product_id': product.id, | ||||
|  |                     'available_qty': product.qty_available, | ||||
|  |                     'list_price': product.list_price, | ||||
|  |                     'qty_need': 0, | ||||
|  |                     'is_modified': False, | ||||
|  |                 }) | ||||
|  |                 if val not in pro_id: | ||||
|  |                     pro_id.append(val) | ||||
|  |             res = { | ||||
|  |                 'type': 'ir.actions.act_window', | ||||
|  |                 'view_mode': 'form', | ||||
|  |                 'res_model': 'product.recommendation', | ||||
|  |                 'target': 'new', | ||||
|  |                 'context': { | ||||
|  |                     'default_line_ids': pro_id, | ||||
|  |                 } | ||||
|  |             } | ||||
|  |         return res | ||||
| @ -0,0 +1,132 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import api, fields, models, _ | ||||
|  | from odoo.exceptions import UserError | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class PurchaseOrderLine(models.Model): | ||||
|  |     """Inherit purchase.order.line to add fields and methods""" | ||||
|  |     _inherit = 'purchase.order.line' | ||||
|  | 
 | ||||
|  |     product_image = fields.Binary( | ||||
|  |         related="product_id.image_1920", | ||||
|  |         string="Product Image", | ||||
|  |         help='For getting product image to purchase order line') | ||||
|  |     purchase_date = fields.Datetime( | ||||
|  |         comodel_name='purchase.order', related='order_id.date_order', store=True, | ||||
|  |         string='Purchase Date', help="Purchase Date" | ||||
|  |     ) | ||||
|  |     barcode_scan = fields.Char( | ||||
|  |         string='Product Barcode', | ||||
|  |         help="Here you can provide the barcode for the product") | ||||
|  |     discount = fields.Float( | ||||
|  |         string="Discount (%)", help="Total Discount" | ||||
|  |     ) | ||||
|  |     _sql_constraints = [ | ||||
|  |         ( | ||||
|  |             "maximum_discount", | ||||
|  |             "CHECK (discount <= 100.0)", | ||||
|  |             "Discount must be lower than 100%.", | ||||
|  |         ) | ||||
|  |     ] | ||||
|  | 
 | ||||
|  |     @api.onchange('order_id') | ||||
|  |     def _onchange_order_id(self): | ||||
|  |         """ Restrict creating purchase order line for purchase order | ||||
|  |                 in locked, cancel and purchase order states""" | ||||
|  |         if self.order_id.state in ['cancel', 'done', 'purchase']: | ||||
|  |             raise UserError(_("You cannot select purchase order in " | ||||
|  |                               "cancel or locked or purchase order state")) | ||||
|  | 
 | ||||
|  |     def get_product_form(self): | ||||
|  |         """Get the product form""" | ||||
|  |         self.product_id.order_partner_id = self.order_id.partner_id.id | ||||
|  |         return { | ||||
|  |             'name': self.product_id.name, | ||||
|  |             'view_mode': 'form', | ||||
|  |             'res_model': 'product.product', | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |             'target': 'current', | ||||
|  |             'res_id': self.product_id.id | ||||
|  |         } | ||||
|  | 
 | ||||
|  |     @api.onchange('barcode_scan') | ||||
|  |     def _onchange_barcode_scan(self): | ||||
|  |         """Search the product with the barcode entered""" | ||||
|  |         if self.barcode_scan: | ||||
|  |             product = self.env['product.product'].search([ | ||||
|  |                 ('barcode', '=', self.barcode_scan)]) | ||||
|  |             self.product_id = product.id | ||||
|  | 
 | ||||
|  |     @api.depends("discount") | ||||
|  |     def _compute_amount(self): | ||||
|  |         """Add discount""" | ||||
|  |         return super()._compute_amount() | ||||
|  | 
 | ||||
|  |     def _convert_to_tax_base_line_dict(self): | ||||
|  |         """Update price unit""" | ||||
|  |         vals = super()._convert_to_tax_base_line_dict() | ||||
|  |         vals.update({"price_unit": self._get_discounted_price()}) | ||||
|  |         return vals | ||||
|  | 
 | ||||
|  |     @api.onchange('product_id') | ||||
|  |     def calculate_discount_percentage(self): | ||||
|  |         """Calculate the discount percentage""" | ||||
|  |         vendor = self.order_id.partner_id | ||||
|  |         sellers = self.product_id.product_tmpl_id.seller_ids | ||||
|  |         for rec in sellers: | ||||
|  |             if rec.name.id == vendor.id: | ||||
|  |                 if rec.discount: | ||||
|  |                     self.write({'discount': rec.discount}) | ||||
|  |                     self.update({'price_unit': rec.price}) | ||||
|  |                     break | ||||
|  |             elif rec.name.id != vendor.id: | ||||
|  |                 self.update({'discount': vendor.discount}) | ||||
|  |                 break | ||||
|  |             else: | ||||
|  |                 self.write({'discount': None}) | ||||
|  | 
 | ||||
|  |     @api.depends('discount') | ||||
|  |     def _get_discounted_price(self): | ||||
|  |         """Returns discounted price""" | ||||
|  |         self.ensure_one() | ||||
|  |         if self.discount: | ||||
|  |             return self.price_unit * (1 - self.discount / 100) | ||||
|  |         return self.price_unit | ||||
|  | 
 | ||||
|  |     def _prepare_account_move_line(self, move=False): | ||||
|  |         """Discount in account.move.line""" | ||||
|  |         sup = super(PurchaseOrderLine, self)._prepare_account_move_line(move) | ||||
|  |         sup.update({'discount': self.discount}) | ||||
|  |         return sup | ||||
|  | 
 | ||||
|  |     def action_purchase_order(self): | ||||
|  |         """Method action_purchase_order to return the form view of the | ||||
|  |         model purchase.order""" | ||||
|  |         return { | ||||
|  |             'type': 'ir.actions.act_window', | ||||
|  |             'name': _('Purchase Order'), | ||||
|  |             'res_id': self.order_id.id, | ||||
|  |             'res_model': 'purchase.order', | ||||
|  |             'view_mode': 'form', | ||||
|  |             'target': 'current', | ||||
|  |         } | ||||
| @ -0,0 +1,46 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class PurchaseReport(models.Model): | ||||
|  |     """Inherit model to add fields and methods""" | ||||
|  |     _inherit = 'purchase.report' | ||||
|  | 
 | ||||
|  |     brand_id = fields.Many2one( | ||||
|  |         'product.brand', string='Brand', help='Select brand of the product' | ||||
|  |     ) | ||||
|  | 
 | ||||
|  |     def _select(self): | ||||
|  |         """Add filter in pivot view""" | ||||
|  |         res = super(PurchaseReport, self)._select() | ||||
|  |         query = res.split('t.categ_id as category_id,', 1) | ||||
|  |         res = query[0] + 't.categ_id as category_id,t.brand_id' \ | ||||
|  |                           ' as brand_id,' + query[1] | ||||
|  |         return res | ||||
|  | 
 | ||||
|  |     def _group_by(self): | ||||
|  |         """Add the group by in pivot view""" | ||||
|  |         res = super(PurchaseReport, self)._group_by() | ||||
|  |         query = res.split('t.categ_id,', 1) | ||||
|  |         res = query[0] + 't.categ_id,t.brand_id,' + query[1] | ||||
|  |         return res | ||||
| @ -0,0 +1,74 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import api, fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class RequisitionOrder(models.Model): | ||||
|  |     """Model for requisition order""" | ||||
|  |     _name = 'requisition.order' | ||||
|  |     _description = 'Requisition order' | ||||
|  | 
 | ||||
|  |     requisition_product_id = fields.Many2one( | ||||
|  |         'employee.purchase.requisition', string="Requisition Product", | ||||
|  |         help='Requisition product.') | ||||
|  |     state = fields.Selection( | ||||
|  |         string='State', related='requisition_product_id.state', | ||||
|  |         help="Requisition State") | ||||
|  |     requisition_type = fields.Selection( | ||||
|  |         string='Requisition Type', | ||||
|  |         selection=[ | ||||
|  |             ('purchase_order', 'Purchase Order'), | ||||
|  |             ('internal_transfer', 'Internal Transfer')], | ||||
|  |         help='Type of requisition') | ||||
|  |     product_id = fields.Many2one( | ||||
|  |         'product.product', required=True, string="Product", | ||||
|  |         help='Select Product') | ||||
|  |     description = fields.Text( | ||||
|  |         string="Description", | ||||
|  |         compute='_compute_product_id', | ||||
|  |         store=True, readonly=False, | ||||
|  |         help='Product Description') | ||||
|  |     quantity = fields.Integer(string='Quantity', help='Quantity') | ||||
|  |     uom = fields.Char( | ||||
|  |         related='product_id.uom_id.name', string='Unit of Measure', | ||||
|  |         help='Product Uom') | ||||
|  |     partner_ids = fields.Many2many('res.partner', | ||||
|  |                                    compute='_compute_requisition_type') | ||||
|  |     partner_id = fields.Many2one( | ||||
|  |         'res.partner', string='Vendor', | ||||
|  |         help='Vendor for the requisition', readonly=False, ) | ||||
|  | 
 | ||||
|  |     @api.depends('product_id') | ||||
|  |     def _compute_product_id(self): | ||||
|  |         """Compute product description '[("id", "in", [13, 66, 65, 51] )]'""" | ||||
|  |         for option in self: | ||||
|  |             if not option.product_id: | ||||
|  |                 continue | ||||
|  |             product_lang = option.product_id.with_context( | ||||
|  |                 lang=self.requisition_product_id.employee_id.lang) | ||||
|  |             option.description = product_lang.get_product_multiline_description_sale() | ||||
|  | 
 | ||||
|  |     @api.depends('requisition_type', 'product_id') | ||||
|  |     def _compute_requisition_type(self): | ||||
|  |         """Fetching product vendors""" | ||||
|  |         self.partner_ids = [data.name.id for data in | ||||
|  |                             self.product_id.seller_ids] if self.product_id else False | ||||
| @ -0,0 +1,31 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ResConfigSettings(models.TransientModel): | ||||
|  |     """Add field in res.config.settings""" | ||||
|  |     _inherit = 'res.config.settings' | ||||
|  |     is_show_product_image_in_report_purchase = fields.Boolean( | ||||
|  |         string="Show Product Image", | ||||
|  |         config_parameter='all_in_one_purchase_kit.is_show_product_image_in_report_purchase', | ||||
|  |         help="Enable this field to Print image in report") | ||||
| @ -0,0 +1,49 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import api, fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class ResPartner(models.Model): | ||||
|  |     """Inheriting res partner to add fields and methods""" | ||||
|  |     _inherit = 'res.partner' | ||||
|  | 
 | ||||
|  |     discount = fields.Float(string="Discount (%)", help="Discount in %") | ||||
|  |     _sql_constraints = [ | ||||
|  |         ( | ||||
|  |             "maximum_discount", | ||||
|  |             "CHECK (discount <= 100.0)", | ||||
|  |             "Discount must be lower than 100%.", | ||||
|  |         ) | ||||
|  |     ] | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def get_vendor_po(self): | ||||
|  |         """Get purchase order of vendors""" | ||||
|  |         count_dict = { | ||||
|  |             count['name']: count['purchase_order_count'] | ||||
|  |             for count in self.search_read( | ||||
|  |                 [], ['name', 'purchase_order_count'], | ||||
|  |                 order='purchase_order_count') | ||||
|  |             if count['purchase_order_count'] > 0 | ||||
|  |         } | ||||
|  |         return {'purchase_order_count': {key: val for key, val in sorted( | ||||
|  |             count_dict.items(), key=lambda ele: ele[1], reverse=True)}} | ||||
| @ -0,0 +1,34 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import fields, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class StockPicking(models.Model): | ||||
|  |     """ | ||||
|  |     Inherit stock.picking model and add field requisition order in | ||||
|  |     stock picking | ||||
|  |     """ | ||||
|  |     _inherit = 'stock.picking' | ||||
|  | 
 | ||||
|  |     requisition_order = fields.Char( | ||||
|  |         string='Requisition Order', help='Requisition Order' | ||||
|  |     ) | ||||
| @ -0,0 +1,22 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from . import purchase_order_report | ||||
| @ -0,0 +1,11 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <!--Purchase requisition report--> | ||||
|  |     <record id="report_purchase_requisition_action" model="ir.actions.report"> | ||||
|  |         <field name="name">Material Purchase Requisition Report</field> | ||||
|  |         <field name="model">employee.purchase.requisition</field> | ||||
|  |         <field name="report_type">qweb-pdf</field> | ||||
|  |         <field name="report_name">all_in_one_purchase_kit.report_purchase_requisition</field> | ||||
|  |         <field name="report_file">all_in_one_purchase_kit.report_purchase_requisition</field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,11 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <!--Print pdf report--> | ||||
|  |     <record id="purchase_all_in_one_purchase_kit_action" model="ir.actions.report"> | ||||
|  |         <field name="name">Purchase All In One Report</field> | ||||
|  |         <field name="model">dynamic.purchase.report</field> | ||||
|  |         <field name="report_type">qweb-pdf</field> | ||||
|  |         <field name="report_name">all_in_one_purchase_kit.purchase_order_report</field> | ||||
|  |         <field name="report_file">all_in_one_purchase_kit.purchase_order_report</field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,43 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################### | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | ||||
|  | #    Author: Swaraj R (odoo@cybrosys.com) | ||||
|  | # | ||||
|  | #    You can modify it under the terms of the GNU AFFERO | ||||
|  | #    GENERAL PUBLIC LICENSE (AGPL 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 AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. | ||||
|  | # | ||||
|  | #    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|  | #    (AGPL v3) along with this program. | ||||
|  | #    If not, see <http://www.gnu.org/licenses/>. | ||||
|  | # | ||||
|  | ############################################################################### | ||||
|  | from odoo import api, models | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class PurchaseOrderReport(models.AbstractModel): | ||||
|  |     """Model to get value for the report""" | ||||
|  |     _name = 'report.all_in_one_purchase_kit.purchase_order_report' | ||||
|  |     _description = "All In One Purchase Order Kit Report" | ||||
|  | 
 | ||||
|  |     @api.model | ||||
|  |     def _get_report_values(self, docids, data=None): | ||||
|  |         """Get values for the report""" | ||||
|  |         if self.env.context.get('purchase_order_report') and\ | ||||
|  |                 data.get('report_data'): | ||||
|  |             data.update( | ||||
|  |                 { | ||||
|  |                     'report_main_line_data': | ||||
|  |                         data.get('report_data')['report_lines'], | ||||
|  |                     'Filters': data.get('report_data')['filters'], | ||||
|  |                     'company': self.env.company | ||||
|  |                 } | ||||
|  |             ) | ||||
|  |         return data | ||||
| @ -0,0 +1,427 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <!--Template to show purchase report respect to the filter selected--> | ||||
|  |     <template id="purchase_order_report"> | ||||
|  |         <t t-call="web.html_container"> | ||||
|  |             <t t-call="web.internal_layout"> | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By Order'"> | ||||
|  |                     <t t-call="all_in_one_purchase_kit.report_order"/> | ||||
|  |                 </t> | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By Order Detail'"> | ||||
|  |                     <t t-call="all_in_one_purchase_kit.report_order_detail"/> | ||||
|  |                 </t> | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By Product'"> | ||||
|  |                     <t t-call="all_in_one_purchase_kit.report_product"/> | ||||
|  |                 </t> | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By Categories'"> | ||||
|  |                     <t t-call="all_in_one_purchase_kit.report_category"/> | ||||
|  |                 </t> | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By Purchase Representative'"> | ||||
|  |                     <t t-call="all_in_one_purchase_kit.report_purchase_representative"/> | ||||
|  |                 </t> | ||||
|  |                 <t t-if="Filters.get('report_type')=='Report By State'"> | ||||
|  |                     <t t-call="all_in_one_purchase_kit.report_state"/> | ||||
|  |                 </t> | ||||
|  |             </t> | ||||
|  |         </t> | ||||
|  |     </template> | ||||
|  |     <!--Report template when 'Report By Order' filter applied--> | ||||
|  |     <template id="report_order"> | ||||
|  |         <div class="page"> | ||||
|  |             <div class="oe_structure"/> | ||||
|  |             <span t-if="Filters.get('date_from')"> | ||||
|  |                 <strong>From:</strong> | ||||
|  |                 <t t-esc="Filters['date_from']"/> | ||||
|  |             </span> | ||||
|  |             <span t-if="Filters.get('date_to')"> | ||||
|  |                 <strong>To:</strong> | ||||
|  |                 <t t-esc="Filters['date_to']"/> | ||||
|  |             </span> | ||||
|  |             <div> | ||||
|  |                 <div style="width:100%;"> | ||||
|  |                     <div style="text-align:centre;" class="row"> | ||||
|  |                         <div class="col-2"> | ||||
|  |                             <strong>Report Type:</strong> | ||||
|  |                             <t t-esc="Filters.get('report_type')"/> | ||||
|  |                         </div> | ||||
|  |                     </div> | ||||
|  |                 </div> | ||||
|  |                 <br/> | ||||
|  |                 <table class="table table-sm table-reports"> | ||||
|  |                     <thead> | ||||
|  |                         <tr> | ||||
|  |                             <th class="text-left">Order</th> | ||||
|  |                             <th colspan="6" class="text-center">Date Order</th> | ||||
|  |                             <th colspan="6" class="text-right">Customer</th> | ||||
|  |                             <th colspan="6" class="text-right">Purchase | ||||
|  |                                 Representative | ||||
|  |                             </th> | ||||
|  |                             <th colspan="6" class="text-center">Total Qty</th> | ||||
|  |                             <th colspan="6" class="text-left">Amount Total</th> | ||||
|  |                         </tr> | ||||
|  |                     </thead> | ||||
|  |                     <tbody class="text-left"> | ||||
|  |                         <t t-foreach="report_main_line_data" t-as="main"> | ||||
|  |                             <tr style="font-weight: bold;"> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['name']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['date_order']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['partner']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['salesman']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['sum']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['amount_total']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  |     <!--Report template when 'Report By Order Detail' filter applied--> | ||||
|  |     <template id="report_order_detail"> | ||||
|  |         <div class="page"> | ||||
|  |             <div class="oe_structure"/> | ||||
|  |             <span t-if="Filters.get('date_from')"> | ||||
|  |                 <strong>From:</strong> | ||||
|  |                 <t t-esc="Filters['date_from']"/> | ||||
|  |             </span> | ||||
|  |             <span t-if="Filters.get('date_to')"> | ||||
|  |                 <strong>To:</strong> | ||||
|  |                 <t t-esc="Filters['date_to']"/> | ||||
|  |             </span> | ||||
|  |             <div> | ||||
|  |                 <div style="width:100%;"> | ||||
|  |                     <div style="text-align:centre;" class="row"> | ||||
|  |                         <div class="col-2"> | ||||
|  |                             <strong>Report Type:</strong> | ||||
|  |                             <t t-esc="Filters.get('report_type')"/> | ||||
|  |                         </div> | ||||
|  |                     </div> | ||||
|  |                 </div> | ||||
|  |                 <br/> | ||||
|  |                 <table class="table table-sm table-reports"> | ||||
|  |                     <thead> | ||||
|  |                         <tr class="text-right"> | ||||
|  |                             <th>Order</th> | ||||
|  |                             <th colspan="6">Date Order</th> | ||||
|  |                             <th colspan="6">Customer</th> | ||||
|  |                             <th colspan="6">Purchase Representative</th> | ||||
|  |                             <th colspan="6">Product Code</th> | ||||
|  |                             <th colspan="6">Product Name</th> | ||||
|  |                             <th colspan="6">Price unit</th> | ||||
|  |                             <th colspan="6">Qty</th> | ||||
|  |                             <th colspan="6">Price Total</th> | ||||
|  |                         </tr> | ||||
|  |                     </thead> | ||||
|  |                     <tbody> | ||||
|  |                         <t t-foreach="report_main_line_data" t-as="main"> | ||||
|  |                             <tr style="font-weight: bold;"> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['name']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['date_order']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['partner']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['salesman']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['default_code']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['product']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['price_unit']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['sum']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['amount_total']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  |     <!--Report template when 'Report By Product' filter applied--> | ||||
|  |     <template id="report_product"> | ||||
|  |         <div class="page"> | ||||
|  |             <div class="oe_structure"/> | ||||
|  |             <span t-if="Filters.get('date_from')"> | ||||
|  |                 <strong>From:</strong> | ||||
|  |                 <t t-esc="Filters['date_from']"/> | ||||
|  |             </span> | ||||
|  |             <span t-if="Filters.get('date_to')"> | ||||
|  |                 <strong>To:</strong> | ||||
|  |                 <t t-esc="Filters['date_to']"/> | ||||
|  |             </span> | ||||
|  |             <div> | ||||
|  |                 <div style="width:100%;"> | ||||
|  |                     <div style="text-align:centre;" class="row"> | ||||
|  |                         <div class="col-2"> | ||||
|  |                             <strong>Report Type:</strong> | ||||
|  |                             <t t-esc="Filters.get('report_type')"/> | ||||
|  |                         </div> | ||||
|  |                     </div> | ||||
|  |                 </div> | ||||
|  |                 <br/> | ||||
|  |                 <table class="table table-sm table-reports"> | ||||
|  |                     <thead> | ||||
|  |                         <tr> | ||||
|  |                             <th class="text-left">Category</th> | ||||
|  |                             <th colspan="6" class="text-center">Product Code | ||||
|  |                             </th> | ||||
|  |                             <th colspan="6" class="text-center">Product Name | ||||
|  |                             </th> | ||||
|  |                             <th colspan="6" class="text-center">Qty</th> | ||||
|  |                             <th colspan="6">Amount Total</th> | ||||
|  |                         </tr> | ||||
|  |                     </thead> | ||||
|  |                     <tbody> | ||||
|  |                         <t t-foreach="report_main_line_data" t-as="main"> | ||||
|  |                             <tr style="font-weight: bold;"> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['name']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['default_code']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['product']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['qty']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['amount_total']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  |     <!--Report template when 'Report By Category' filter applied--> | ||||
|  |     <template id="report_category"> | ||||
|  |         <div class="page"> | ||||
|  |             <div class="oe_structure"/> | ||||
|  |             <span t-if="Filters.get('date_from')"> | ||||
|  |                 <strong>From:</strong> | ||||
|  |                 <t t-esc="Filters['date_from']"/> | ||||
|  |             </span> | ||||
|  |             <span t-if="Filters.get('date_to')"> | ||||
|  |                 <strong>To:</strong> | ||||
|  |                 <t t-esc="Filters['date_to']"/> | ||||
|  |             </span> | ||||
|  |             <div> | ||||
|  |                 <div style="width:100%;"> | ||||
|  |                     <div style="text-align:centre;" class="row"> | ||||
|  |                         <div class="col-2"> | ||||
|  |                             <strong>Report Type:</strong> | ||||
|  |                             <t t-esc="Filters.get('report_type')"/> | ||||
|  |                         </div> | ||||
|  |                     </div> | ||||
|  |                 </div> | ||||
|  |                 <br/> | ||||
|  |                 <table class="table table-sm table-reports"> | ||||
|  |                     <thead> | ||||
|  |                         <tr> | ||||
|  |                             <th colspan="6">Category</th> | ||||
|  |                             <th colspan="6">Qty</th> | ||||
|  |                             <th colspan="6">Amount Total</th> | ||||
|  |                         </tr> | ||||
|  |                     </thead> | ||||
|  |                     <tbody> | ||||
|  |                         <t t-foreach="report_main_line_data" | ||||
|  |                            t-as="purchase_category"> | ||||
|  |                             <tr style="font-weight: bold;"> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="purchase_category['name']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="purchase_category['qty']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="purchase_category['amount_total']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  |     <!--Report template when 'Report By Purchase Representative' | ||||
|  |     filter applied--> | ||||
|  |     <template id="report_purchase_representative"> | ||||
|  |         <div class="page"> | ||||
|  |             <div class="oe_structure"/> | ||||
|  |             <span t-if="Filters.get('date_from')"> | ||||
|  |                 <strong>From:</strong> | ||||
|  |                 <t t-esc="Filters['date_from']"/> | ||||
|  |             </span> | ||||
|  |             <span t-if="Filters.get('date_to')"> | ||||
|  |                 <strong>To:</strong> | ||||
|  |                 <t t-esc="Filters['date_to']"/> | ||||
|  |             </span> | ||||
|  |             <div> | ||||
|  |                 <div style="width:100%;"> | ||||
|  |                     <div style="text-align:centre;" class="row"> | ||||
|  | 
 | ||||
|  |                         <div class="col-2"> | ||||
|  |                             <strong>Report Type:</strong> | ||||
|  |                             <t t-esc="Filters.get('report_type')"/> | ||||
|  |                         </div> | ||||
|  |                     </div> | ||||
|  |                 </div> | ||||
|  |                 <br/> | ||||
|  |                 <table class="table table-sm table-reports"> | ||||
|  |                     <thead> | ||||
|  |                         <tr> | ||||
|  |                             <th>Purchase Representative</th> | ||||
|  |                             <th colspan="6">Total Order</th> | ||||
|  |                             <th colspan="6">Total Qty</th> | ||||
|  |                             <th colspan="6">Total Amount</th> | ||||
|  |                         </tr> | ||||
|  |                     </thead> | ||||
|  |                     <tbody> | ||||
|  |                         <t t-foreach="report_main_line_data" t-as="main"> | ||||
|  |                             <tr style="font-weight: bold;"> | ||||
|  |                                 <td> | ||||
|  |                                     <span t-esc="main['name']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['order']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['qty']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <span t-esc="main['amount']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  |     <!--Report template when 'Report By State' filter applied--> | ||||
|  |     <template id="report_state"> | ||||
|  |         <div class="page"> | ||||
|  |             <div class="oe_structure"/> | ||||
|  |             <span t-if="Filters.get('date_from')"> | ||||
|  |                 <strong>From:</strong> | ||||
|  |                 <t t-esc="Filters['date_from']"/> | ||||
|  |             </span> | ||||
|  |             <span t-if="Filters.get('date_to')"> | ||||
|  |                 <strong>To:</strong> | ||||
|  |                 <t t-esc="Filters['date_to']"/> | ||||
|  |             </span> | ||||
|  |             <div> | ||||
|  |                 <div style="width:100%;"> | ||||
|  |                     <div style="text-align:centre;" class="row"> | ||||
|  |                         <div class="col-2"> | ||||
|  |                             <strong>Report Type:</strong> | ||||
|  |                             <t t-esc="Filters.get('report_type')"/> | ||||
|  |                         </div> | ||||
|  |                     </div> | ||||
|  |                 </div> | ||||
|  |                 <br/> | ||||
|  |                 <table class="table table-sm table-reports"> | ||||
|  |                     <thead> | ||||
|  |                         <tr class="text-left"> | ||||
|  |                             <th>State</th> | ||||
|  |                             <th colspan="6">Total Count</th> | ||||
|  |                             <th colspan="6">Quantity</th> | ||||
|  |                             <th colspan="6">Amount</th> | ||||
|  |                         </tr> | ||||
|  |                     </thead> | ||||
|  |                     <tbody> | ||||
|  |                         <t t-foreach="report_main_line_data" t-as="main"> | ||||
|  |                             <tr style="font-weight: bold;"> | ||||
|  |                                 <td colspan="6"> | ||||
|  |                                     <t t-if="main['state'] == 'draft'"> | ||||
|  |                                         <span>Quotation</span> | ||||
|  |                                     </t> | ||||
|  |                                     <t t-if="main['state'] == 'sent'"> | ||||
|  |                                         <span>Quotation Sent</span> | ||||
|  |                                     </t> | ||||
|  |                                     <t t-if="main['state'] == 'purchase'"> | ||||
|  |                                         <span>Purchase Order</span> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6" class="text-left"> | ||||
|  |                                     <span t-esc="main['order']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6" class="text-left"> | ||||
|  |                                     <span t-esc="main['qty']"/> | ||||
|  |                                 </td> | ||||
|  |                                 <td colspan="6" class="text-left"> | ||||
|  |                                     <span t-esc="main['amount']"/> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </t> | ||||
|  |                     </tbody> | ||||
|  |                 </table> | ||||
|  |             </div> | ||||
|  |             <br/> | ||||
|  |         </div> | ||||
|  |     </template> | ||||
|  |     <!--Inherit template report_purchaseorder_document--> | ||||
|  |     <template id="report_purchaseorder_inherit" | ||||
|  |               inherit_id="purchase.report_purchaseorder_document"> | ||||
|  |         <xpath expr="//table//tr/th[1]" position="after"> | ||||
|  |             <t t-if="request.env['ir.config_parameter'].sudo().get_param('all_in_one_purchase_kit.is_show_product_image_in_report_purchase')"> | ||||
|  |                 <th> | ||||
|  |                     <strong>Image</strong> | ||||
|  |                 </th> | ||||
|  |             </t> | ||||
|  |         </xpath> | ||||
|  |         <!--Add product image in the report--> | ||||
|  |         <xpath expr="//t[@t-foreach='o.order_line']/tr/t[@t-if='not line.display_type']/td[1]" | ||||
|  |                position="after"> | ||||
|  |             <t t-if="request.env['ir.config_parameter'].sudo().get_param('all_in_one_purchase_kit.is_show_product_image_in_report_purchase')"> | ||||
|  |                 <td style="height:20px !important;width:20px !important;"> | ||||
|  |                     <span t-field="line.product_image" | ||||
|  |                           t-options='{"widget": "image"}'/> | ||||
|  |                 </td> | ||||
|  |             </t> | ||||
|  |         </xpath> | ||||
|  |         <xpath expr="//th[@name='th_price_unit']" position="after"> | ||||
|  |             <th name="th_discount" class="text-right"> | ||||
|  |                 <strong>Discount(%)</strong> | ||||
|  |             </th> | ||||
|  |         </xpath> | ||||
|  |         <!--Add discount to report--> | ||||
|  |         <xpath expr="//td[span[@t-field='line.price_subtotal']]" position="before"> | ||||
|  |             <td class="text-right"> | ||||
|  |                 <span t-field="line.discount"/> | ||||
|  |             </td> | ||||
|  |         </xpath> | ||||
|  |     </template> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,15 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8" ?> | ||||
|  | <odoo> | ||||
|  |     <!--Print amount in words in bill--> | ||||
|  |     <template id="invoice_report_view_amount_in_words" | ||||
|  |               inherit_id="account.report_invoice_document"> | ||||
|  |         <xpath expr="//div[@id='informations']" position="before"> | ||||
|  |             <div style="font-size:15px; padding-top:15px; padding-bottom:15px;"> | ||||
|  |                 <span> | ||||
|  |                     <strong>Amount in Words (Total) :</strong> | ||||
|  |                 </span> | ||||
|  |                 <span t-field="o.number_to_words"/> | ||||
|  |             </div> | ||||
|  |         </xpath> | ||||
|  |     </template> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,206 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <!--Purchase requisition report template--> | ||||
|  |     <template id="report_purchase_requisition"> | ||||
|  |         <t t-call="web.external_layout"> | ||||
|  |             <t t-call="web.html_container"> | ||||
|  |                 <div class="page"> | ||||
|  |                     <t t-foreach="records" t-as="rec"> | ||||
|  |                         <h1>Purchase Requisition : | ||||
|  |                             <t t-if="rec['name']"> | ||||
|  |                             <t t-esc="rec['name']"/> | ||||
|  |                             </t> | ||||
|  |                         </h1> | ||||
|  |                         <table class="table table-striped"> | ||||
|  |                             <tr> | ||||
|  |                                 <th>Employee</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['employee_id']"> | ||||
|  |                                     <t t-esc="rec['employee_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <th>Requisition Date</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['employee_id']"> | ||||
|  |                                     <t t-esc="rec['requisition_date']"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                             <tr> | ||||
|  |                                 <th>Department</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['dept_id']"> | ||||
|  |                                     <t t-esc="rec['dept_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <th>Received Date</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['receive_date']"> | ||||
|  |                                     <t t-esc="rec['receive_date']"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                             <tr> | ||||
|  |                                 <th>Requisition Responsible</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['user_id']"> | ||||
|  |                                     <t t-esc="rec['user_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <th>Requisition Deadline</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['requisition_deadline']"> | ||||
|  |                                     <t t-esc="rec['requisition_deadline']"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                             <tr> | ||||
|  |                                 <th>Company</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['company_id']"> | ||||
|  |                                     <t t-esc="rec['company_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </table> | ||||
|  |                         <h1>Other Information</h1> | ||||
|  |                         <table class="table table-sm"> | ||||
|  |                             <tr> | ||||
|  |                                 <th>Confirmed By</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['confirm_id']"> | ||||
|  |                                     <t t-esc="rec['confirm_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <th>Confirmed Date</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['confirmed_date']"> | ||||
|  |                                     <t t-esc="rec['confirmed_date']"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                             <tr> | ||||
|  |                                 <th>Department Manager</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['manager_id']"> | ||||
|  |                                     <t t-esc="rec['manager_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <th>Department Approval Date</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['department_approval_date']"> | ||||
|  |                                     <t t-esc="rec['department_approval_date']"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  | 
 | ||||
|  |                             <tr> | ||||
|  |                                 <th>Approved By:</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['requisition_head_id']"> | ||||
|  |                                     <t t-esc="rec['requisition_head_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <th>Approved Date:</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['approval_date']"> | ||||
|  |                                     <t t-esc="rec['approval_date']"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                             <tr> | ||||
|  |                                 <th>Rejected By</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['rejected_user_id']"> | ||||
|  |                                         <t t-esc="rec['rejected_user_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <th>Rejected Date</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['reject_date']"> | ||||
|  |                                         <t t-esc="rec['reject_date']"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                         </table> | ||||
|  |                         <h1>Picking Details</h1> | ||||
|  |                         <table class="table table-sm"> | ||||
|  |                             <tr> | ||||
|  |                                 <th>Source Location</th> | ||||
|  |                                 <td> | ||||
|  |                                      <t t-if="rec['source_location_id']"> | ||||
|  |                                     <t t-esc="rec['source_location_id'][1]"/> | ||||
|  |                                      </t> | ||||
|  |                                 </td> | ||||
|  |                                 <th>Destination Location</th> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="rec['source_location_id']"> | ||||
|  |                                     <t t-esc="rec['destination_location_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                             </tr> | ||||
|  |                             <tr> | ||||
|  |                                 <t t-if="rec['delivery_type_id']"> | ||||
|  |                                     <th>Delivery To</th> | ||||
|  |                                     <td> | ||||
|  |                                         <t t-esc="rec['delivery_type_id'][1]"/> | ||||
|  |                                     </td> | ||||
|  |                                 </t> | ||||
|  |                                 <t t-if="rec['internal_picking_id']"> | ||||
|  |                                     <th>Internal Transfer</th> | ||||
|  |                                     <td> | ||||
|  |                                         <t t-esc="rec['internal_picking_id'][1]"/> | ||||
|  |                                     </td> | ||||
|  |                                 </t> | ||||
|  |                             </tr> | ||||
|  |                         </table> | ||||
|  |                     </t> | ||||
|  |                     <h1>Requisition Lines</h1> | ||||
|  |                     <table class='table'> | ||||
|  |                         <thead> | ||||
|  |                             <th>Requisition Action</th> | ||||
|  |                             <th>Product</th> | ||||
|  |                             <th>Description</th> | ||||
|  |                             <th>Quantity</th> | ||||
|  |                             <th>Unit Of Measure</th> | ||||
|  |                         </thead> | ||||
|  |                         <t t-foreach="order_ids" t-as="order"> | ||||
|  |                             <tbody> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="order['requisition_type']=='internal_transfer'"> | ||||
|  |                                         Internal Transfer | ||||
|  |                                     </t> | ||||
|  |                                     <t t-if="order['requisition_type']=='purchase_order'"> | ||||
|  |                                         Purchase Order | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="order['product_id']"> | ||||
|  |                                     <t t-esc="order['product_id'][1]"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="order['description']"> | ||||
|  |                                     <t t-esc="order['description']"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <td> | ||||
|  |                                     <t t-if="order['quantity']"> | ||||
|  |                                     <t t-esc="order['quantity']"/> | ||||
|  |                                     </t> | ||||
|  |                                 </td> | ||||
|  |                                 <td><t t-if="order['uom']"> | ||||
|  |                                     <t t-esc="order['uom']"/> | ||||
|  |                                 </t> | ||||
|  |                                 </td> | ||||
|  |                             </tbody> | ||||
|  |                         </t> | ||||
|  |                     </table> | ||||
|  |                     <h3>Employee Signature :</h3> | ||||
|  |                     <h3>Manager Signature :</h3> | ||||
|  |                     <h3>Approve Signature :</h3> | ||||
|  |                 </div> | ||||
|  |             </t> | ||||
|  |         </t> | ||||
|  |     </template> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,30 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||
|  | <odoo> | ||||
|  |     <record id="employee_requisition" model="ir.module.category"> | ||||
|  |         <field name="name">Employee Purchase Requisition</field> | ||||
|  |         <field name="description">User access level for Material Request | ||||
|  |             module | ||||
|  |         </field> | ||||
|  |         <field name="sequence">20</field> | ||||
|  |     </record> | ||||
|  |     <!--User groups--> | ||||
|  |     <!--User requisition--> | ||||
|  |     <record id="employee_requisition_user" model="res.groups"> | ||||
|  |         <field name="name">Requisition Users</field> | ||||
|  |         <field name="category_id" ref="employee_requisition"/> | ||||
|  |     </record> | ||||
|  |     <!--Requisition rights for head--> | ||||
|  |     <record id="employee_requisition_head" model="res.groups"> | ||||
|  |         <field name="name">Department Head</field> | ||||
|  |         <field name="category_id" ref="employee_requisition"/> | ||||
|  |         <field name="implied_ids" | ||||
|  |                eval="[(4, ref('all_in_one_purchase_kit.employee_requisition_user'))]"/> | ||||
|  |     </record> | ||||
|  |     <!--Requisition rights for manager--> | ||||
|  |     <record id="employee_requisition_manager" model="res.groups"> | ||||
|  |         <field name="name">Requisition Manager</field> | ||||
|  |         <field name="category_id" ref="employee_requisition"/> | ||||
|  |         <field name="implied_ids" | ||||
|  |                eval="[(4, ref('all_in_one_purchase_kit.employee_requisition_head'))]"/> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,34 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |     <!--Record rules--> | ||||
|  |     <!--Rule for User--> | ||||
|  |     <record id="requisition_user_rule" model="ir.rule"> | ||||
|  |         <field name="name">Requisition User Rule</field> | ||||
|  |         <field name="model_id" ref="model_employee_purchase_requisition"/> | ||||
|  |         <field name="domain_force">[('confirm_id', '=', user.id)]</field> | ||||
|  |         <field name="groups" | ||||
|  |                eval="[(4, ref('all_in_one_purchase_kit.employee_requisition_user'))]"/> | ||||
|  |     </record> | ||||
|  |     <!--Rule for head--> | ||||
|  |     <record id="department_head_rule" model="ir.rule"> | ||||
|  |         <field name="name">Department Head Rule</field> | ||||
|  |         <field ref="model_employee_purchase_requisition" name="model_id"/> | ||||
|  |         <field name="domain_force">[('user_id','=',user.id)]</field> | ||||
|  |         <field name="groups" | ||||
|  |                eval="[(4, ref('all_in_one_purchase_kit.employee_requisition_head'))]"/> | ||||
|  |     </record> | ||||
|  |     <!--Rule for manager--> | ||||
|  |     <record id="requisition_manager_rule" model="ir.rule"> | ||||
|  |         <field name="name">Requisition Manager Rule</field> | ||||
|  |         <field ref="model_employee_purchase_requisition" name="model_id"/> | ||||
|  |         <field name="domain_force">[(1,'=',1)]</field> | ||||
|  |         <field name="groups" | ||||
|  |                eval="[(4, ref('all_in_one_purchase_kit.employee_requisition_manager'))]"/> | ||||
|  |     </record> | ||||
|  |     <!--Company rule--> | ||||
|  |     <record id="requisition_company_rule" model="ir.rule"> | ||||
|  |         <field name="name">Purchase Requisition Company Rule</field> | ||||
|  |         <field ref="model_employee_purchase_requisition" name="model_id"/> | ||||
|  |         <field name="domain_force">[('company_id', '=', company_id)]</field> | ||||
|  |     </record> | ||||
|  | </odoo> | ||||
| 
 | 
| After Width: | Height: | Size: 3.6 KiB | 
| After Width: | Height: | Size: 310 B | 
| After Width: | Height: | Size: 1.3 KiB | 
| After Width: | Height: | Size: 1.4 KiB | 
| After Width: | Height: | Size: 576 B | 
| After Width: | Height: | Size: 733 B | 
| After Width: | Height: | Size: 911 B | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 673 B | 
| After Width: | Height: | Size: 878 B | 
| After Width: | Height: | Size: 653 B | 
| After Width: | Height: | Size: 905 B | 
| After Width: | Height: | Size: 839 B | 
| After Width: | Height: | Size: 427 B | 
| After Width: | Height: | Size: 627 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 988 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 1.5 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.9 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 2.1 KiB | 
| After Width: | Height: | Size: 4.4 KiB | 
| After Width: | Height: | Size: 589 B | 
| After Width: | Height: | Size: 3.4 KiB | 
| After Width: | Height: | Size: 1.7 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 967 B | 
| After Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 3.8 KiB | 
| After Width: | Height: | Size: 5.0 KiB | 
| After Width: | Height: | Size: 57 KiB | 
| After Width: | Height: | Size: 58 KiB | 
| After Width: | Height: | Size: 48 KiB | 
| After Width: | Height: | Size: 80 KiB | 
| After Width: | Height: | Size: 50 KiB | 
| After Width: | Height: | Size: 92 KiB | 
| After Width: | Height: | Size: 128 KiB | 
| After Width: | Height: | Size: 42 KiB | 
| After Width: | Height: | Size: 127 KiB | 
| After Width: | Height: | Size: 240 KiB | 
| After Width: | Height: | Size: 136 KiB | 
| After Width: | Height: | Size: 79 KiB | 
| After Width: | Height: | Size: 127 KiB | 
| After Width: | Height: | Size: 226 KiB | 
| After Width: | Height: | Size: 167 KiB | 
| After Width: | Height: | Size: 215 KiB | 
| After Width: | Height: | Size: 190 KiB | 
| After Width: | Height: | Size: 37 KiB | 
| After Width: | Height: | Size: 211 KiB | 
| After Width: | Height: | Size: 190 KiB | 
| After Width: | Height: | Size: 212 KiB | 
| After Width: | Height: | Size: 212 KiB | 
| After Width: | Height: | Size: 219 KiB | 
| After Width: | Height: | Size: 188 KiB | 
| After Width: | Height: | Size: 77 KiB | 
| After Width: | Height: | Size: 237 KiB | 
| After Width: | Height: | Size: 215 KiB | 
| After Width: | Height: | Size: 223 KiB | 
| After Width: | Height: | Size: 54 KiB | 
| After Width: | Height: | Size: 291 KiB | 
| After Width: | Height: | Size: 214 KiB | 
| After Width: | Height: | Size: 216 KiB |