Example #1
0
class OpBatch(models.Model):
    _name = 'op.batch'

    code = fields.Char('Code', size=8, required=True)
    name = fields.Char('Name', size=32, required=True)
    start_date = fields.Date('Start Date',
                             required=True,
                             default=fields.Date.today())
    end_date = fields.Date('End Date', required=True)
    course_id = fields.Many2one('op.course', 'Course', required=True)

    @api.one
    @api.constrains('start_date', 'end_date')
    def check_dates(self):
        start_date = fields.Date.from_string(self.start_date)
        end_date = fields.Date.from_string(self.end_date)
        if start_date > end_date:
            raise ValidationError("End Date cannot be set before Start Date.")

    @api.model
    def name_search(self, name, args=None, operator='ilike', limit=100):
        if self.env.context.get('get_parent_batch', False):
            lst = []
            lst.append(self.env.context.get('course_id'))
            courses = self.env['op.course'].browse(lst)
            while courses.parent_id:
                lst.append(courses.parent_id.id)
                courses = courses.parent_id
            batches = self.env['op.batch'].search([('course_id', 'in', lst)])
            return batches.name_get()
        return super(OpBatch, self).name_search(name,
                                                args,
                                                operator=operator,
                                                limit=limit)
Example #2
0
class StudentAttendance(models.TransientModel):
    _name = 'student.attendance'

    from_date = fields.Date('From Date',
                            required=True,
                            default=lambda self: fields.Date.today())
    to_date = fields.Date('To Date',
                          required=True,
                          default=lambda self: fields.Date.today())

    @api.one
    @api.constrains('from_date', 'to_date')
    def check_dates(self):
        from_date = fields.Date.from_string(self.from_date)
        to_date = fields.Date.from_string(self.to_date)
        if to_date < from_date:
            raise ValidationError("To Date cannot be set before From Date.")

    @api.multi
    def print_report(self):
        data = self.read(['from_date', 'to_date'])[0]
        data.update({'student_id': self.env.context.get('active_id', False)})

        return self.env['report'].get_action(
            self, 'openeducat_attendance.student_attendance_report', data=data)
Example #3
0
class OpBookQueue(models.Model):
    _name = 'op.book.queue'
    _inherit = 'mail.thread'
    _rec_name = 'user_id'
    _description = 'Book Queue Request'

    name = fields.Char("Sequence No", readonly=True, copy=False, default='/')
    partner_id = fields.Many2one('res.partner', 'Student/Faculty')
    book_id = fields.Many2one('op.book',
                              'Book',
                              required=True,
                              track_visibility='onchange')
    date_from = fields.Date('From Date',
                            required=True,
                            default=fields.Date.today())
    date_to = fields.Date('To Date', required=True)
    user_id = fields.Many2one('res.users',
                              'User',
                              readonly=True,
                              default=lambda self: self.env.uid)
    state = fields.Selection([('request', 'Request'), ('accept', 'Accepted'),
                              ('reject', 'Rejected')],
                             'Status',
                             copy=False,
                             default='request',
                             track_visibility='onchange')

    @api.onchange('user_id')
    def onchange_user(self):
        self.partner_id = self.user_id.partner_id.id

    @api.constrains('date_from', 'date_to')
    def _check_date(self):
        if self.date_from > self.date_to:
            raise ValidationError('To Date cannot be set before From Date.')

    @api.model
    def create(self, vals):
        if vals.get('name', '/') == '/':
            vals['name'] = self.env['ir.sequence'].next_by_code(
                'op.book.queue') or '/'
        return super(OpBookQueue, self).create(vals)

    @api.one
    def do_reject(self):
        self.state = 'reject'

    @api.one
    def do_accept(self):
        self.state = 'accept'

    @api.one
    def do_request_again(self):
        self.state = 'request'
Example #4
0
class OpPlacementOffer(models.Model):
    _name = 'op.placement.offer'
    _inherit = 'mail.thread'
    _description = 'Placement Offer'

    name = fields.Char('Company Name', required=True)
    student_id = fields.Many2one('op.student', 'Student Name', required=True)
    join_date = fields.Date('Join Date', default=fields.Date.today())
    offer_package = fields.Char('Offered Package', size=256)
    training_period = fields.Char('Training Period', size=256)
    state = fields.Selection(
        [('draft', 'Draft'), ('offer', 'Offer'), ('join', 'Join'),
         ('reject', 'Rejected'), ('cancel', 'Cancel')], 'State',
        default='draft', track_visibility='onchange')

    @api.one
    def placement_offer(self):
        self.state = 'offer'

    @api.one
    def placement_join(self):
        self.state = 'join'

    @api.one
    def confirm_rejected(self):
        self.state = 'reject'

    @api.one
    def confirm_to_draft(self):
        self.state = 'draft'

    @api.one
    def confirm_cancel(self):
        self.state = 'cancel'
Example #5
0
class ReturnBook(models.TransientModel):

    """ Retrun Book Wizard """
    _name = 'return.book'

    book_id = fields.Many2one('op.book', 'Book', readonly=True)
    book_unit_id = fields.Many2one(
        'op.book.unit', 'Book Unit', readonly=True, required=True)
    actual_return_date = fields.Date(
        'Actual Return Date', default=lambda self: fields.Date.today(),
        required=True)

    @api.one
    def do_return(self):
        book_movement = self.env['op.book.movement']
        if self.book_unit_id.state and self.book_unit_id.state == 'issue':
            book_move_search = book_movement.search(
                [('book_unit_id', '=', self.book_unit_id.id),
                 ('state', '=', 'issue')])
            if not book_move_search:
                return {'type': 'ir.actions.act_window_close'}
            book_move_search.actual_return_date = self.actual_return_date
            book_move_search.calculate_penalty()
            book_move_search.state = 'return'
            self.book_unit_id.state = 'available'
        else:
            raise UserError(_(
                "Book Unit can not be returned because it's state is : %s") %
                (dict(book_unit.unit_states).get(self.book_unit_id.state)))
Example #6
0
class OpHostelRoomAllocation(models.Model):
    _name = 'op.hostel.room'

    hostel_id = fields.Many2one('op.hostel', 'Hostel', required=True)
    name = fields.Many2one('op.room', 'Room', required=True)
    student_ids = fields.Many2many('res.partner', string='Allocated Students')
    students_per_room = fields.Integer('Students per Room', required=True)
    rent = fields.Float('Rent')
    allocated_date = fields.Date('Allocated Date', default=fields.Date.today())

    @api.constrains('students_per_room')
    def check_capacity(self):
        if self.students_per_room <= 0:
            raise ValidationError("Enter proper Student Per Room")

    @api.onchange('hostel_id')
    def onchange_hostel(self):
        if self.hostel_id:
            self.name = False

    @api.onchange('name')
    def onchange_name(self):
        if self.name:
            self.students_per_room = self.name.capacity

    @api.one
    @api.constrains('student_ids', 'students_per_room')
    def _check_student_capacity(self):
        if len(self.student_ids) > self.students_per_room:
            raise ValidationError('Room capacity Over')
Example #7
0
class OpLibraryCard(models.Model):
    _name = 'op.library.card'
    _rec_name = 'number'
    _description = 'Library Card'

    partner_id = fields.Many2one('res.partner',
                                 'Student/Faculty',
                                 required=True)
    number = fields.Char('Number', size=256, required=True)
    library_card_type_id = fields.Many2one('op.library.card.type',
                                           'Card Type',
                                           required=True)
    issue_date = fields.Date('Issue Date',
                             required=True,
                             default=fields.Date.today())
    type = fields.Selection([('student', 'Student'), ('faculty', 'Faculty')],
                            'Type',
                            default='student',
                            required=True)
    student_id = fields.Many2one('op.student', 'Student')
    faculty_id = fields.Many2one('op.faculty', 'Faculty')

    _sql_constraints = [
        ('unique_library_card_number', 'unique(number)',
         'Library card Number should be unique per card!'),
    ]
Example #8
0
class OpAttendanceLine(models.Model):
    _name = 'op.attendance.line'
    _rec_name = 'attendance_id'

    attendance_id = fields.Many2one(
        'op.attendance.sheet', 'Attendance Sheet', required=True)
    student_id = fields.Many2one('op.student', 'Student', required=True)
    present = fields.Boolean('Present ?', default=True)
    course_id = fields.Many2one(
        'op.course', 'Course',
        related='attendance_id.register_id.course_id', store=True,
        readonly=True)
    batch_id = fields.Many2one(
        'op.batch', 'Batch',
        related='attendance_id.register_id.batch_id', store=True,
        readonly=True)
    remark = fields.Char('Remark', size=256)
    attendance_date = fields.Date(
        'Date', related='attendance_id.attendance_date', store=True,
        readonly=True)

    _sql_constraints = [
        ('unique_student',
         'unique(student_id,attendance_id,attendance_date)',
         'Student must be unique per Attendance.'),
    ]
Example #9
0
class OpHealthLine(models.Model):
    _name = 'op.health.line'

    health_id = fields.Many2one('op.health', 'Health')
    date = fields.Date('Date', default=lambda self: fields.Date.today())
    name = fields.Text('Checkup Detail', required=True)
    recommendation = fields.Text('Checkup Recommendation')
Example #10
0
class wx_qyh_extend(models.Model):
    _inherit = "wx.qyh"
    operator_name = fields.Char(string="运营者姓名")
    register_mobile = fields.Char(string="手机号")
    register_email = fields.Char(string="邮箱")
    auth_time = fields.Date(string="认证时间")
    wx_number = fields.Char(string="微信号")
    cus_phone = fields.Char(string="客服电话")
Example #11
0
class OpStudent(models.Model):
    _name = 'op.student'
    _inherits = {'res.partner': 'partner_id'}

    @api.one
    @api.depends('roll_number_line', 'batch_id', 'course_id')
    def _get_curr_roll_number(self):
        # TO_DO:: Improve the logic by adding sequence field in course.
        if self.roll_number_line:
            for roll_no in self.roll_number_line:
                if roll_no.course_id == self.course_id and \
                        roll_no.batch_id == self.batch_id:
                    self.roll_number = roll_no.roll_number
        else:
            self.roll_number = 0

    middle_name = fields.Char('Middle Name', size=128)
    last_name = fields.Char('Last Name', size=128, required=True)
    birth_date = fields.Date('Birth Date', required=True)
    blood_group = fields.Selection([('A+', 'A+ve'), ('B+', 'B+ve'),
                                    ('O+', 'O+ve'), ('AB+', 'AB+ve'),
                                    ('A-', 'A-ve'), ('B-', 'B-ve'),
                                    ('O-', 'O-ve'), ('AB-', 'AB-ve')],
                                   'Blood Group')
    gender = fields.Selection([('m', 'Male'), ('f', 'Female'), ('o', 'Other')],
                              'Gender',
                              required=True)
    nationality = fields.Many2one('res.country', 'Nationality')
    emergency_contact = fields.Many2one('res.partner', 'Emergency Contact')
    visa_info = fields.Char('Visa Info', size=64)
    id_number = fields.Char('ID Card Number', size=64)
    photo = fields.Binary('Photo')
    course_id = fields.Many2one('op.course', 'Course', required=True)
    batch_id = fields.Many2one('op.batch', 'Batch', required=True)
    roll_number_line = fields.One2many('op.roll.number', 'student_id',
                                       'Roll Number')
    partner_id = fields.Many2one('res.partner',
                                 'Partner',
                                 required=True,
                                 ondelete="cascade")
    roll_number = fields.Char('Current Roll Number',
                              compute='_get_curr_roll_number',
                              size=8,
                              store=True)
    gr_no = fields.Char("GR Number", size=20)

    @api.one
    @api.constrains('birth_date')
    def _check_birthdate(self):
        if self.birth_date > fields.Date.today():
            raise ValidationError(
                "Birth Date can't be greater than current date!")

    @api.onchange('course_id')
    def onchange_course(self):
        self.batch_id = False
Example #12
0
class report_plm_document_wall(models.Model):
    _name = "report.plm_document.wall"
    _description = "Users that did not inserted documents since one month"
    _auto = False

    name = fields.Date(_('Month'), readonly=True)
    user_id = fields.Many2one('res.users', _('Owner'), readonly=True)
    user = fields.Char(_('User'), size=64, readonly=True)
    month = fields.Char(_('Month'), size=24, readonly=True)
    last = fields.Datetime(_('Last Posted Time'), readonly=True)
Example #13
0
class OpActivity(models.Model):
    _name = 'op.activity'
    _rec_name = 'student_id'
    _inherit = 'mail.thread'

    student_id = fields.Many2one('op.student', 'Student', required=True)
    faculty_id = fields.Many2one('op.faculty', 'Faculty')
    type_id = fields.Many2one('op.activity.type', 'Activity Type')
    description = fields.Text('Description')
    date = fields.Date('Date', default=fields.Date.today())
Example #14
0
class OpAchievement(models.Model):
    _name = 'op.achievement'
    _rec_name = 'student_id'

    student_id = fields.Many2one('op.student', 'Student', required=True)
    faculty_id = fields.Many2one('op.faculty', 'Faculty', required=True)
    achievement_type = fields.Many2one(
        'op.achievement.type', 'Achievement Type', required=True)
    description = fields.Text('Description', required=True)
    achievement_date = fields.Date(
        'Date', required=True, default=fields.Date.today())
Example #15
0
class OpFaculty(models.Model):
    _name = 'op.faculty'
    _inherits = {'res.partner': 'partner_id'}

    partner_id = fields.Many2one('res.partner',
                                 'Partner',
                                 required=True,
                                 ondelete="cascade")
    middle_name = fields.Char('Middle Name', size=128)
    last_name = fields.Char('Last Name', size=128, required=True)
    birth_date = fields.Date('Birth Date', required=True)
    blood_group = fields.Selection([('A+', 'A+ve'), ('B+', 'B+ve'),
                                    ('O+', 'O+ve'), ('AB+', 'AB+ve'),
                                    ('A-', 'A-ve'), ('B-', 'B-ve'),
                                    ('O-', 'O-ve'), ('AB-', 'AB-ve')],
                                   'Blood Group')
    gender = fields.Selection([('male', 'Male'), ('female', 'Female')],
                              'Gender',
                              required=True)
    nationality = fields.Many2one('res.country', 'Nationality')
    emergency_contact = fields.Many2one('res.partner', 'Emergency Contact')
    visa_info = fields.Char('Visa Info', size=64)
    id_number = fields.Char('ID Card Number', size=64)
    photo = fields.Binary('Photo')
    login = fields.Char('Login',
                        related='partner_id.user_id.login',
                        readonly=1)
    last_login = fields.Datetime('Latest Connection',
                                 related='partner_id.user_id.login_date',
                                 readonly=1)
    faculty_subject_ids = fields.Many2many('op.subject', string='Subject(s)')
    emp_id = fields.Many2one('hr.employee', 'Employee')

    @api.one
    @api.constrains('birth_date')
    def _check_birthdate(self):
        if self.birth_date > fields.Date.today():
            raise ValidationError(
                "Birth Date can't be greater than current date!")

    @api.one
    def create_employee(self):
        vals = {
            'name':
            self.name + ' ' + (self.middle_name or '') + ' ' + self.last_name,
            'country_id': self.nationality.id,
            'gender': self.gender,
            'address_home_id': self.partner_id.id
        }
        emp_id = self.env['hr.employee'].create(vals)
        self.write({'emp_id': emp_id.id})
        self.partner_id.write({'supplier': True, 'employee': True})
Example #16
0
class OpExamSession(models.Model):
    _name = 'op.exam.session'
    _description = 'Exam Session'

    name = fields.Char('Exam', size=256, required=True)
    course_id = fields.Many2one('op.course', 'Course', required=True)
    batch_id = fields.Many2one('op.batch', 'Batch', required=True)
    exam_code = fields.Char('Exam Code', size=8, required=True)
    start_date = fields.Date('Start Date', required=True)
    end_date = fields.Date('End Date', required=True)
    room_id = fields.Many2one('op.exam.room', 'Room', required=True)
    exam_ids = fields.One2many('op.exam', 'session_id', 'Exam(s)')

    @api.constrains('start_date', 'end_date')
    def _check_date_time(self):
        if self.start_date > self.end_date:
            raise ValidationError(
                'End Date cannot be set before Start Date.')

    @api.onchange('course_id')
    def onchange_course(self):
        self.batch_id = False
Example #17
0
class AdmissionAnalysis(models.TransientModel):
    """ Admission Analysis Wizard """
    _name = 'admission.analysis'

    course_id = fields.Many2one('op.course', 'Course', required=True)
    start_date = fields.Date('Start Date',
                             default=time.strftime('%Y-%m-01'),
                             required=True)
    end_date = fields.Date('End Date', required=True)

    @api.multi
    def print_report(self):
        start_date = fields.Date.from_string(self.start_date)
        end_date = fields.Date.from_string(self.end_date)
        if start_date > end_date:
            raise ValidationError("End Date cannot be set before Start Date.")
        else:
            data = self.read(['course_id', 'start_date', 'end_date'])[0]
            return self.env['report'].get_action(
                self,
                'openeducat_admission.report_admission_analysis',
                data=data)
Example #18
0
class training(models.Model):
    '''
    实体:培训记录
    '''
    _name = 'hr.training.record'

    lession_id = fields.Many2one(
        'hr.training.lession',
        string='培训课程',
        required=True,
    )
    date = fields.Date(required=True, string='培训日期')
    time = fields.Char(required=True, string='培训时间')
    address = fields.Char(required=True, string='培训地点')
    teacher = fields.Char(required=True, string='培训讲师')
    student = fields.Many2many('hr.employee',
                               'training_employee_rel',
                               'training_id',
                               'employee_id',
                               required=True,
                               string='培训学员')
    price = fields.Float(digits=(16, 2), string='培训费用', default=0.0)
    description = fields.Text(string='培训描述')

    @api.onchange('lession_id')
    def change_lession(self):
        '''
        功能:默认根据课程获取培训费用、培训讲师
        :return:
        '''
        if self.lession_id:
            self.price = self.lession_id.price
            teachers = ''
            if self.lession_id.external_teacher:
                teachers = self.lession_id.external_teacher + ','

            #取内聘讲师
            sql_str = '''select emp.name_related from lession_teacher_rel as r join hr_employee as emp on r.teacher_id=emp.id
                              where r.lession_id=%s
                              ''' % (self.lession_id.id)

            _logger.info('根据培训课程ID,查找讲师=%s' % sql_str)
            self._cr.execute(sql_str)
            res = self._cr.fetchall()
            for r in res:
                teachers += r[0] + ','
            if len(teachers) > 0:
                teachers = teachers[0:-1]

            self.teacher = teachers
            self.description = self.lession_id.description
Example #19
0
class link_tracker_click(models.Model):
    _name = "link.tracker.click"
    _rec_name = "link_id"

    click_date = fields.Date(string='Create Date')
    link_id = fields.Many2one('link.tracker',
                              'Link',
                              required=True,
                              ondelete='cascade')
    ip = fields.Char(string='Internet Protocol')
    country_id = fields.Many2one('res.country', 'Country')

    @api.model
    def add_click(self, code, ip, country_code, stat_id=False):
        self = self.sudo()
        code_rec = self.env['link.tracker.code'].search([('code', '=', code)])

        if not code_rec:
            return None

        again = self.search_count([('link_id', '=', code_rec.link_id.id),
                                   ('ip', '=', ip)])

        if not again:
            country_record = self.env['res.country'].search(
                [('code', '=', country_code)], limit=1)

            vals = {
                'link_id': code_rec.link_id.id,
                'create_date': datetime.date.today(),
                'ip': ip,
                'country_id': country_record.id,
                'mail_stat_id': stat_id
            }

            if stat_id:
                mail_stat = self.env['mail.mail.statistics'].search([
                    ('id', '=', stat_id)
                ])

                if mail_stat.mass_mailing_campaign_id:
                    vals[
                        'mass_mailing_campaign_id'] = mail_stat.mass_mailing_campaign_id.id

                if mail_stat.mass_mailing_id:
                    vals['mass_mailing_id'] = mail_stat.mass_mailing_id.id

            self.create(vals)
Example #20
0
class ReturnDate(models.TransientModel):
    """ Assign return date """
    _name = 'return.date'

    actual_return_date = fields.Date('Actual Return Date',
                                     required=True,
                                     default=lambda self: fields.Date.today())

    @api.one
    def assign_return_date(self):
        book_movement = self.env['op.book.movement'].browse(
            self.env.context.get('active_ids', False))
        book_movement.write({'actual_return_date': self.actual_return_date})
        book_movement.calculate_penalty()
        book_movement.state = 'return'
        book_movement.book_unit_id.state = 'available'
Example #21
0
class StudentMigrate(models.TransientModel):
    """ Student Migration Wizard """
    _name = 'student.migrate'

    date = fields.Date('Date', required=True, default=fields.Date.today())
    course_from_id = fields.Many2one('op.course', 'From Course', required=True)
    course_to_id = fields.Many2one('op.course', 'To Course', required=True)
    student_ids = fields.Many2many('op.student',
                                   string='Student(s)',
                                   required=True)

    @api.one
    @api.constrains('course_from_id', 'course_to_id')
    def _check_admission_register(self):
        if self.course_from_id == self.course_to_id:
            raise ValidationError("From Course must not be same as To Course!")

        if self.course_from_id.parent_id:
            if self.course_from_id.parent_id != \
                    self.course_to_id.parent_id:
                raise ValidationError(
                    "Can't migrate, As selected courses don't \
                    share same parent course!")
        else:
            raise ValidationError("Can't migrate, Proceed for new admission")

    @api.one
    @api.onchange('course_from_id')
    def onchange_course_id(self):
        self.student_ids = False

    @api.one
    def student_migrate_forward(self):
        activity_type = self.env["op.activity.type"]
        act_type = activity_type.search([('name', '=', 'Migration')], limit=1)
        if not act_type:
            act_type = activity_type.create({'name': 'Migration'})

        for student in self.student_ids:
            activity_vals = {
                'student_id': student.id,
                'type_id': act_type.id,
                'date': self.date
            }
            self.env['op.activity'].create(activity_vals)
            student.write({'course_id': self.course_to_id.id})
Example #22
0
class OpMarksheetRegister(models.Model):
    _name = 'op.marksheet.register'

    exam_session_id = fields.Many2one(
        'op.exam.session', 'Exam', required=True)
    marksheet_line = fields.One2many(
        'op.marksheet.line', 'marksheet_reg_id', 'Marksheets')
    generated_date = fields.Date(
        'Generated Date', required=True, default=fields.Date.today())
    generated_by = fields.Many2one(
        'res.users', 'Generated By',
        default=lambda self: self.env.uid, required=True)
    status = fields.Selection(
        [('draft', 'Draft'), ('validated', 'Validated'),
         ('cancelled', 'Cancelled')], 'Status', default="draft", required=True)
    total_pass = fields.Float('Total Pass')
    total_failed = fields.Float('Total Fail')
    name = fields.Char('Marksheet Register', size=256, required=True)

    @api.constrains('total_pass', 'total_failed')
    def _check_marks(self):
        if (self.total_pass < 0.0) or (self.total_failed < 0.0):
            raise ValidationError('Enter proper pass or fail!')
Example #23
0
class OpAttendanceSheet(models.Model):
    _name = 'op.attendance.sheet'

    @api.one
    @api.depends('attendance_line.present')
    def _total_present(self):
        self.total_present = len(
            self.attendance_line.filtered(lambda self: self.present))

    @api.one
    @api.depends('attendance_line.present')
    def _total_absent(self):
        self.total_absent = len(
            self.attendance_line.filtered(lambda self: self.present is False))

    name = fields.Char('Name', required=True, size=32)
    register_id = fields.Many2one('op.attendance.register',
                                  'Register',
                                  required=True)
    course_id = fields.Many2one('op.course',
                                related='register_id.course_id',
                                store=True,
                                readonly=True)
    batch_id = fields.Many2one('op.batch',
                               'Batch',
                               related='register_id.batch_id',
                               store=True,
                               readonly=True)
    attendance_date = fields.Date('Date',
                                  required=True,
                                  default=lambda self: fields.Date.today())
    attendance_line = fields.One2many('op.attendance.line', 'attendance_id',
                                      'Attendance Line')
    total_present = fields.Integer('Total Present', compute='_total_present')
    total_absent = fields.Integer('Total Absent', compute='_total_absent')
    faculty_id = fields.Many2one('op.faculty', 'Faculty')
class hr_recruitment_report(models.Model):
    _name = "hr.recruitment.report"
    _description = "Recruitments Statistics"
    _auto = False
    _rec_name = 'date_create'
    _order = 'date_create desc'

    user_id = fields.Many2one('res.users', 'User', readonly=True)
    company_id = fields.Many2one('res.company', 'Company', readonly=True)
    date_create = fields.Datetime('Create Date', readonly=True)
    date_last_stage_update = fields.Datetime('Last Stage Update', readonly=True)
    date_closed = fields.Date('Closed', readonly=True)
    job_id = fields.Many2one('hr.job', 'Applied Job', readonly=True)
    stage_id = fields.Many2one('hr.recruitment.stage', 'Stage')
    type_id = fields.Many2one('hr.recruitment.degree', 'Degree')
    department_id = fields.Many2one('hr.department', 'Department', readonly=True)
    priority = fields.Selection(hr_recruitment.AVAILABLE_PRIORITIES, 'Appreciation')
    salary_prop = fields.Float("Salary Proposed", digits=0)
    salary_prop_avg = fields.Float("Avg. Proposed Salary", group_operator="avg", digits=0)
    salary_exp = fields.Float("Salary Expected", digits=0)
    salary_exp_avg = fields.Float("Avg. Expected Salary", group_operator="avg", digits=0)
    partner_id = fields.Many2one('res.partner', 'Partner', readonly=True)
    delay_close = fields.Float('Avg. Delay to Close', digits=(16, 2), readonly=True, group_operator="avg", help="Number of Days to close the project issue")
    last_stage_id = fields.Many2one('hr.recruitment.stage', 'Last Stage')
    medium_id = fields.Many2one('utm.medium', 'Medium', readonly=True, help="This is the method of delivery. Ex: Postcard, Email, or Banner Ad")
    source_id = fields.Many2one('utm.source', 'Source', readonly=True, help="This is the source of the link Ex: Search Engine, another domain, or name of email list")

    def init(self, cr):
        tools.drop_view_if_exists(cr, 'hr_recruitment_report')
        cr.execute("""
            create or replace view hr_recruitment_report as (
                 select
                     min(s.id) as id,
                     s.create_date as date_create,
                     date(s.date_closed) as date_closed,
                     s.date_last_stage_update as date_last_stage_update,
                     s.partner_id,
                     s.company_id,
                     s.user_id,
                     s.job_id,
                     s.type_id,
                     s.department_id,
                     s.priority,
                     s.stage_id,
                     s.last_stage_id,
                     s.medium_id,
                     s.source_id,
                     sum(salary_proposed) as salary_prop,
                     (sum(salary_proposed)/count(*)) as salary_prop_avg,
                     sum(salary_expected) as salary_exp,
                     (sum(salary_expected)/count(*)) as salary_exp_avg,
                     extract('epoch' from (s.write_date-s.create_date))/(3600*24) as delay_close,
                     count(*) as nbr
                 from hr_applicant s
                 group by
                     s.date_open,
                     s.create_date,
                     s.write_date,
                     s.date_closed,
                     s.date_last_stage_update,
                     s.partner_id,
                     s.company_id,
                     s.user_id,
                     s.stage_id,
                     s.last_stage_id,
                     s.type_id,
                     s.priority,
                     s.job_id,
                     s.department_id,
                     s.medium_id,
                     s.source_id
            )
        """)
Example #25
0
class OpAdmissionRegister(models.Model):
    _name = 'op.admission.register'
    _inherit = 'mail.thread'
    _description = 'Admission Register'

    name = fields.Char('Name',
                       required=True,
                       readonly=True,
                       states={'draft': [('readonly', False)]})
    start_date = fields.Date('Start Date',
                             required=True,
                             readonly=True,
                             default=fields.Date.today(),
                             states={'draft': [('readonly', False)]})
    end_date = fields.Date('End Date',
                           required=True,
                           readonly=True,
                           default=(datetime.today() + relativedelta(days=30)),
                           states={'draft': [('readonly', False)]})
    course_id = fields.Many2one('op.course',
                                'Course',
                                required=True,
                                readonly=True,
                                states={'draft': [('readonly', False)]},
                                track_visibility='onchange')
    min_count = fields.Integer('Minimum No. of Admission',
                               readonly=True,
                               states={'draft': [('readonly', False)]})
    max_count = fields.Integer('Maximum No. of Admission',
                               readonly=True,
                               states={'draft': [('readonly', False)]},
                               default=30)
    product_id = fields.Many2one('product.product',
                                 'Product',
                                 required=True,
                                 domain=[('type', '=', 'service')],
                                 readonly=True,
                                 states={'draft': [('readonly', False)]},
                                 track_visibility='onchange')
    admission_ids = fields.One2many('op.admission', 'register_id',
                                    'Admissions')
    state = fields.Selection([('draft', 'Draft'), ('confirm', 'Confirmed'),
                              ('cancel', 'Cancelled'),
                              ('application', 'Application Gathering'),
                              ('admission', 'Admission Process'),
                              ('done', 'Done')],
                             'Status',
                             default='draft',
                             track_visibility='onchange')

    @api.one
    @api.constrains('start_date', 'end_date')
    def check_dates(self):
        start_date = fields.Date.from_string(self.start_date)
        end_date = fields.Date.from_string(self.end_date)
        if start_date > end_date:
            raise ValidationError("End Date cannot be set before Start Date.")

    @api.one
    @api.constrains('min_count', 'max_count')
    def check_no_of_admission(self):
        if (self.min_count < 0) or (self.max_count < 0):
            raise ValidationError("No of Admission should be positive!")
        if self.min_count > self.max_count:
            raise ValidationError(
                "Min Admission can't be greater than Max Admission")

    @api.one
    def confirm_register(self):
        self.state = 'confirm'

    @api.one
    def set_to_draft(self):
        self.state = 'draft'

    @api.one
    def cancel_register(self):
        self.state = 'cancel'

    @api.one
    def start_application(self):
        self.state = 'application'

    @api.one
    def start_admission(self):
        self.state = 'admission'

    @api.one
    def close_register(self):
        self.state = 'done'
Example #26
0
class Applicant(models.Model):
    _name = "hr.applicant"
    _description = "Applicant"
    _order = "priority desc, id desc"
    _inherit = ['mail.thread', 'ir.needaction_mixin', 'utm.mixin']
    _mail_mass_mailing = _('Applicants')

    def _default_stage_id(self):
        if self._context.get('default_job_id'):
            ids = self.env['hr.recruitment.stage'].search([
                ('job_ids', '=', self._context['default_job_id']),
                ('fold', '=', False)
            ], order='sequence asc', limit=1).ids
            if ids:
                return ids[0]
        return False

    def _default_company_id(self):
        company_id = False
        if self._context.get('default_department_id'):
            department = self.env['hr.department'].browse(self._context['default_department_id'])
            company_id = department.company_id.id
        if not company_id:
            company_id = self.env['res.company']._company_default_get('hr.applicant')
        return company_id

    name = fields.Char("Subject / Application Name", required=True)
    active = fields.Boolean("Active", default=True, help="If the active field is set to false, it will allow you to hide the case without removing it.")
    description = fields.Text("Description")
    email_from = fields.Char("Email", size=128, help="These people will receive email.")
    email_cc = fields.Text("Watchers Emails", size=252,
                           help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma")
    probability = fields.Float("Probability")
    partner_id = fields.Many2one('res.partner', "Contact")
    create_date = fields.Datetime("Creation Date", readonly=True, select=True)
    write_date = fields.Datetime("Update Date", readonly=True)
    stage_id = fields.Many2one('hr.recruitment.stage', 'Stage', track_visibility='onchange',
                               domain="[('job_ids', '=', job_id)]", copy=False, select=1,
                               default=_default_stage_id)
    last_stage_id = fields.Many2one('hr.recruitment.stage', "Last Stage",
                                    help="Stage of the applicant before being in the current stage. Used for lost cases analysis.")
    categ_ids = fields.Many2many('hr.applicant.category', string="Tags")
    company_id = fields.Many2one('res.company', "Company", default=_default_company_id)
    user_id = fields.Many2one('res.users', "Responsible", track_visibility="onchange", default=lambda self: self.env.uid)
    date_closed = fields.Datetime("Closed", readonly=True, select=True)
    date_open = fields.Datetime("Assigned", readonly=True, select=True)
    date_last_stage_update = fields.Datetime("Last Stage Update", select=True, default=fields.Datetime.now)
    date_action = fields.Date("Next Action Date")
    title_action = fields.Char("Next Action", size=64)
    priority = fields.Selection(AVAILABLE_PRIORITIES, "Appreciation", default='0')
    job_id = fields.Many2one('hr.job', "Applied Job")
    salary_proposed_extra = fields.Char("Proposed Salary Extra", help="Salary Proposed by the Organisation, extra advantages")
    salary_expected_extra = fields.Char("Expected Salary Extra", help="Salary Expected by Applicant, extra advantages")
    salary_proposed = fields.Float("Proposed Salary", help="Salary Proposed by the Organisation")
    salary_expected = fields.Float("Expected Salary", help="Salary Expected by Applicant")
    availability = fields.Date("Availability", help="The date at which the applicant will be available to start working")
    partner_name = fields.Char("Applicant's Name")
    partner_phone = fields.Char("Phone", size=32)
    partner_mobile = fields.Char("Mobile", size=32)
    type_id = fields.Many2one('hr.recruitment.degree', "Degree")
    department_id = fields.Many2one('hr.department', "Department")
    survey = fields.Many2one('survey.survey', related='job_id.survey_id', string="Survey")  # TDE FIXME: rename to survey_id
    response_id = fields.Many2one('survey.user_input', "Response", ondelete="set null", oldname="response")
    reference = fields.Char("Referred By")
    day_open = fields.Float(compute='_compute_day', string="Days to Open")
    day_close = fields.Float(compute='_compute_day', string="Days to Close")
    color = fields.Integer("Color Index", default=0)
    emp_id = fields.Many2one('hr.employee', string="Employee", track_visibility="onchange", help="Employee linked to the applicant.")
    user_email = fields.Char(related='user_id.email', type="char", string="User Email", readonly=True)
    attachment_number = fields.Integer(compute='_get_attachment_number', string="Number of Attachments")
    employee_name = fields.Char(related='emp_id.name', string="Employee Name")
    attachment_ids = fields.One2many('ir.attachment', 'res_id', domain=[('res_model', '=', 'hr.applicant')], string='Attachments')

    @api.depends('date_open', 'date_closed')
    @api.one
    def _compute_day(self):
        if self.date_open:
            date_create = datetime.strptime(self.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
            date_open = datetime.strptime(self.date_open, tools.DEFAULT_SERVER_DATETIME_FORMAT)
            self.day_open = (date_open - date_create).total_seconds() / (24.0 * 3600)

        if self.date_closed:
            date_create = datetime.strptime(self.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
            date_closed = datetime.strptime(self.date_closed, tools.DEFAULT_SERVER_DATETIME_FORMAT)
            self.day_close = (date_closed - date_create).total_seconds() / (24.0 * 3600)

    @api.multi
    def _get_attachment_number(self):
        read_group_res = self.env['ir.attachment'].read_group(
            [('res_model', '=', 'hr.applicant'), ('res_id', 'in', self.ids)],
            ['res_id'], ['res_id'])
        attach_data = dict((res['res_id'], res['res_id_count']) for res in read_group_res)
        for record in self:
            record.attachment_number = attach_data.get(record.id, 0)

    @api.model
    def _read_group_stage_ids(self, ids, domain, read_group_order=None, access_rights_uid=None):
        access_rights_uid = access_rights_uid or self.env.uid
        Stage = self.env['hr.recruitment.stage']
        order = Stage._order
        # lame hack to allow reverting search, should just work in the trivial case
        if read_group_order == 'stage_id desc':
            order = "%s desc" % order
        # retrieve job_id from the context and write the domain: ids + contextual columns (job or default)
        job_id = self._context.get('default_job_id')
        department_id = self._context.get('default_department_id')
        search_domain = []
        if job_id:
            search_domain = [('job_ids', '=', job_id)]
        if department_id:
            if search_domain:
                search_domain = ['|', ('job_ids.department_id', '=', department_id)] + search_domain
            else:
                search_domain = [('job_ids.department_id', '=', department_id)]
        if self.ids:
            if search_domain:
                search_domain = ['|', ('id', 'in', self.ids)] + search_domain
            else:
                search_domain = [('id', 'in', self.ids)]

        stage_ids = Stage._search(search_domain, order=order, access_rights_uid=access_rights_uid)
        stages = Stage.sudo(access_rights_uid).browse(stage_ids)
        result = stages.name_get()
        # restore order of the search
        result.sort(lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))

        fold = {}
        for stage in stages:
            fold[stage.id] = stage.fold or False
        return result, fold

    _group_by_full = {
        'stage_id': _read_group_stage_ids
    }

    @api.onchange('job_id')
    def onchange_job_id(self):
        vals = self._onchange_job_id_internal(self.job_id.id)
        self.department_id = vals['value']['department_id']
        self.user_id = vals['value']['user_id']
        self.stage_id = vals['value']['stage_id']

    def _onchange_job_id_internal(self, job_id):
        department_id = False
        user_id = False
        stage_id = self.stage_id.id
        if job_id:
            job = self.env['hr.job'].browse(job_id)
            department_id = job.department_id.id
            user_id = job.user_id.id
            if not self.stage_id:
                stage_ids = self.env['hr.recruitment.stage'].search([
                    ('job_ids', '=', job.id),
                    ('fold', '=', False)
                ], order='sequence asc', limit=1).ids
                stage_id = stage_ids[0] if stage_ids else False

        return {'value': {
            'department_id': department_id,
            'user_id': user_id,
            'stage_id': stage_id
        }}

    @api.onchange('partner_id')
    def onchange_partner_id(self):
        self.partner_phone = self.partner_id.phone
        self.partner_mobile = self.partner_id.mobile
        self.email_from = self.partner_id.email

    @api.onchange('stage_id')
    def onchange_stage_id(self):
        vals = self._onchange_stage_id_internal(self.stage_id.id)
        if vals['value'].get('date_closed'):
            self.date_closed = vals['value']['date_closed']

    def _onchange_stage_id_internal(self, stage_id):
        if not stage_id:
            return {'value': {}}
        stage = self.env['hr.recruitment.stage'].browse(stage_id)
        if stage.fold:
            return {'value': {'date_closed': fields.datetime.now()}}
        return {'value': {'date_closed': False}}

    @api.model
    def create(self, vals):
        if vals.get('department_id') and not self._context.get('default_department_id'):
            self = self.with_context(default_department_id=vals.get('department_id'))
        if vals.get('job_id') or self._context.get('default_job_id'):
            job_id = vals.get('job_id') or self._context.get('default_job_id')
            for key, value in self._onchange_job_id_internal(job_id)['value'].iteritems():
                if key not in vals:
                    vals[key] = value
        if vals.get('user_id'):
            vals['date_open'] = fields.Datetime.now()
        if 'stage_id' in vals:
            vals.update(self._onchange_stage_id_internal(vals.get('stage_id'))['value'])
        return super(Applicant, self.with_context(mail_create_nolog=True)).create(vals)

    @api.multi
    def write(self, vals):
        # user_id change: update date_open
        if vals.get('user_id'):
            vals['date_open'] = fields.Datetime.now()
        # stage_id: track last stage before update
        if 'stage_id' in vals:
            vals['date_last_stage_update'] = fields.Datetime.now()
            vals.update(self._onchange_stage_id_internal(vals.get('stage_id'))['value'])
            for applicant in self:
                vals['last_stage_id'] = applicant.stage_id.id
                res = super(Applicant, self).write(vals)
        else:
            res = super(Applicant, self).write(vals)

        # post processing: if stage changed, post a message in the chatter
        if vals.get('stage_id'):
            if self.stage_id.template_id:
                self.message_post_with_template(self.stage_id.template_id.id, notify=True, composition_mode='mass_mail')
        return res

    @api.model
    def get_empty_list_help(self, help):
        return super(Applicant, self.with_context(empty_list_help_model='hr.job',
                                                  empty_list_help_id=self.env.context.get('default_job_id'),
                                                  empty_list_help_document_name=_("job applicants"))).get_empty_list_help(help)

    @api.multi
    def action_get_created_employee(self):
        self.ensure_one()
        action = self.env['ir.actions.act_window'].for_xml_id('hr', 'open_view_employee_list')
        action['res_id'] = self.mapped('emp_id').ids[0]
        return action

    @api.multi
    def action_makeMeeting(self):
        """ This opens Meeting's calendar view to schedule meeting on current applicant
            @return: Dictionary value for created Meeting view
        """
        self.ensure_one()
        partners = self.partner_id | self.user_id.partner_id | self.department_id.manager_id.user_id.partner_id

        category = self.env.ref('hr_recruitment.categ_meet_interview')
        res = self.env['ir.actions.act_window'].for_xml_id('calendar', 'action_calendar_event')
        res['context'] = {
            'search_default_partner_ids': self.partner_id.name,
            'default_partner_ids': partners.ids,
            'default_user_id': self.env.uid,
            'default_name': self.name,
            'default_categ_ids': category and [category.id] or False,
        }
        return res

    @api.multi
    def action_start_survey(self):
        self.ensure_one()
        # create a response and link it to this applicant
        if not self.response_id:
            response = self.env['survey.user_input'].create({'survey_id': self.survey.id, 'partner_id': self.partner_id.id})
            self.response_id = response.id
        else:
            response = self.response_id
        # grab the token of the response and start surveying
        return self.survey.with_context(survey_token=response.token).action_start_survey()

    @api.multi
    def action_print_survey(self):
        """ If response is available then print this response otherwise print survey form (print template of the survey) """
        self.ensure_one()
        if not self.response_id:
            return self.survey.action_print_survey()
        else:
            response = self.response_id
            return self.survey.with_context(survey_token=response.token).action_print_survey()

    @api.multi
    def action_get_attachment_tree_view(self):
        attachment_action = self.env.ref('base.action_attachment')
        action = attachment_action.read()[0]
        action['context'] = {'default_res_model': self._name, 'default_res_id': self.ids[0]}
        action['domain'] = str(['&', ('res_model', '=', self._name), ('res_id', 'in', self.ids)])
        return action

    @api.multi
    def _track_subtype(self, init_values):
        record = self[0]
        if 'emp_id' in init_values and record.emp_id:
            return 'hr_recruitment.mt_applicant_hired'
        elif 'stage_id' in init_values and record.stage_id and record.stage_id.sequence <= 1:
            return 'hr_recruitment.mt_applicant_new'
        elif 'stage_id' in init_values and record.stage_id and record.stage_id.sequence > 1:
            return 'hr_recruitment.mt_applicant_stage_changed'
        return super(Applicant, self)._track_subtype(init_values)

    @api.model
    def message_get_reply_to(self, ids, default=None):
        """ Override to get the reply_to of the parent project. """
        applicants = self.sudo().browse(ids)
        aliases = self.env['hr.job'].message_get_reply_to(applicants.mapped('job_id').ids, default=default)
        return dict((applicant.id, aliases.get(applicant.job_id and applicant.job_id.id or 0, False)) for applicant in applicants)

    @api.multi
    def message_get_suggested_recipients(self):
        recipients = super(Applicant, self).message_get_suggested_recipients()
        for applicant in self:
            if applicant.partner_id:
                applicant._message_add_suggested_recipient(recipients, partner=applicant.partner_id, reason=_('Contact'))
            elif applicant.email_from:
                applicant._message_add_suggested_recipient(recipients, email=applicant.email_from, reason=_('Contact Email'))
        return recipients

    @api.model
    def message_new(self, msg, custom_values=None):
        """ Overrides mail_thread message_new that is called by the mailgateway
            through message_process.
            This override updates the document according to the email.
        """
        val = msg.get('from').split('<')[0]
        defaults = {
            'name': msg.get('subject') or _("No Subject"),
            'partner_name': val,
            'email_from': msg.get('from'),
            'email_cc': msg.get('cc'),
            'user_id': False,
            'partner_id': msg.get('author_id', False),
        }
        if msg.get('priority'):
            defaults['priority'] = msg.get('priority')
        if custom_values:
            defaults.update(custom_values)
        return super(Applicant, self).message_new(msg, custom_values=defaults)

    @api.multi
    def create_employee_from_applicant(self):
        """ Create an hr.employee from the hr.applicants """
        employee = False
        for applicant in self:
            address_id = contact_name = False
            if applicant.partner_id:
                address_id = applicant.partner_id.address_get(['contact'])['contact']
                contact_name = applicant.partner_id.name_get()[0][1]
            if applicant.job_id and (applicant.partner_name or contact_name):
                applicant.job_id.write({'no_of_hired_employee': applicant.job_id.no_of_hired_employee + 1})
                employee = self.env['hr.employee'].create({'name': applicant.partner_name or contact_name,
                                               'job_id': applicant.job_id.id,
                                               'address_home_id': address_id,
                                               'department_id': applicant.department_id.id or False,
                                               'address_id': applicant.company_id and applicant.company_id.partner_id and applicant.company_id.partner_id.id or False,
                                               'work_email': applicant.department_id and applicant.department_id.company_id and applicant.department_id.company_id.email or False,
                                               'work_phone': applicant.department_id and applicant.department_id.company_id and applicant.department_id.company_id.phone or False})
                applicant.write({'emp_id': employee.id})
                applicant.job_id.message_post(
                    body=_('New Employee %s Hired') % applicant.partner_name if applicant.partner_name else applicant.name,
                    subtype="hr_recruitment.mt_job_applicant_hired")
                employee._broadcast_welcome()
            else:
                raise UserError(_('You must define an Applied Job and a Contact Name for this applicant.'))

        employee_action = self.env.ref('hr.open_view_employee_list')
        dict_act_window = employee_action.read([])[0]
        if employee:
            dict_act_window['res_id'] = employee.id
        dict_act_window['view_mode'] = 'form,tree'
        return dict_act_window

    @api.multi
    def archive_applicant(self):
        self.write({'active': False})

    @api.multi
    def reset_applicant(self):
        """ Reinsert the applicant into the recruitment pipe in the first stage"""
        for applicant in self:
            first_stage_obj = self.env['hr.recruitment.stage'].search([('job_ids', 'in', applicant.job_id.id)], order="sequence asc", limit=1)
            applicant.write({'active': True, 'stage_id': first_stage_obj.id})
Example #27
0
class TimeTableReport(models.TransientModel):
    _name = 'time.table.report'
    _description = 'Generate Time Table Report'

    state = fields.Selection([('faculty', 'Faculty'), ('student', 'Student')],
                             string='Select',
                             required=True,
                             default='faculty')
    course_id = fields.Many2one('op.course', 'Course')
    batch_id = fields.Many2one('op.batch', 'Batch')
    faculty_id = fields.Many2one('op.faculty', 'Faculty')
    start_date = fields.Date(
        'Start Date',
        required=True,
        default=(datetime.today() -
                 relativedelta(days=datetime.date(datetime.today()).weekday())
                 ).strftime('%Y-%m-%d'))
    end_date = fields.Date(
        'End Date',
        required=True,
        default=(
            datetime.today() +
            relativedelta(days=6 - datetime.date(datetime.today()).weekday())
        ).strftime('%Y-%m-%d'))

    @api.one
    @api.constrains('start_date', 'end_date')
    def _check_dates(self):
        start_date = fields.Date.from_string(self.start_date)
        end_date = fields.Date.from_string(self.end_date)
        if end_date < start_date:
            raise ValidationError('End Date cannot be set before Start Date.')
        elif end_date > (start_date + timedelta(days=6)):
            raise ValidationError("Select date range for a week!")

    @api.onchange('course_id')
    def onchange_course(self):
        self.batch_id = False

    @api.multi
    def gen_time_table_report(self):
        data = self.read([
            'start_date', 'end_date', 'course_id', 'batch_id', 'state',
            'faculty_id'
        ])[0]
        if data['state'] == 'student':
            time_table_ids = self.env['op.timetable'].search(
                [('course_id', '=', data['course_id'][0]),
                 ('batch_id', '=', data['batch_id'][0]),
                 ('start_datetime', '>', data['start_date'] + '%H:%M:%S'),
                 ('end_datetime', '<', data['end_date'] + '%H:%M:%S')],
                order='start_datetime asc')

            data.update({'time_table_ids': time_table_ids.ids})
            return self.env['report'].get_action(
                self,
                'openeducat_timetable.report_timetable_student_generate',
                data=data)
        else:
            teacher_time_table_ids = self.env['op.timetable'].search(
                [('start_datetime', '>', data['start_date'] + '%H:%M:%S'),
                 ('end_datetime', '<', data['end_date'] + '%H:%M:%S'),
                 ('faculty_id', '=', data['faculty_id'][0])],
                order='start_datetime asc')

            data.update({'teacher_time_table_ids': teacher_time_table_ids.ids})
            return self.env['report'].get_action(
                self,
                'openeducat_timetable.report_timetable_teacher_generate',
                data=data)
Example #28
0
class SaleForecastLoad(models.TransientModel):

    _name = 'sale.forecast.load'

    def _get_default_partner(self):
        model = self.env.context.get('active_model', False)
        record = self.env[model].browse(self.env.context.get('active_id'))
        partner = False
        if model == 'sale.order':
            partner = record.partner_id
        return partner

    def _get_default_forecast(self):
        model = self.env.context.get('active_model', False)
        record = self.env[model].browse(self.env.context.get('active_id'))
        forecast = False
        if model == 'procurement.sale.forecast':
            forecast = record.id
        return forecast

    def _get_default_sale(self):
        model = self.env.context.get('active_model', False)
        record = self.env[model].browse(self.env.context.get('active_id'))
        sale = False
        if model == 'sale.order':
            sale = record.id
        return sale

    def _get_default_date_from(self):
        model = self.env.context.get('active_model', False)
        record = self.env[model].browse(self.env.context.get('active_id'))
        date_from = False
        if model == 'sale.order':
            date_from = record.date_order
        elif model == 'procurement.sale.forecast':
            reg_date = record.date_from
            cur_year = fields.Date.from_string(reg_date).year
            date_from = fields.Date.from_string(reg_date).replace(
                year=cur_year - 1)
        return date_from

    def _get_default_date_to(self):
        model = self.env.context.get('active_model', False)
        record = self.env[model].browse(self.env.context.get('active_id'))
        date_to = False
        if model == 'sale.order':
            date_to = record.date_order
        elif model == 'procurement.sale.forecast':
            reg_date = record.date_to
            cur_year = fields.Date.from_string(reg_date).year
            date_to = fields.Date.from_string(reg_date).replace(year=cur_year -
                                                                1)
        return date_to

    partner_id = fields.Many2one("res.partner",
                                 string="Partner",
                                 default=_get_default_partner)
    date_from = fields.Date(string="Date from", default=_get_default_date_from)
    date_to = fields.Date(string="Date to", default=_get_default_date_to)
    sale_id = fields.Many2one("sale.order", "Sale", default=_get_default_sale)
    forecast_id = fields.Many2one("procurement.sale.forecast",
                                  "Forecast",
                                  default=_get_default_forecast)
    product_categ_id = fields.Many2one("product.category", string="Category")
    product_tmpl_id = fields.Many2one("product.template", string="Template")
    product_id = fields.Many2one("product.product", string="Product")
    factor = fields.Float(string="Factor", default=1)

    @api.onchange('sale_id')
    def sale_onchange(self):
        if self.sale_id:
            self.partner_id = self.sale_id.partner_id.id
            self.date_from = self.sale_id.date_order
            self.date_to = self.sale_id.date_order

    @api.onchange('forecast_id')
    def forecast_onchange(self):
        if self.forecast_id:
            from_date = self.forecast_id.date_from
            to_date = self.forecast_id.date_to
            f_cur_year = fields.Date.from_string(from_date).year
            t_cur_year = fields.Date.from_string(to_date).year
            date_from = fields.Date.from_string(from_date).replace(
                year=f_cur_year - 1)
            date_to = fields.Date.from_string(to_date).replace(
                year=t_cur_year - 1)
            self.date_from = date_from
            self.date_to = date_to

    @api.multi
    def match_sales_forecast(self, sales, factor):
        self.ensure_one()
        forecast_line_obj = self.env['procurement.sale.forecast.line']
        res = {}
        for sale in sales:
            forecast = self.forecast_id.id
            product = sale.product_id.id
            partner = self.partner_id.id
            forecast_lines = forecast_line_obj.search([
                ('product_id', '=', product), ('partner_id', '=', partner),
                ('forecast_id', '=', forecast)
            ])
            if not forecast_lines:
                if partner not in res:
                    res[partner] = {}
                if product not in res[partner]:
                    res[partner][product] = {'qty': 0.0, 'amount': 0.0}
                product_dict = res[partner][product]
                sum_qty = product_dict['qty'] + sale.product_uom_qty
                sum_subtotal = (product_dict['amount'] + sale.price_subtotal)
                product_dict['qty'] = sum_qty * factor
                product_dict['amount'] = sum_subtotal
        return res

    @api.multi
    def get_date_list(self, forecast):
        self.ensure_one()
        date_list = []
        date_start = fields.Date.from_string(forecast.date_from)
        date_end = fields.Date.from_string(forecast.date_to)
        month_count = ((date_end.year - date_start.year) * 12 +
                       date_end.month - date_start.month)
        date = '-'.join([str(date_start.year), str(date_start.month), str(1)])
        first_date = fields.Date.from_string(date)
        date_list.append(date)
        while month_count > 0:
            next_date = first_date + relativedelta(months=month_count)
            date_list.append(fields.Date.to_string(next_date))
            month_count -= 1
        return date_list

    @api.multi
    def get_sale_forecast_lists(self, forecast):
        sale_line_obj = self.env['sale.order.line']
        sale_obj = self.env['sale.order']
        product_obj = self.env['product.product']
        self.ensure_one()
        sales = []
        if self.sale_id:
            sales = self.sale_id
        else:
            sale_domain = [('date_order', '>=', self.date_from),
                           ('date_order', '<=', self.date_to)]
            if self.partner_id:
                sale_domain += [('partner_id', '=', self.partner_id.id)]
            sales = sale_obj.search(sale_domain)
        sale_line_domain = [('order_id', 'in', sales.ids)]
        if self.product_id:
            sale_line_domain += [('product_id', '=', self.product_id.id)]
        elif self.product_tmpl_id:
            sale_line_domain += [('product_tmpl_id', '=',
                                  self.product_tmpl_id.id)]
        elif self.product_categ_id:
            products = product_obj.search([('categ_id', '=',
                                            self.product_categ_id.id)])
            sale_line_domain += [('product_id', 'in', products.ids)]
        sale_lines = sale_line_obj.search(sale_line_domain)
        return sale_lines

    @api.multi
    def load_sales(self):
        self.ensure_one()
        forecast_line_obj = self.env['procurement.sale.forecast.line']
        forecast = self.forecast_id
        sale_lines = self.get_sale_forecast_lists(forecast)
        date_list = self.get_date_list(forecast)
        date_start = fields.Date.from_string(self.date_from)
        date_end = fields.Date.from_string(self.date_to)
        month_count = ((date_end.year - date_start.year) * 12 +
                       date_end.month - date_start.month + 1)
        result = self.match_sales_forecast(sale_lines, self.factor)
        for date in date_list:
            for partner in result.keys():
                for product in result[partner].keys():
                    prod_vals = result[partner][product]
                    forecast_line_vals = {
                        'product_id': product,
                        'forecast_id': self.forecast_id.id,
                        'partner_id': partner,
                        'date': date,
                        'qty': (prod_vals['qty'] / month_count),
                        'unit_price': (prod_vals['amount'] / prod_vals['qty'])
                    }
                    forecast_line_obj.create(forecast_line_vals)
        return True
class report_stock_forecast(models.Model):
    _name = 'report.stock.forecast'
    _auto = False

    date = fields.Date(string='Date')
    product_id = fields.Many2one('product.product',
                                 string='Product',
                                 readonly=True)
    product_tmpl_id = fields.Many2one('product.template',
                                      string='Product',
                                      related='product_id.product_tmpl_id',
                                      readonly=True)
    cumulative_quantity = fields.Float(string='Cumulative Quantity',
                                       readonly=True)
    quantity = fields.Float(readonly=True)

    def init(self, cr):
        tools.drop_view_if_exists(cr, 'report_stock_forecast')
        cr.execute("""CREATE or REPLACE VIEW report_stock_forecast AS (SELECT
        MIN(id) as id,
        product_id as product_id,
        date as date,
        sum(product_qty) AS quantity,
        sum(sum(product_qty)) OVER (PARTITION BY product_id ORDER BY date) AS cumulative_quantity
        FROM
        (SELECT
        MIN(id) as id,
        MAIN.product_id as product_id,
        SUB.date as date,
        CASE WHEN MAIN.date = SUB.date THEN sum(MAIN.product_qty) ELSE 0 END as product_qty
        FROM
        (SELECT
            MIN(sq.id) as id,
            sq.product_id,
            date_trunc('week', to_date(to_char(CURRENT_DATE, 'YYYY/MM/DD'), 'YYYY/MM/DD')) as date,
            SUM(sq.qty) AS product_qty
            FROM
            stock_quant as sq
            LEFT JOIN
            product_product ON product_product.id = sq.product_id
            LEFT JOIN
            stock_location location_id ON sq.location_id = location_id.id
            WHERE
            location_id.usage = 'internal'
            GROUP BY date, sq.product_id
            UNION ALL
            SELECT
            MIN(-sm.id) as id,
            sm.product_id,
            CASE WHEN sm.date_expected > CURRENT_DATE
            THEN date_trunc('week', to_date(to_char(sm.date_expected, 'YYYY/MM/DD'), 'YYYY/MM/DD'))
            ELSE date_trunc('week', to_date(to_char(CURRENT_DATE, 'YYYY/MM/DD'), 'YYYY/MM/DD')) END
            AS date,
            SUM(sm.product_qty) AS product_qty
            FROM
               stock_move as sm
            LEFT JOIN
               product_product ON product_product.id = sm.product_id
            LEFT JOIN
            stock_location dest_location ON sm.location_dest_id = dest_location.id
            LEFT JOIN
            stock_location source_location ON sm.location_id = source_location.id
            WHERE
            sm.state IN ('confirmed','assigned','waiting') and
            source_location.usage != 'internal' and dest_location.usage = 'internal'
            GROUP BY sm.date_expected,sm.product_id
            UNION ALL
            SELECT
                MIN(-sm.id) as id,
                sm.product_id,
                CASE WHEN sm.date_expected > CURRENT_DATE
                    THEN date_trunc('week', to_date(to_char(sm.date_expected, 'YYYY/MM/DD'), 'YYYY/MM/DD'))
                    ELSE date_trunc('week', to_date(to_char(CURRENT_DATE, 'YYYY/MM/DD'), 'YYYY/MM/DD')) END
                AS date,
                SUM(-(sm.product_qty)) AS product_qty
            FROM
               stock_move as sm
            LEFT JOIN
               product_product ON product_product.id = sm.product_id
            LEFT JOIN
               stock_location source_location ON sm.location_id = source_location.id
            LEFT JOIN
               stock_location dest_location ON sm.location_dest_id = dest_location.id
            WHERE
                sm.state IN ('confirmed','assigned','waiting') and
            source_location.usage = 'internal' and dest_location.usage != 'internal'
            GROUP BY sm.date_expected,sm.product_id)
         as MAIN
     LEFT JOIN
     (SELECT DISTINCT date
      FROM
      (
             SELECT date_trunc('week', CURRENT_DATE) AS DATE
             UNION ALL
             SELECT date_trunc('week', to_date(to_char(sm.date_expected, 'YYYY/MM/DD'), 'YYYY/MM/DD')) AS date
             FROM stock_move sm
             LEFT JOIN
             stock_location source_location ON sm.location_id = source_location.id
             LEFT JOIN
             stock_location dest_location ON sm.location_dest_id = dest_location.id
             WHERE
             sm.state IN ('confirmed','assigned','waiting') and sm.date_expected > CURRENT_DATE and
             ((dest_location.usage = 'internal' AND source_location.usage != 'internal')
              or (source_location.usage = 'internal' AND dest_location.usage != 'internal'))) AS DATE_SEARCH)
             SUB ON (SUB.date IS NOT NULL)
    GROUP BY MAIN.product_id,SUB.date, MAIN.date
    ) AS FINAL
    GROUP BY product_id,date)""")
Example #30
0
class ProcurementSaleForecast(models.Model):
    _name = 'procurement.sale.forecast'

    @api.one
    @api.depends('forecast_lines.procurement_id')
    def _get_procurement_count(self):
        procurement_lst = []
        for line in self.forecast_lines:
            if line.procurement_id:
                procurement_lst.append(line.procurement_id.id)
        self.procurement_count = len(procurement_lst)

    name = fields.Char(string='Name', required=True)
    date_from = fields.Date(string='Date From', required=True)
    date_to = fields.Date(string='Date To', required=True)
    forecast_lines = fields.One2many('procurement.sale.forecast.line',
                                     'forecast_id',
                                     string="Forecast Lines")
    warehouse_id = fields.Many2one('stock.warehouse', string="Warehouse")
    procurement_count = fields.Integer(string="Procurement Count",
                                       compute=_get_procurement_count)

    @api.one
    @api.constrains('date_from', 'date_to')
    def check_dates(self):
        if self.date_from >= self.date_to:
            raise exceptions.Warning(
                _('Error! Date to must be lower '
                  'than date from.'))

    @api.multi
    def create_procurements(self):
        procurement_obj = self.env['procurement.order']
        procure_lst = []
        for record in self:
            for product_line in record.forecast_lines:
                if product_line.product_id and not product_line.procurement_id:
                    procure_id = procurement_obj.create({
                        'name': ('MPS: ' + record.name + ' (' +
                                 record.date_from + '.' + record.date_to +
                                 ') ' + record.warehouse_id.name),
                        'date_planned':
                        product_line.date,
                        'product_id':
                        product_line.product_id.id,
                        'product_qty':
                        product_line.qty,
                        'product_uom':
                        product_line.product_id.uom_id.id,
                        'location_id':
                        record.warehouse_id.lot_stock_id.id,
                        'company_id':
                        record.warehouse_id.company_id.id,
                        'warehouse_id':
                        record.warehouse_id.id,
                    })
                    procure_id.signal_workflow('button_confirm')
                    procure_lst.append(procure_id.id)
                    product_line.procurement_id = procure_id.id
        return {
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'procurement.order',
            'res_ids': procure_lst,
            'domain': [('id', 'in', procure_lst)],
            'type': 'ir.actions.act_window',
        }

    @api.multi
    def show_all_forecast_procurements(self):
        procurement_list = []
        for record in self:
            for line in record.forecast_lines:
                if line.procurement_id:
                    procurement_list.append(line.procurement_id.id)
        return {
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'procurement.order',
            'res_ids': procurement_list,
            'domain': [('id', 'in', procurement_list)],
            'type': 'ir.actions.act_window',
        }