You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							198 lines
						
					
					
						
							7.0 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							198 lines
						
					
					
						
							7.0 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| from odoo import api, fields, models, _ | |
| from odoo.exceptions import UserError | |
| 
 | |
| 
 | |
| class GymAttendance(models.Model): | |
|     """Simple Gym Attendance Model""" | |
|     _name = 'gym.attendance' | |
|     _description = 'Gym Attendance' | |
|     _order = 'check_in desc' | |
|     _rec_name = 'member_id' | |
| 
 | |
|     member_id = fields.Many2one('res.partner', string='Member', required=True, | |
|                                 domain="[('is_gym_member', '=', True)]") | |
|     check_in = fields.Datetime(string='Check In', required=True, | |
|                                default=fields.Datetime.now) | |
|     check_out = fields.Datetime(string='Check Out') | |
| 
 | |
|     duration = fields.Float(string='Duration (Hours)', | |
|                             compute='_compute_duration', store=True) | |
| 
 | |
|     state = fields.Selection([ | |
|         ('checked_in', 'Checked In'), | |
|         ('checked_out', 'Checked Out') | |
|     ], string='State', compute='_compute_state', store=True) | |
| 
 | |
|     @api.depends('check_out') | |
|     def _compute_state(self): | |
|         for record in self: | |
|             record.state = 'checked_out' if record.check_out else 'checked_in' | |
| 
 | |
|     @api.depends('check_in', 'check_out') | |
|     def _compute_duration(self): | |
|         for record in self: | |
|             if record.check_in and record.check_out: | |
|                 delta = record.check_out - record.check_in | |
|                 record.duration = delta.total_seconds() / 3600 | |
|             else: | |
|                 record.duration = 0.0 | |
| 
 | |
|     @api.model | |
|     def create(self, vals): | |
|         """Override create to validate BEFORE creating the record""" | |
|         if 'member_id' in vals: | |
|             member_id = vals['member_id'] | |
| 
 | |
|             existing_checkin = self.search([ | |
|                 ('member_id', '=', member_id), | |
|                 ('check_out', '=', False) | |
|             ]) | |
| 
 | |
|             if existing_checkin: | |
|                 member_name = self.env['res.partner'].browse(member_id).name | |
|                 raise UserError(_('%s is already checked in at %s. Please check out first.') % | |
|                                 (member_name, existing_checkin.check_in.strftime('%Y-%m-%d %H:%M:%S'))) | |
| 
 | |
|             member = self.env['res.partner'].browse(member_id) | |
|             validation = self._validate_member_can_checkin(member) | |
|             if not validation['can_checkin']: | |
|                 raise UserError(validation['message']) | |
| 
 | |
|         return super(GymAttendance, self).create(vals) | |
| 
 | |
|     def write(self, vals): | |
|         """Override write to validate member changes""" | |
|         if 'member_id' in vals: | |
|             existing_checkin = self.env['gym.attendance'].search([ | |
|                 ('member_id', '=', vals['member_id']), | |
|                 ('check_out', '=', False), | |
|                 ('id', 'not in', self.ids) | |
|             ]) | |
| 
 | |
|             if existing_checkin: | |
|                 member_name = self.env['res.partner'].browse(vals['member_id']).name | |
|                 raise UserError(_('%s is already checked in. Cannot change to this member.') % member_name) | |
| 
 | |
|         return super(GymAttendance, self).write(vals) | |
| 
 | |
|     def action_check_in(self): | |
|         """Check in a member - simplified since validation is now in create()""" | |
|         self.ensure_one() | |
| 
 | |
|         return { | |
|             'type': 'ir.actions.client', | |
|             'tag': 'display_notification', | |
|             'params': { | |
|                 'message': f'Welcome {self.member_id.name}! Check-in successful.', | |
|                 'type': 'success', | |
|                 'sticky': False, | |
|             } | |
|         } | |
| 
 | |
|     def _validate_member_can_checkin(self, member): | |
|         """Validate if member can check in - returns dict with can_checkin boolean and message""" | |
| 
 | |
|         active_memberships = self.env['gym.membership'].search([ | |
|             ('member_id', '=', member.id), | |
|             ('state', '=', 'active') | |
|         ]) | |
| 
 | |
|         active_membership = None | |
|         if active_memberships: | |
|             if len(active_memberships) == 1: | |
|                 active_membership = active_memberships | |
|             else: | |
|                 active_membership = max(active_memberships, | |
|                                         key=lambda m: m.effective_end_date or fields.Date.today()) | |
| 
 | |
|         if active_membership: | |
|             if active_membership.effective_end_date and active_membership.effective_end_date < fields.Date.today(): | |
|                 active_membership.action_expire() | |
|             else: | |
|                 return { | |
|                     'can_checkin': True, | |
|                     'message': _('Check-in allowed.') | |
|                 } | |
| 
 | |
|         any_membership = self.env['gym.membership'].search([ | |
|             ('member_id', '=', member.id) | |
|         ], order='id desc', limit=1) | |
| 
 | |
|         if not any_membership: | |
|             return { | |
|                 'can_checkin': False, | |
|                 'message': _('No membership found for this member.') | |
|             } | |
| 
 | |
|         if any_membership.state == 'paused': | |
|             return { | |
|                 'can_checkin': False, | |
|                 'message': _( | |
|                     'Cannot check in. Your latest membership is PAUSED.\n' | |
|                     'Please resume your membership to check in.' | |
|                 ) | |
|             } | |
|         elif any_membership.state == 'expired': | |
|             return { | |
|                 'can_checkin': False, | |
|                 'message': _( | |
|                     'Cannot check in. Your latest membership has EXPIRED.\n' | |
|                     'Please renew your membership to continue.' | |
|                 ) | |
|             } | |
|         elif any_membership.state in ['draft', 'confirm']: | |
|             return { | |
|                 'can_checkin': False, | |
|                 'message': _( | |
|                     'Cannot check in. Your membership is not yet active.\n' | |
|                     'Please wait for activation or contact support.' | |
|                 ) | |
|             } | |
|         else: | |
|             return { | |
|                 'can_checkin': False, | |
|                 'message': _( | |
|                     'Cannot check in. Membership status: %s' | |
|                 ) % any_membership.state.title() | |
|             } | |
| 
 | |
|     def action_check_out(self): | |
|         """Check out manually""" | |
|         self.ensure_one() | |
|         if self.check_out: | |
|             raise UserError(_('Already checked out.')) | |
| 
 | |
|         self.check_out = fields.Datetime.now() | |
| 
 | |
|         return { | |
|             'type': 'ir.actions.client', | |
|             'tag': 'display_notification', | |
|             'params': { | |
|                 'message': f'Goodbye {self.member_id.name}! Duration: {self.duration:.2f} hours', | |
|                 'type': 'success', | |
|                 'sticky': False, | |
|             } | |
|         } | |
| 
 | |
|     @api.model | |
|     def quick_checkin(self, member_id): | |
|         """Method for quick check-in from external calls""" | |
|         member = self.env['res.partner'].browse(member_id) | |
|         if not member.exists(): | |
|             raise UserError(_('Member not found.')) | |
| 
 | |
|         attendance = self.create({ | |
|             'member_id': member_id, | |
|             'check_in': fields.Datetime.now(), | |
|         }) | |
| 
 | |
|         return { | |
|             'type': 'ir.actions.client', | |
|             'tag': 'display_notification', | |
|             'params': { | |
|                 'message': f'Welcome {member.name}! Check-in successful.', | |
|                 'type': 'success', | |
|                 'sticky': False, | |
|             } | |
|         } |