i'm using odoo 11. i have create a custom module for attendance modification request which be approuved by the manager of attendance . My goal is to limit the acces to the modification of attendance and when the manager press approuve "hr.attendance" will be modified automatically whith the new values of check_in and check_out (if it's the same employee and same date between "hr.attendance" and my request modification). The problem is when i press approuve there is no error but in the same time there is no modification.
Here is my code. Any idea for help please ?
modification_request.xml
<record model="ir.ui.view" id="view_attendance_modification_request_form">
<field name="name">attendance.modification.request.form</field>
<field name="model">attendance.modification.request</field>
<field name="arch" type="xml">
<form string="Attendance modification Request">
<header>
<field name="state" statusbar_visible="draft,waiting,approved,cancel" widget="statusbar" />
<button name="submit_modification" string="Submit for manager" type="object" class="btn-primary"
attrs="{'invisible': [('state','not in','draft')]}"/>
<button name="modification_approval" type="object" string="Approve" class="oe_highlight"
groups="hr_attendance.group_hr_attendance_manager"
attrs="{'invisible': [('state','not in','waiting')]}"/>
<button name="modification_rejection" type="object" string="Cancel" class="oe_highlight"
groups="hr_attendance.group_hr_attendance_manager"
attrs="{'invisible': [('state','not in','waiting')]}"/>
</header>
<sheet>
<h2>
<group>
<field name="employee_id"/>
</group>
</h2>
<group col="4" colspan="4">
<field name="time_check_in_1"/>
<field name="time_check_out_1"/>
</group>
<label for="note"/>
<field name="note"/>
</sheet>
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
</form>
</field>
</record>
modification_request.py
class AttendanceModificationRequest(models.Model):
_name = 'attendance.modification.request'
_description = 'Attendance modification Request'
_inherit = ['mail.thread', 'mail.activity.mixin']
def _get_employee_id(self):
employee_rec = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
return employee_rec.id
employee_id = fields.Many2one('hr.employee',"Employee", readonly=True,default=_get_employee_id, required=True)
user_id = fields.Many2one('res.users', string='User', track_visibility='onchange', readonly=True,
states={'draft': [('readonly', False)]}, default=lambda self: self.env.user)
state = fields.Selection([
('draft', 'Pending'),
('waiting', 'Waiting for approval'),
('approved', 'Approved'),
('cancel', 'Cancelled')], readonly=True,
help="Gives the state of the attendance request modification .",
default='draft')
modification_date = fields.Date("Date")
time_check_in_1 = fields.Datetime("Check in")
time_check_out_1 = fields.Datetime("Check out")
note = fields.Text("Note")
attendance_id = fields.Many2one('hr.attendance', string='Attendance')
#api.multi
def modification_approval(self):
attend_signin_ids = self.env['hr.attendance']
check_in_date = datetime.strptime(self.time_check_in_1, "%Y-%m-%d %H:%M:%S").date()
check_out_date = datetime.strptime(self.time_check_out_1, "%Y-%m-%d %H:%M:%S").date()
for record in self:
attendance_check_in_date = datetime.strptime(record.attendance_id.check_in, "%Y-%m-%d %H:%M:%S").date()
attendance_check_out_date = datetime.strptime(record.attendance_id.check_out, "%Y-%m-%d %H:%M:%S").date()
if (record.attendance_id.employee_id == self.employee_id) and (check_in_date == attendance_check_in_date):
record.attendance_id.check_in = self.time_check_in_1
record.attendance_id.check_out = self.time_check_out_1
return self.write({
'state': 'approved'
})
since attendance_ids is a group of people. attendance_id = fields.Many2one('hr.attendance', string='Attendance') is an issue.
Because m2o can't refer to a group of people.
attendance_id = fields.One2many('hr.attendance','keyfield_in_hr_attendance' ,string='Attendance') is correct.
And keyfield_in_hr_attendance is a many2one field refer to attendance.modification.request model.
Related
I need to download files in zip format.
I wrote code that for some reason does not work.
I'm trying to do it with controller
attachment.py
from odoo import api, fields, models, _
from odoo.odoo.exceptions import UserError
class IrAttachment(models.Model):
_inherit = ["ir.attachment", "sale.order.line"]
def download_product_attachments(self):
attachment_id = self.datas
if attachment_id:
return {"type": "ir.actions.act_url",
"url": "/download_attachments?attachment_id={}".format(
",".join([str(elem) for elem in attachment_id.ids])),
"target": "new",
"res_id": self.id,
}
else:
raise UserError("Photos were not found")
contriller/main.py
class DownloadZipFile(http.Controller):
#http.route("/download_attachments", type="http", auth="user", website=True)
def download_attachments_product_routes(self, **data):
"""Method compose data with attachments and send for download."""
attachments_ids = [int(x) for x in data["attachment_id"].split(',')]
attachments_items = request.env["ir.attachment"].search([("id", "in", attachments_ids)])
in_memory = BytesIO()
zip_archive = ZipFile(in_memory, "w")
for attachment in attachments_items:
zip_archive.writestr(attachment.filename, base64.b64decode(attachment.image))
zip_archive.close()
res = http.send_file(in_memory, filename="attachments.zip", as_attachment=True)
return res
When I try to go to the /download_attachments. I get an error
File "/home/user/PycharmProjects/Odoo14/custom/first_model/controllers/main.py", line 32, in download_attachments_product_routes
attachments_ids = [int(x) for x in data["attachment_id"].split(',')]
KeyError: 'attachment_id'
What's wrong with me?
I found a solution to my question.
sale.py
class SaleOrder(models.Model):
_inherit = "sale.order"
attachment = fields.Many2one('ir.attachment')
def download_product_attachments(self):
return {"type": "ir.actions.act_url",
"url": "/download_attachments?res_id={}".format(self.id),
}
controllers/main.py
class DownloadZipFile(http.Controller):
#http.route("/download_attachments/", type="http", auth="user", website=True)
def download_attachments_product_routes(self, **data):
"""Method compose data with attachments and send for download."""
attachments_items = request.env["ir.attachment"].search(
[("res_id", "=", data.get('res_id')), ('res_model', '=', 'sale.order')])
in_memory = BytesIO()
zip_archive = ZipFile(in_memory, "w")
for attachment in attachments_items:
zip_archive.writestr(attachment.name, base64.b64decode(attachment.datas))
zip_archive.close()
res = http.send_file(in_memory, filename="attachments.zip", as_attachment=True)
return res
sale.xml
<record id="view_order_form_inherit" model="ir.ui.view">
<field name="name">sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//header" position="inside">
<button name="download_product_attachments" type="object" string="Download all files"/>
</xpath>
</field>
</record>
Create a sale order and add a couple of items. After clicking on the "Confirm" button the delivery "Delivery" will be created. All items from the sale order will be in delivery.
You need to add the express delivery sign to the sale order (bool).
Example: Add 5 items A B C(express delivery) D E(express delivery) to the sale order. After sale order confirmation two deliveries should be created: the first delivery should contain positions A, B and D; the second delivery (express delivery) should contain positions C and E.
I added the button. and now with the debugger I reached the function def _action_launch_stock_rule(self, previous_product_uom_qty=False) in odoo/addons/sale_stock/models/sale_order.py
I don't know what to do next. I can't understand at what stage (in which function) the data is thrown to delivery.
And there I need to write the logic. If we have Express delivery then I have to divide it into two deliveries.
sale.py
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
express_delivery = fields.Boolean(string='Express delivery')
sale.xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_order_form_inherit" model="ir.ui.view">
<field name="name">sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[#name='order_line']/tree/field[#name='qty_delivered']" position="after">
<field name="express_delivery" />
</xpath>
</field>
</record>
</odoo>
Maybe someone can help me understand?
I found a solution to this problem
sale.py
class SaleOrderLine(models.Model):
_name = "sale.order.line"
_inherit = "sale.order.line"
express_delivery = fields.Boolean(string='Express delivery')
def _prepare_procurement_values(self, group_id=False):
res = super(SaleOrderLine, self)._prepare_procurement_values(group_id)
res.update({'express_delivery': self.express_delivery})
return res
stock_move.py
from odoo import models, fields
from itertools import groupby
class StockMoveInherit(models.Model):
_inherit = 'stock.move'
express_delivery = fields.Boolean()
def _search_picking_for_assignation(self):
self.ensure_one()
picking = self.env['stock.picking'].search([
('group_id', '=', self.group_id.id),
('location_id', '=', self.location_id.id),
('location_dest_id', '=', self.location_dest_id.id),
('picking_type_id', '=', self.picking_type_id.id),
('printed', '=', False),
('express_delivery', '=', self.express_delivery), # Добавляю поле
('immediate_transfer', '=', False),
('state', 'in', ['draft', 'confirmed', 'waiting', 'partially_available', 'assigned'])], limit=1)
return picking
def _assign_picking(self):
Picking = self.env['stock.picking']
grouped_moves = groupby(sorted(self, key=lambda m: [f.id for f in m._key_assign_picking()]),
key=lambda m: [m._key_assign_picking(), m.express_delivery])
for group, moves in grouped_moves:
moves = self.env['stock.move'].concat(*list(moves))
new_picking = False
picking = moves[0]._search_picking_for_assignation()
if picking:
if any(picking.partner_id.id != m.partner_id.id or
picking.origin != m.origin for m in moves):
picking.write({
'partner_id': False,
'origin': False,
})
else:
new_picking = True
picking = Picking.create(moves._get_new_picking_values())
picking.write({'express_delivery': moves[0].express_delivery}) # Добавляю поле
moves.write({'picking_id': picking.id})
moves._assign_picking_post_process(new=new_picking)
return True
stock_picking.py
from odoo import fields, models, api
class StockMoveInherit(models.Model):
_name = 'stock.picking'
_inherit = 'stock.picking'
express_delivery = fields.Boolean(default=False)
stock_rule.py
from odoo import api, fields, models
class StockRuleInh(models.Model):
_inherit = 'stock.rule'
def _get_stock_move_values(self, product_id, product_qty, product_uom, location_id, name, origin, company_id,
values):
res = super(StockRuleInh, self)._get_stock_move_values(product_id, product_qty, product_uom, location_id,
name, origin, company_id, values)
res['express_delivery'] = values.get('express_delivery', False)
return res
stock_picking_view.xml
<?xml version="1.0"?>
<odoo>
<record id="stock_picking_view_form_inherit" model="ir.ui.view">
<field name="name">stock.picking.view.form.inherit</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">
<xpath expr="//group/field[#name='origin']" position="after">
<field name="express_delivery" attrs="{'readonly':[True]}" />
</xpath>
</field>
</record>
<record id="vpicktree_inherit" model="ir.ui.view">
<field name="name">stock.picking.tree</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.vpicktree"/>
<field name="arch" type="xml">
<xpath expr="//tree/field[#name='user_id']" position="after">
<field name="express_delivery"/>
</xpath>
</field>
</record>
</odoo>
sale.xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_order_form_inherit" model="ir.ui.view">
<field name="name">sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[#name='order_line']/tree/field[#name='qty_delivered']" position="after">
<field name="express_delivery" />
</xpath>
</field>
</record>
</odoo>
i was building a custom wizard and i get this error while refreshing my module in odoo
i want to build a wizard and get the data entered in wizard to another fields.
how to do that..?
Thanks in advance
from odoo import fields, models, api
class CreateExam(models.TransientModel):
_name = 'exam.wizards'
_description = 'Create exams'
std_wiz = fields.Many2one(
comodel_name='std.record',
string='Student',
required=False)
std_subject = fields.Many2one('std.subject',string="Subject")
std_marks=fields.Float(string="Marks")
def save_btn(self):
print("saved")
return True
This is my xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="examwiz_view_form" model="ir.ui.view">
<field name="name">exam_view_form</field>
<field name="model">exam.wizards</field>
<field name="arch" type="xml">
<form string="exam form">
<sheet>
<group>
<field name="std_wiz"/>
<field name="std_subject"/>
<field name="std_marks"/>
</group>
</sheet>
<footer>
<button name="save_btn" string="save" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="examwiz_action" model="ir.actions.act_window">
<field name="name"></field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">exam.wizards</field>
<field name="view_mode">form</field>
<field name="view_id" ref="examwiz_view_form"/>
<field name="target">new</field>
</record>
<!-- This Menu Item must have a parent and an action -->
<menuitem id="examwiz_categ" name="Create Exam" parent="school_root_menu" action="examwiz_action" sequence="5"/>
</data>
</odoo>
error log
2022-02-19 13:10:25,416 18668 ERROR alfikodoo odoo.modules.registry: Failed to load registry
2022-02-19 13:10:25,416 18668 CRITICAL alfikodoo odoo.service.server: Failed to initialize database `alfikodoo`.
Traceback (most recent call last):
File "C:\Users\alfik\PycharmProjects\pythonProject\odoo11\odoo\service\server.py", line 1199, in preload_registries
registry = Registry.new(dbname, update_module=update_module)
File "C:\Users\alfik\PycharmProjects\pythonProject\odoo11\odoo\modules\registry.py", line 89, in new
odoo.modules.load_modules(registry._db, force_demo, status, update_module)
File "C:\Users\alfik\PycharmProjects\pythonProject\odoo11\odoo\modules\loading.py", line 503, in load_modules
env['ir.model.data']._process_end(processed_modules)
File "C:\Users\alfik\PycharmProjects\pythonProject\odoo11\odoo\addons\base\models\ir_model.py", line 2296, in _process_end
record.unlink()
File "C:\Users\alfik\PycharmProjects\pythonProject\odoo11\odoo\addons\base\models\ir_model.py", line 1370, in unlink
self._process_ondelete()
File "C:\Users\alfik\PycharmProjects\pythonProject\odoo11\odoo\addons\base\models\ir_model.py", line 1418, in _process_ondelete
ondelete = (field.ondelete or {}).get(selection.value)
AttributeError: 'str' object has no attribute 'get'
Set ondelete attribute for many2one field. From Odoo documentation
ondelete (str) – what to do when the referred record is deleted; possible values are: 'set null', 'restrict', 'cascade'
For more information please visit Odoo official documentation about many2one field. For example,
std_wiz = fields.Many2one(
comodel_name='std.record',
string='Student',
required=False, ondelete='cascade')
If you're making an odoo module and you have a test document of that model saved in the database, and you then change the model, adding a Many2one field, then "upgrade" the app in Odoo, you will get this message. I believe it's related to the record that was created before the Many2one field was added.
Solution for me was to "uninstall" the app in odoo, which cleared the test documents, and then install it again.
I have two model:
class Requisition(models.Model):
'''
This module is responsible for all of the requisition related operations.
'''
_name = 'mir.requisition'
_description = 'Mir Requisition'
name = fields.Char('Requisition Name', required=True)
company_id = fields.Many2one('res.company', string='Company')
requisition_line_ids = fields.One2many('mir.requisition.line', 'requisition_id', string='Requisition Line')
class RequisitionLine(models.Model):
'''
This module is responsible for all of the requisition line item related operations.
'''
_name = 'mir.requisition.line'
_description = 'Mir Requisition Line'
product_id = fields.Many2one(
'product.product', 'Product', required=True)
product_qty = fields.Float(
'Quantity',
digits=dp.get_precision('Product Unit of Measure'), default=0, required=True)
product_uom_id = fields.Many2one(
'product.uom', 'Unit of Measure',
oldname='product_uom', required=True)
delivery_date = fields.Date(string='Delivery Date', required=True)
delivery_location = fields.Many2one('stock.location', 'Warehouse Location', required=True)
requisition_id = fields.Many2one('mir.requisition', string='Mir Requisition Reference', index=True, ondelete='cascade')
status = fields.Selection([
('draft', 'Draft'),
('in_progress', 'In Progress'),
('approved', 'Approved'),
('cancel', 'Cancel'),
], 'draft')
#api.onchange('product_id')
def _product_onchange(self):
product = self.product_id
self.product_uom_id = self.product_id.uom_id.id
return {'domain': {'product_uom': [('category_id', '=', product.uom_id.category_id.id)]}}
and view is:
<!--Requisition Tree View-->
<record id="mir_requisition_tree" model="ir.ui.view">
<field name="name">Requisition</field>
<field name="model">mir.requisition</field>
<field name="arch" type="xml">
<tree string="Requisition">
<field name="name"/>
<field name="company_id"/>
<field name="create_uid" string="Created By"/>
<field name="create_date" string="Created Date"/>
</tree>
</field>
</record>
Currently this view showing data form parent model mir.requisition. But i want to display both model data in a single view. Any help will be appreciated.
You should take a look the invoice_form definition, it works with 'account.invoice' and 'account.invoice.line' models. Its something like this:
<!--Requisition Tree View-->
<record id="mir_requisition_tree" model="ir.ui.view">
<field name="name">Requisition</field>
<field name="model">mir.requisition</field>
<field name="arch" type="xml">
<form string="Requisition">
<field name="name"/>
<field name="company_id"/>
<field name="create_uid" string="Created By"/>
<field name="create_date" string="Created Date"/>
<field name="requisition_line_ids" nolabel="1" widget="one2many_list" >
<tree string="Requisition Lines" editable="bottom">
<!-- 'mir.requisition.line' fields -->
</tree>
</field>
</form>
</field>
</record>
I hope this answer can be helful for you.
I have to make Purchase Order Line as editable in Odoo 8. Currently, the field order_line in Purchase.Order Model has modifier as below:
'order_line': fields.one2many('purchase.order.line', 'order_id', 'Order Lines',
states={'approved':[('readonly',True)],
'done':[('readonly',True)]},
copy=True)
So the states is readonly if approved or done. I want to remove this. I tried with below:
<field name="order_line" position="attributes">
<attribute name="readonly">0</attribute>
</field>
Also,
<xpath expr="//field[#name='order_line']" position="attributes">
<attribute name="readonly">0</attribute>
</xpath>
But It does not work.
Please help
Thanks,
UPDATE:
class PurchaseOrder(models.Model):
'''
classdocs
'''
_name = 'purchase.order'
_inherit = 'purchase.order'
total_cases = fields.Integer('Total Cases', default=None)
appointment_number = fields.Char('Appointment Number', default=None)
order_line = fields.One2many('purchase.order.line', 'order_id', 'Order Lines', copy=True)
I overrided the field order_line as above, But nothing happens
Just inherit from the model and define the field again to override it, then you can remove states totally
from openerp import fields, models
class custom_purchase_order(models.Model):
_inherit = 'purchase.order'
order_line = fields.One2many('purchase.order.line', 'order_id', 'Order Lines', states={}, copy=True)