You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							215 lines
						
					
					
						
							9.8 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							215 lines
						
					
					
						
							9.8 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ############################################################################# | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | |
| #    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | |
| # | |
| #    You can modify it under the terms of the GNU LESSER | |
| #    GENERAL PUBLIC LICENSE (LGPL v3), Version 3. | |
| # | |
| #    This program is distributed in the hope that it will be useful, | |
| #    but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| #    GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | |
| # | |
| #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | |
| #    (LGPL v3) along with this program. | |
| #    If not, see <http://www.gnu.org/licenses/>. | |
| # | |
| ############################################################################# | |
| import ast | |
| from datetime import datetime | |
| from odoo import api, fields, models, _ | |
| from odoo.exceptions import UserError | |
| from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF | |
| from dateutil.relativedelta import relativedelta | |
| 
 | |
| 
 | |
| class AccountInvoiceLine(models.Model): | |
|     """Define a model for account invoice lines with fields related to assets and their management.""" | |
|     _inherit = 'account.move.line' | |
| 
 | |
|     asset_category_id = fields.Many2one('account.asset.category', | |
|                                         string='Asset Category') | |
|     asset_start_date = fields.Date(string='Asset Start Date', | |
|                                    compute='_get_asset_date', readonly=True, | |
|                                    store=True) | |
|     asset_end_date = fields.Date(string='Asset End Date', | |
|                                  compute='_get_asset_date', readonly=True, | |
|                                  store=True) | |
|     asset_mrr = fields.Float(string='Monthly Recurring Revenue', | |
|                              compute='_get_asset_date', | |
|                              readonly=True, digits='Account', | |
|                              store=True) | |
| 
 | |
|     @api.depends('asset_category_id', 'move_id.invoice_date') | |
|     def _get_asset_date(self): | |
|         """Returns the asset_start_date and the asset_end_date of the Asset""" | |
|         for record in self: | |
|             record.asset_mrr = 0 | |
|             record.asset_start_date = False | |
|             record.asset_end_date = False | |
|             cat = record.asset_category_id | |
|             if cat: | |
|                 if cat.method_number == 0 or cat.method_period == 0: | |
|                     raise UserError(_( | |
|                         'The number of depreciations or the period length of ' | |
|                         'your asset category cannot be null.')) | |
|                 months = cat.method_number * cat.method_period | |
|                 if record.move_id in ['out_invoice', 'out_refund']: | |
|                     record.asset_mrr = record.price_subtotal_signed / months | |
|                 if record.move_id.invoice_date: | |
|                     start_date = datetime.strptime( | |
|                         str(record.move_id.invoice_date), DF).replace(day=1) | |
|                     end_date = (start_date + relativedelta(months=months, | |
|                                                            days=-1)) | |
|                     record.asset_start_date = start_date.strftime(DF) | |
|                     record.asset_end_date = end_date.strftime(DF) | |
| 
 | |
|     def asset_create(self): | |
|         """Create function for the asset and its associated properties""" | |
|         for record in self: | |
|             if record.asset_category_id: | |
|                 vals = { | |
|                     'name': record.name, | |
|                     'code': record.move_id.name or False, | |
|                     'category_id': record.asset_category_id.id, | |
|                     'value': record.price_subtotal, | |
|                     'partner_id': record.partner_id.id, | |
|                     'company_id': record.move_id.company_id.id, | |
|                     'currency_id': record.move_id.company_currency_id.id, | |
|                     'date': record.move_id.invoice_date, | |
|                     'invoice_id': record.move_id.id, | |
|                 } | |
|                 changed_vals = record.env[ | |
|                     'account.asset.asset'].onchange_category_id_values( | |
|                     vals['category_id']) | |
|                 vals.update(changed_vals['value']) | |
|                 asset = record.env['account.asset.asset'].create(vals) | |
|                 if record.asset_category_id.open_asset: | |
|                     asset.validate() | |
|         return True | |
| 
 | |
|     @api.depends('asset_category_id') | |
|     def onchange_asset_category_id(self): | |
|         """On change function based on the category and its updates the | |
|         account status""" | |
|         if self.move_id.move_type == 'out_invoice' and self.asset_category_id: | |
|             self.account_id = self.asset_category_id.account_asset_id.id | |
|         elif self.move_id.move_type == 'in_invoice' and self.asset_category_id: | |
|             self.account_id = self.asset_category_id.account_asset_id.id | |
| 
 | |
|     @api.onchange('product_id') | |
|     def _onchange_uom_id(self): | |
|         """Onchange function for product that's call the UOM compute function | |
|          and the asset category function""" | |
|         result = super(AccountInvoiceLine, self)._compute_product_uom_id() | |
|         self.onchange_asset_category_id() | |
|         return result | |
| 
 | |
|     @api.depends('product_id') | |
|     def _onchange_product_id(self): | |
|         """Onchange product values and it's associated with the move types""" | |
|         vals = super(AccountInvoiceLine, self)._compute_price_unit() | |
|         if self.product_id: | |
|             if self.move_id.move_type == 'out_invoice': | |
|                 self.asset_category_id = self.product_id.product_tmpl_id.deferred_revenue_category_id | |
|             elif self.move_id.move_type == 'in_invoice': | |
|                 self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id | |
|         return vals | |
| 
 | |
|     def _set_additional_fields(self, invoice): | |
|         """The function adds additional fields that based on the invoice | |
|         move types""" | |
|         if not self.asset_category_id: | |
|             if invoice.type == 'out_invoice': | |
|                 self.asset_category_id = self.product_id.product_tmpl_id.deferred_revenue_category_id.id | |
|             elif invoice.type == 'in_invoice': | |
|                 self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id.id | |
|             self.onchange_asset_category_id() | |
|         super(AccountInvoiceLine, self)._set_additional_fields(invoice) | |
| 
 | |
|     def get_invoice_line_account(self, type, product, fpos, company): | |
|         """"It returns the invoice line and callback""" | |
|         return product.asset_category_id.account_asset_id or super( | |
|             AccountInvoiceLine, self).get_invoice_line_account(type, product, | |
|                                                                fpos, company) | |
| 
 | |
|     @api.model | |
|     def _query_get(self, domain=None): | |
|         """Used to add domain constraints to the query""" | |
|         self.check_access_rights('read') | |
| 
 | |
|         context = dict(self._context or {}) | |
|         domain = domain or [] | |
|         if not isinstance(domain, (list, tuple)): | |
|             domain = ast.literal_eval(domain) | |
| 
 | |
|         date_field = 'date' | |
|         if context.get('aged_balance'): | |
|             date_field = 'date_maturity' | |
|         if context.get('date_to'): | |
|             domain += [(date_field, '<=', context['date_to'])] | |
|         if context.get('date_from'): | |
|             if not context.get('strict_range'): | |
|                 domain += ['|', (date_field, '>=', context['date_from']), | |
|                            ('account_id.include_initial_balance', '=', True)] | |
|             elif context.get('initial_bal'): | |
|                 domain += [(date_field, '<', context['date_from'])] | |
|             else: | |
|                 domain += [(date_field, '>=', context['date_from'])] | |
| 
 | |
|         if context.get('journal_ids'): | |
|             domain += [('journal_id', 'in', context['journal_ids'])] | |
| 
 | |
|         state = context.get('state') | |
|         if state and state.lower() != 'all': | |
|             domain += [('parent_state', '=', state)] | |
| 
 | |
|         if context.get('company_id'): | |
|             domain += [('company_id', '=', context['company_id'])] | |
|         elif context.get('allowed_company_ids'): | |
|             domain += [('company_id', 'in', self.env.companies.ids)] | |
|         else: | |
|             domain += [('company_id', '=', self.env.company.id)] | |
| 
 | |
|         if context.get('reconcile_date'): | |
|             domain += ['|', ('reconciled', '=', False), '|', | |
|                        ('matched_debit_ids.max_date', '>', context['reconcile_date']), | |
|                        ('matched_credit_ids.max_date', '>', context['reconcile_date'])] | |
| 
 | |
|         if context.get('account_tag_ids'): | |
|             domain += [('account_id.tag_ids', 'in', context['account_tag_ids'].ids)] | |
| 
 | |
|         if context.get('account_ids'): | |
|             domain += [('account_id', 'in', context['account_ids'].ids)] | |
| 
 | |
|         if context.get('analytic_tag_ids'): | |
|             domain += [('analytic_tag_ids', 'in', context['analytic_tag_ids'].ids)] | |
| 
 | |
|         if context.get('analytic_account_ids'): | |
|             domain += [('analytic_account_id', 'in', context['analytic_account_ids'].ids)] | |
| 
 | |
|         if context.get('partner_ids'): | |
|             domain += [('partner_id', 'in', context['partner_ids'].ids)] | |
| 
 | |
|         if context.get('partner_categories'): | |
|             domain += [('partner_id.category_id', 'in', context['partner_categories'].ids)] | |
| 
 | |
|         where_clause = "" | |
|         where_clause_params = [] | |
|         tables = '' | |
|         if domain: | |
|             domain.append(('display_type', 'not in', ('line_section', 'line_note'))) | |
|             domain.append(('parent_state', '!=', 'cancel')) | |
| 
 | |
|             query = self._where_calc(domain) | |
| 
 | |
|             # Wrap the query with 'company_id IN (...)' to avoid bypassing company access rights. | |
|             self._apply_ir_rules(query) | |
|             tables, from_params = query.from_clause | |
|             where_clause, where_params = query.where_clause | |
|             where_clause_params = from_params + where_params | |
|         return tables, where_clause, where_clause_params
 | |
| 
 |