Odoo 15 Search non-stored compute value that depends on search_count of many2one field - odoo

I'm trying to display a view with certain products that have multiple BoM's. I've created a computed field that labels which records should be displayed. I'm trying to create a search function so that the records in interest can be displayed as a filter but am having trouble creating the function.
Currently trying to append record.id's of interest into a list and returning the list within the search domain but that is not working. Any help would be much appreciated. Please see code below and thanks in advance!
I tried the following code but it returns an empty data list. I think there's something wrong with how I'm getting the id of the current record and appending it to the list that is returned.
class products_ppa_bom_check(models.Model):
_inherit = ['product.template']
ppa_multi_bom = fields.Selection([
('true', 'True'),
('false', 'False'),
('na', 'Not Applicable')],
string="PPA Multi BOM Check", compute='_compute_ppa_multi_bom',
search='_search_ppa_multi_bom')
def _compute_ppa_multi_bom(self):
for record in self:
count = record.env['mrp.bom'].search_count(['|', ('product_tmpl_id', '=', record.id), ('byproduct_ids.product_id.product_tmpl_id', '=', record.id)])
if (count > 1) and ('PPA' in str(record.default_code)):
record.ppa_multi_bom = 'true'
elif (count == 1) and ('PPA' in str(record.default_code)):
record.ppa_multi_bom = 'false'
else: record.ppa_multi_bom = 'na'
def _search_ppa_multi_bom(self, operator, value):
ids = []
for record in self:
count = record.env['mrp.bom'].search_count(['|', ('product_tmpl_id', '=', record.id), ('byproduct_ids.product_id.product_tmpl_id', '=', record.id)])
if (count > 1) and ('PPA' in str(record.default_code)):
ids = ids.append(record.id)
return[('id', 'in', ids)]

If you want to use a filter in products with = operator, you can use the below code which I already tested:
You can use bom_count field rather than use search_count method
from odoo import api, fields, models, _
class products_ppa_bom_check(models.Model):
_inherit = ['product.template']
ppa_multi_bom = fields.Selection([
('true', 'True'),
('false', 'False'),
('na', 'Not Applicable')],
string="PPA Multi BOM Check", compute='_compute_ppa_multi_bom',
search='_search_ppa_multi_bom')
def _compute_ppa_multi_bom(self):
for record in self:
if (record.bom_count > 1) and ('PPA' in str(record.default_code)):
record.ppa_multi_bom = 'true'
elif (record.bom_count == 1) and ('PPA' in str(record.default_code)):
record.ppa_multi_bom = 'false'
else:
record.ppa_multi_bom = 'na'
def _search_ppa_multi_bom(self, operator, value):
true_ids = self.env['product.template'].search([]).filtered(
lambda x: x.bom_count > 1 and 'PPA' in str(x.default_code)).ids
false_ids = self.env['product.template'].search([]).filtered(
lambda x: x.bom_count == 1 and x.default_code and 'PPA' in x.default_code).ids
if value == 'true':
ids = true_ids
elif value == 'false':
ids = false_ids
else:
all_ids = self.env['product.template'].search([]).ids
ids = list(set(all_ids) - set(true_ids + false_ids))
return [('id', 'in', ids)]
To add filter to search view:
<record id="product_template_search_view_inherit_bom" model="ir.ui.view">
<field name="name">product.template.search.inherit.bom</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_search_view"/>
<field name="arch" type="xml">
<xpath expr="//filter[#name='consumable']" position="after">
<separator/>
<filter string="Multi BOM" name="ppa_multi_bom" domain="[('ppa_multi_bom', '=', 'true')]"/>
<filter string="One BOM" name="ppa_one_bom" domain="[('ppa_multi_bom', '=', 'false')]"/>
<filter string="NA BOM" name="ppa_na_bom" domain="[('ppa_multi_bom', '=', 'na')]"/>
</xpath>
</field>
</record>

Related

Odoo - How to search by date

I want to search a list of object based on date field
reservations = self.env['rm.reservation'].search([
('check_in', '=', self.check_in)
])
But when I run the Odoo, I get a runtime error
ValueError: Invalid field rm.reservation.check_in in leaf ('check_in', '=', datetime.date(2021, 12, 20))
This is the check_in field declaration in the reservation model class
check_in = fields.Date(string='Check In', required=True,
default=lambda self: fields.date.today())
Sorry this is my fault, I should call
reservations = self.env['rm.reservation.room.line'].search([
('check_in', '=', self.check_in)
])
And this is solve the problem

How to choose invoices and make payment in payment form odoo14

n v14, I want to make invoices payment in payment form by choosing invoices. In v13, already have invoice_ids field and I changed to readonly to 0 and can make payment. But in v14, there is no invoice_ids field.So I create this but how can I do that?I share my some code
invoice_ids = fields.Many2many('account.move', 'account_invoice_payment_rel', 'payment_id', 'invoice_id', string="Invoices", copy=False,
help="""Technical field containing the invoice for which the payment has been generated.
This does not especially correspond to the invoices reconciled with the payment,
as it can have been generated first, and reconciled later""")
My view is
record id="view_account_payment_form_inherit_payment" model="ir.ui.view">
<field name="name">view.account.payment.form.inherit.payment</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form"/>
<field name="arch" type="xml">
<xpath expr="//group" position="after">
<group invisible="context.get('active_model') == 'account.move'">
<field name="invoice_ids" attrs="{'invisible': [('partner_id', '=', False)]}" readonly="1" domain="[('partner_id','child_of',partner_id),('state','=','posted'),('payment_state','=','not_paid')]" >
<tree>
<field name="partner_id"/>
<field name="name"/>
<field name="amount_residual"/>
<field name="state"/>
</tree>
</field>
</group>
<xpath/>
</field>
</record/>
class AccountPayment(models.Model):
_inherit = 'account.payment'
invoice_ids = fields.Many2many('account.move', 'account_invoice_payment_rel', 'payment_id', 'invoice_id', string="Invoices", copy=False,
help="""Technical field containing the invoice for which the payment has been generated.
This does not especially correspond to the invoices reconciled with the payment,
as it can have been generated first, and reconciled later""")
def action_view_move(self):
return {
'name': _('Journal Entries'),
'view_mode': 'tree,form',
'res_model': 'account.move',
'view_id': False,
'type': 'ir.actions.act_window',
'domain': [('id', 'in', self.mapped('move_id').ids)],
'context': {
'journal_id': self.journal_id.id,
}
}
#api.depends('amount')
def _compute_amount_untaxed(self):
rec = []
untaxed_amount = 0.0
for payment in self:
if payment.invoice_ids:
for invoice in payment.invoice_ids:
# untaxed_amount += invoice.amount_untaxed_signed
# if invoice.move_type == 'out_invoice':
# untaxed_amount += invoice.amount_untaxed
# elif invoice.move_type == 'out_refund':
# untaxed_amount -= invoice.amount_untaxed
if invoice.move_type in ['out_invoice','in_refund']:
untaxed_amount += invoice.amount_untaxed
elif invoice.move_type in ['out_refund','in_invoice']:
untaxed_amount -= invoice.amount_untaxed
payment.amount_untaxed = abs(untaxed_amount)
return rec
#api.onchange('invoice_ids')
def _compute_amount(self):
logging.info("======================= compute_amount =================")
logging.info("===== invoice.")
total = 0.0
if self.invoice_ids:
for invoice in self.invoice_ids:
if invoice.move_type in ['out_invoice','in_refund']:
total += invoice.amount_total_signed
elif invoice.move_type in ['out_refund','in_invoice']:
total -= invoice.amount_total_signed
self.amount = total
def action_post(self):
res = super(AccountPayment, self).action_post()
# logging.info("=========================== action_post start here")
# logging.info(res)
# logging.info(self)
for payment_res in self:
# logging.info("-------- payment_res")
# logging.info(payment_res)
# logging.info(payment_res.amount)
# logging.info(payment_res.invoice_ids)
if payment_res.invoice_ids:
moves_to_reconcile = []
# for move in payment_res.move_id.line_ids:
# logging.info("============ before_moves_to_reconcile =================")
# logging.info(partner_account)
# logging.info(payment_res)
# logging.info(payment_res.display_name)
# logging.info(payment_res.move_id)
# logging.info(payment_res.move_id.display_name)
# logging.info(move)
# logging.info(move.display_name)
# logging.info(move.account_id)
# logging.info(move.account_id.display_name)
for move in payment_res.move_id.line_ids:
# logging.info("**************************")
# logging.info(move.display_name)
# logging.info(move.account_id.id)
# logging.info(move.account_id.display_name)
if move.account_id.id == partner_account:
moves_to_reconcile = []
moves_to_reconcile.append(move.id)
# logging.info("============ moves_to_reconcile1 =================")
# logging.info(moves_to_reconcile)
for invoice in payment_res.invoice_ids:
for move in invoice.line_ids:
# logging.info("------------------------------------")
# logging.info(partner_account)
# logging.info(move.account_id.id)
# logging.info("------------------------------------")
if move.account_id.id == partner_account:
moves_to_reconcile.append(move.id)
# if moves_to_reconcile:
# logging.info("============ moves_to_reconcile2 =================")
# logging.info(moves_to_reconcile)
move_lines = self.env['account.move.line'].search([('id','in',moves_to_reconcile)])
move_lines.reconcile()
# logging.info("=========================== action_post end here")
return res

Odoo 9 : How to pass parameters to query (display result in tree view) via wizard

I have this wizard where I select date :
<record id="wizard_forecast_invoice_date_form" model="ir.ui.view">
<field name="name">wizard.forecast.invoice.date.form</field>
<field name="model">custom_accounting.wizard_forecast_due_collection</field>
<field name="arch" type="xml">
<form string="Date for Forecast Due Collection">
<separator string="Date for Forecast Due Collection"/>
<label string="This will list all open customer invoices that are on or before the Due Date selected"/>
<group>
<field name="before_date"/>
</group>
<footer>
<button name="forecast_due_collection" string="Okay" type="object" class="btn-primary" context="{'before_date': before_date}"/>
<button special="cancel" string="Cancel" class="btn-default"/>
</footer>
</form>
</field>
</record>
Where I want send this date value to new class like this :
class WizardForecastDueCollection(models.TransientModel):
_name='custom_accounting.wizard_forecast_due_collection'
before_date = fields.Date(string='Before Date', required=True, default=fields.Date.context_today)
#api.multi
def forecast_due_collection(self):
ac = self.env['ir.model.data'].xmlid_to_res_id('custom_accounting.view_forecast_invoice_date_report_pivot')
return {
'name': 'ForecastInvoiceDateReport',
'view_type': 'form',
'res_model': 'custom_accounting.forecast_invoice_date_report',
'view_id': ac,
'context': {'default_before_date': self.before_date},
'type': 'ir.actions.act_window',
'view_mode': 'pivot',
'domain': [('date_invoice', '<=', self.before_date)]
}
And here's the class which should receive the value to execute the query :
class ForecastInvoiceDateReport(models.Model):
_name = "custom_accounting.forecast_invoice_date_report"
_description = "Forecast Invoices Date Report"
date_maturity = fields.Date(string='Due Date', readonly=True)
date_invoice = fields.Date(string='Invoice Date', readonly=True)
before_date = fields.Date(store=False, default=lambda s: fields.Date.context_today(s))
# account_id = fields.Many2one('account.account', string='Account', readonly=True, domain=[('deprecated', '=', False)])
country = fields.Char('Country', readonly=True)
sales_person_name = fields.Char('Sales Person', readonly=True)
partner_name = fields.Char('Customer', readonly=True)
state = fields.Char('State', readonly=True)
city = fields.Char('City', readonly=True)
debit = fields.Float("Debit", readonly=True)
credit = fields.Float("Credit", readonly=True)
amount_residual = fields.Float("Balance", digits_compute=dp.get_precision('accounting_financial_report_dp'),
readonly=True)
duration = fields.Char('Duration', readonly=True)
invoice_number = fields.Char('Invoice Number', readonly=True)
_auto = False
_rec_name = 'date_maturity'
_depends = {
'account.move': ['id', 'name'],
'account.move.line': ['move_id', 'date_maturity'],
'res.currency.rate': ['currency_id', 'name'],
'res.partner': ['country_id', 'state_id', 'city'],
'account.invoice': ['date_invoice'],
}
def _select(self):
select_str = """
SELECT
row_number() OVER () as id, duration, date_invoice, date_maturity,
country,state,city, sales_person_name, concat(partner_name,'(', Payment_Term, ')') partner_name ,
balance,amount_residual, debit,credit,invoice_number
From
(
SELECT
case
when "account_move_line".date_maturity is null Then 'No Date'
when (%s-ai.date_invoice) <30 then 'b# 0-30 days'
else 'Older'
END as duration, ai.date_invoice as date_invoice, "account_move_line".date_maturity as date_maturity,
res_country.name as country,res_country_state.name as state,res_partner.city as city,
new_rp.name as "sales_person_name", res_partner.name as "partner_name", res_partner.id as "partner_id1",
COALESCE(SUM("account_move_line".balance), 0) AS balance,
COALESCE(SUM("account_move_line".amount_residual), 0) AS amount_residual,
COALESCE(SUM("account_move_line".debit), 0) AS debit,
COALESCE(SUM("account_move_line".credit), 0) AS credit,
"account_move_line__move_id".name AS invoice_number
FROM "account_move" as "account_move_line__move_id","account_move_line"
LEFT JOIN res_partner on "account_move_line".partner_id = res_partner.id
LEFT JOIN res_country on res_partner.country_id = res_country.id
LEFT JOIN res_country_state on res_partner.state_id = res_country_state.id
LEFT JOIN res_users on res_partner.user_id = res_users.id
LEFT JOIN res_partner as new_rp on res_users.partner_id = new_rp.id
INNER JOIN account_account as aa on "account_move_line"."account_id"=aa.id
INNER JOIN account_invoice as ai on "account_move_line"."invoice_id"=ai.id
INNER JOIN account_account_type as aat on aat.id = aa.user_type_id
WHERE ("account_move_line"."move_id"="account_move_line__move_id"."id")
AND ((((
(aat.type = 'receivable') and account_move_line__move_id.state='posted' and
("account_move_line"."reconciled" IS NULL or "account_move_line"."reconciled" = false ))
) AND ("account_move_line__move_id"."state" = 'posted'))
) GROUP BY
case
when "account_move_line".date_maturity is null Then 'No Date'
when (%s-ai.date_invoice) <30 then 'b# 0-30 days'
else 'Older'
END
, new_rp.name , res_partner.name, res_country.name,res_country_state.name,res_partner.city,res_users.login,
"account_move_line".date_maturity,"account_move_line__move_id".name,ai.date_invoice,res_partner.id
order by 3
) as q1
left join
(
SELECT Substr(res_id,13) partner_id2,Substr(value_reference,22) Payment_Term_Id,pt.name Payment_Term
FROM public.ir_property ir join account_payment_term pt on pt.id = cast(Substr(value_reference,22) as integer)
where ir.name ='property_payment_term_id'
) as q2 on q1.partner_id1 = cast(q2.partner_id2 as integer)
""" %(self.before_date, self.before_date)
return select_str
_table = 'custom_forecast_invoices_date_view'
def init(self, cr):
# self._table = account_invoice_report
tools.drop_view_if_exists(cr, self._table)
cr.execute("""CREATE or REPLACE VIEW %s as (
WITH currency_rate AS (%s)
%s
)""" % (
self._table, self.pool['res.currency']._select_companies_rates(),
self._select()))
It works fine if I replace the field before_date by current_date in sql query, But if I set parameters instead, I can't get the expected value.
I got it,
Just run the query in the first class of wizard, that's all :)

Load Country -> State -> City depencency in Odoo

How can we create dependent selection of Country->State->City in Odoo?
For example -
Selected Country = United States
which will load All state of US
State = Texas, California, Ohio, .. etc,
Selected state = Texas
On Selection of State, it will load all Cities in selected state.
City = Austin, Huston, ..etc.
How can we achieve this in Odoo?
I have created below code in model.py
country = fields.Many2one('res.country',string='Country', help='Select Country')
state = fields.Many2one('state.country',string='State', help='Enter State')
city = fields.Char('City', help='Enter City')
view.xml file is having just below code:
<field name="country"/>
<field name="state"/>
<field name="city"/>
state_id = fields.Many2one("res.country.state", string='State', help='Enter State', ondelete='restrict')
country_id = fields.Many2one('res.country', string='Country', help='Select Country', ondelete='restrict')
city = fields.Char('City', help='Enter City')
hide = fields.Boolean(string='Hide', compute="_compute_hide")
# Dependent picklist code to show State based on selected Country E.g India -> Gujarat, Maharastra, Rajasthan, etc..
#api.onchange('country_id')
def _onchange_country_id(self):
if self.country_id:
return {'domain': {'state_id': [('country_id', '=', self.country_id.id)]}}
else:
return {'domain': {'state_id': []}}
# Show Hide State selection based on Country
#api.depends('country_id')
def _compute_hide(self):
if self.country_id:
self.hide = False
else:
self.hide = True
# view.xml
<field name="hide" invisible="1"/>
<field name="country_id" options="{'no_quick_create': True, 'no_create_edit' : True}"/>
<field name="state_id" options="{'no_quick_create': True, 'no_create_edit' : True}" attrs="{'invisible':[('hide', '=', True)]}"/>
<field name="city"/>

how can i use function value in Domain filter

I am getting current login user id by following function
def _get_user_name(self, cr, uid, *args):
user_obj = self.pool.get('res.users')
user_value = user_obj.browse(cr, uid, uid)
return user_value.id or False
and now i want to use its value in this field's Domain like ....
x_trainer_id = fields.Many2one('res.partner', string='Trainer',domain=[('user_id.id','=','get_user_name')])
How is it possible? I'll be very thankful....
you can do it as below:
x_trainer_id = fields.Many2one('res.partner', string='Trainer',domain=lambda self: [('id', '=', self.env.uid)])
pass domain=lambda self: [('id', '=', self.env.uid)]