当前位置:首页>python>中篇Python(ODOO)篇 第四章 ODOO项目优化(五)教练预约单

中篇Python(ODOO)篇 第四章 ODOO项目优化(五)教练预约单

  • 2026-10-11 07:11:48
中篇Python(ODOO)篇 第四章 ODOO项目优化(五)教练预约单

预约单子模块数据来自预约单,指定教练和预约日,列出该教练当日所有预约信息。关键字是教练编号+年月日,这个子模块,采用按钮生成方式,在窗口放两个按钮。

一个是基于教练生成,即选择教练和日期后,点击按钮,则自动生成该教练和该日所有预约单数据。

一个是基于日期生成,即选择日期后,点击按钮,则自动生成所有教练该日所有预约单数据。

预约情况

学员姓名:

王小二

手机:

1862323

日期:

2020/8/1

预约时间:

7:00:00

至

9:59:59

排档类:

手动挡

金额:

220

自备车:

否

上车地点:

上海浦东大道1111号

下车地点:

上海浦东大道22号

教练员

工号:

001

姓名:

顾总

车辆信息

车牌:

沪A7868

类型:

桑塔纳3000型

实际情况

学员姓名:

王小二

手机:

1862323

日期:

2020/8/1

陪驾时间:

7:00:00

至

9:59:59

排档类:

手动挡

金额:

220

自备车:

否

上车地点:

上海浦东大道1111号

下车地点:

上海浦东大道22号

教练员

工号:

001

姓名:

顾总

车辆信息

车牌:

沪99900A

类型:

桑塔纳3000型

新增数据模型

在models目录下新增teacher_appointment.py数据模型文件,代码如下:

from datetime import datetime, timedeltafrom odoo import fields, models, apiclass NebulaTeacherAppointment(models.Model):    _name = "nebula.teacher.appointment"    _description = "教练预约单"    _order = 'name'    active = fields.Boolean('是否有效', default=True)    name = fields.Char('教练预约简情', size=30)    appointment_date = fields.Date('预约日期', default=datetime.now())    teacher_name = fields.Many2one('nebula.teacher', string='教练工号',                                   size=8, required=True,                                   domain=[('active', '=', True)])    teacher_full_name = fields.Char('教练姓名', related='teacher_name.full_name',                                    store=True)    teacher_mobile = fields.Char('教练手机', related='teacher_name.mobile')    date_docket = fields.Datetime('单据日期', required=True, readonly=True,                                  index=True, default=fields.Datetime.now)    user_id = fields.Many2one('res.users', string='创建人', index=True,                              readonly=True, default=lambda self: self.env.user)    order_line = fields.One2many('nebula.teacher.appointment.line', 'order_id',                                 string='预约明细', auto_join=True)    _sql_constraints = [('check_uniq_name', 'unique(appointment_date, name)', '一个教练一个日期预约单')]class TeacherAppointmentLine(models.Model):    _name = 'nebula.teacher.appointment.line'    _description = '预约明细'    @api.model    def _select_car_type(self):        records = self.env['nebula.car.type'].search([('active', '=', True)])        return [(r.name, r.name_type) for r in records]    def _select_auto_type(self):        records = self.env['nebula.auto.type'].search([])        return [(r.name, r.name_type) for r in records]    @api.depends('complete_begin_date', 'complete_hours')    def _calc_complete_end_date(self):        for order in self:            if order.complete_begin_date:                begin_date = order.complete_begin_date                add_hours = order.complete_hours                begin_date += timedelta(hours=add_hours)                begin_date -= timedelta(seconds=1)                order.complete_end_date = begin_date    order_id = fields.Many2one('nebula.teacher.appointment', string='预约明细行',                               required=True,                               ondelete='cascade', index=True, copy=False)    appointment_name = fields.Many2one('nebula.appointment', string='预约单',                                       index=True, size=8)    auto_type_name = fields.Selection(selection='_select_auto_type',                                      string='预约类型', related='appointment_name.auto_type_name')    student_name = fields.Many2one('nebula.student', string='学员姓名',                                   index=True, size=8, related='appointment_name.student_name')student_mobile = fields.Char('学员手机', related='student_name.mobile')appointment_begin_date = fields.Datetime('预约起始时间', related='appointment_name.appointment_begin_date')    appointment_hours = fields.Integer('预约小时数', related='appointment_name.appointment_hours')    appointment_end_date = fields.Datetime('预约结束时间', related='appointment_name.appointment_end_date')    complete_begin_date = fields.Datetime('实际起始时间')    complete_hours = fields.Integer('实际小时数')    complete_end_date = fields.Datetime('实际结束时间', compute='_calc_complete_end_date',                                        store=True)    car_name = fields.Many2one('nebula.car', string='车辆编号',                               size=8, related='appointment_name.car_name',                               domain=[('active', '=', True)])    license_plate = fields.Char('车辆牌照', related='car_name.license_plate')    car_type_name = fields.Selection(selection='_select_car_type', string='车型',                                     related='car_name.car_type_name')    car_auto_type_name = fields.Selection(selection='_select_auto_type',                                          string='排挡类',                                          related='car_name.auto_type_name')    work_charge_hour = fields.Integer('每小时收费', related='appointment_name.work_charge_hour')    deposit = fields.Integer('学员缴费')    begin_address = fields.Text('上车地点', related='appointment_name.begin_address')    end_address = fields.Text('下车地点', related='appointment_name.end_address')note = fields.Text('备注', related='appointment_name.note')

将teacher_appointment.py添加到 models目录下__init__.py文件中import部分,以逗号分割文件名。

设置访问权限

在peijia->security目录下的ir.model.access.csv新增权限的记录。

access_nebula_teacher_appointment,nebula.teacher.appointment,model_nebula_teacher_appointment,group_peijia_manager,1,1,1,1access_nebula_teacher_appointment_line,nebula.teacher.appointment.line,model_nebula_teacher_appointment_line,group_peijia_manager,1,1,1,1

创建视图层

在views目录新增teacher_appointment_views.xml文件,暂时以默认方式展示即可,内容如下:

<?xml version="1.0" encoding="utf-8"?><odoo>    <act_windowid="peijia.action_teacher_appointment_views"name="教练预约单"    res_model="nebula.teacher.appointment" view_mode="tree,form" /></odoo>

修改peijia目录下__manifest__.py文件中data段,在views/car_views.xml前新增views/teacher_appointment_views文件名。

在views目录下car_views.xml文件,教练管理下添加菜单指向该子模块,代码:

<menuitem id="menu_teacher_appointment_views" name="教练预约单"          parent="menu_peijia_teacher_data" sequence="105"          action="peijia.action_teacher_appointment_views"/>

全部修改完成后,重启odoo服务。

name自动赋值

name设计为教练编号+日期,当教练编号和日期变化后,name自动变化。

我们在数据模型NebulaTeacherAppointment添加以下代码。

@api.onchange('teacher_name', 'appointment_date')def _onchange_name_date(self):    if self.appointment_date and self.teacher_name:        self.name = _make_name(self.appointment_date, self.teacher_name.name, self.teacher_name.full_name)

公用函数:

def _make_name(appointment_date, teacher_name, teacher_full_name):    # 传入参数,生成默认name    order_date = appointment_date + timedelta(hours=8)    order_text = datetime.strftime(order_date, "%Y-%m-%d")    record_name = '(' + teacher_name + ')'    record_name += teacher_full_name + '^'    record_name += order_text    return record_name

效果见下图,当教练工号和预约日期变化时自动更新教练预约简情字段。

完善视图

将teacher_appointment_views.xml文件中act_window段删除,参考费用管理子模块修改,请读者自行完成,如果完成不了,最好从头再学!

另外为子表在views目录下新建视图文件teacher_appointment_lines_views.xml,并将该文件名添加到__manifest__.py的data段里面。该代码也请参考费用管理子模块修改。

子模块完整代码会在本节未贴出。

另外,演示了如何在视图中屏蔽教练、学员、陪驾单号的新建、修改等功能。关键点是添加options参数,如下例:

<fieldname="teacher_name"options="{'no_open': True, 'no_create': True}"/>

生成预约单按钮事件

我们在teacher_appointment_views.xml视图文件中添加按钮。

<form string="表单">    <header>        <button name="button_teacher_time" type="object"                string="指定教练本日预约" class="oe_highlight"/>        <button name="button_all_time" type="object"                string="所有教练本日预约" class="oe_highlight"/>    </header> 

在teacher_appointment.py数据模型文件中NebulaTeacherAppointment类最末段添加按钮事件。

def button_teacher_time(self):    """        功能: 生成指定教练本日预约。              从传入的self中得到指定的教练和日期,删除旧子表,再创建新子表        1.调插入子表程序    """    # todo : 应该有时间判断,大于等于今天才能操作,未写    _insert_line_table(self, self.id, self.appointment_date, self.teacher_name.id)def button_all_time(self):  # 所有教练本日预约    # todo : 应该有时间判断,大于等于今天才能操作,未写    """        功能: 生成所有教练本日预约。              从传入的self中得到指定的教练和日期,生成所有教练本日预约单。        1. 删除除了传入的教练外所有本日主表,子表会自动删除删除。        2.查找本日预约表中所有教练,循环生成除了本教练外主表,        3.查找教练预约表本日所有记录,遍历生成子表    """    # 1. 删除除了传入的教练外所有本日主表,子表会自动删除删除。    appointment_date = self.appointment_date    domain = [('teacher_name', '!=', self.teacher_name.id),  # 教练排除              ('active', '=', True),              ('appointment_date', '=', appointment_date)]    self.env['nebula.teacher.appointment'].search(domain).unlink()    # 2. 查找本日预约表中所有教练,生成主表    begin_time = datetime.strftime(appointment_date, "%Y-%m-%d 00:00:00")    end_time = datetime.strftime(appointment_date, "%Y-%m-%d 23:59:59")    domain = [('active', '=', True),              ('appointment_begin_date', '>=', begin_time),              ('appointment_begin_date', '<=', end_time),              ('teacher_name', '!=', self.teacher_name.id),              ('complete_begin_date', '=', None)]    field_names = ['teacher_name', 'teacher_full_name']    records = self.env['nebula.appointment'].search_read(domain, field_names, order='teacher_name desc')    old_name = ''    for record in records:        record_name = _make_name(self.appointment_date, record['teacher_name'][1], record['teacher_full_name'])        if old_name != record_name:  # 不是重名            old_name = record_name            new_record = {                'teacher_name': record['teacher_name'][0],                'appointment_date': self.appointment_date,                'name': record_name,            }            self.env['nebula.teacher.appointment'].create(new_record)    # 3.查找教练预约表本日所有记录,遍历生成子表    domain = [('active', '=', True),              ('appointment_date', '=', appointment_date)]    field_names = ['teacher_name']    records = self.env['nebula.teacher.appointment'].search_read(domain, field_names)    for record in records:        order_id = record['id']        teacher_id = record['teacher_name'][0]        _insert_line_table(self, order_id, appointment_date, teacher_id)

公用函数:

def _insert_line_table(self, order_id, appointment_date, teacher_id):    """        功能:传入主表,然后生成子表        1.传入主表        2.删除主表对应的子表        3.查询预约表本教练所有预约情况        4. 逐条插入到子表    """    domain = [('order_id', '=', order_id)]    self.env['nebula.teacher.appointment.line'].search(domain).unlink()    begin_time = datetime.strftime(appointment_date, "%Y-%m-%d 00:00:00")    end_time = datetime.strftime(appointment_date, "%Y-%m-%d 23:59:59")    domain = [('active', '=', True),              ('appointment_begin_date', '>=', begin_time),              ('appointment_begin_date', '<=', end_time),              ('teacher_name', '=', teacher_id),              ('complete_begin_date', '=', None)]    field_names = ['name']    items = self.env['nebula.appointment'].search_read(domain, field_names)    for item in items:        new_record = {            'order_id': order_id, # 主表ID            'appointment_name': item['id'],  # 子表预约单ID        }        self.env['nebula.teacher.appointment.line'].create(new_record)

界面展示

列表效果:

表单效果:

最新文章

随机文章