first push message
This commit is contained in:
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,27 @@
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
class SignupError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ck_res_parter(models.Model):
|
||||
|
||||
_name = "res.partner"
|
||||
_inherit = "res.partner"
|
||||
_description = "Partner"
|
||||
|
||||
@api.model
|
||||
def _signup_retrieve_partner(self, token, check_validity=False, raise_exception=False):
|
||||
if self.search(['&', '&', ('signup_token', '=', token), ('signup_expiration', '=', False), ('active', '=', False)]):
|
||||
partner = self.search(['&', ('signup_token', '=', token), ('active', '=', False)], limit=1)
|
||||
else:
|
||||
partner = self.search([('signup_token', '=', token)], limit=1)
|
||||
if not partner:
|
||||
if raise_exception:
|
||||
raise SignupError("Signup token '%s' is not valid" % token)
|
||||
return False
|
||||
if check_validity and not partner.signup_valid:
|
||||
if raise_exception:
|
||||
raise SignupError("Signup token '%s' is no longer valid" % token)
|
||||
return False
|
||||
return partner
|
||||
@@ -0,0 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from ast import literal_eval
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
class CkSetting(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
intern = fields.Boolean(string="Enable Intern")
|
||||
exam = fields.Boolean(string="Enable Exam")
|
||||
@@ -0,0 +1,323 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
import random
|
||||
import base64
|
||||
from io import BytesIO
|
||||
|
||||
from odoo import api, fields, models, _, tools
|
||||
from odoo.exceptions import UserError, AccessError
|
||||
from odoo.addons.base.models.ir_mail_server import MailDeliveryException
|
||||
from odoo.addons.auth_signup.models.res_partner import SignupError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import qrcode
|
||||
from qrcode.constants import ERROR_CORRECT_L
|
||||
except ImportError:
|
||||
qrcode = None
|
||||
ERROR_CORRECT_L = None
|
||||
|
||||
|
||||
class MainPin(models.Model):
|
||||
_name = 'main.pin'
|
||||
_description = 'SHS Code'
|
||||
_rec_name = 'custom_group_label'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
|
||||
data_term = fields.Integer(string="ចំនួនប្រតិបត្ដិការ", default=1)
|
||||
name = fields.Char(string="ផ្សេងៗ")
|
||||
pin_code_id = fields.One2many('pin.spm', 'main_id', string="តារាងលេខកូដ", readonly=True)
|
||||
reviewer_code = fields.Many2one('res.users', string="អ្នកទទួលលេខកូដ", domain="[('active', '=', True)]")
|
||||
groups_id = fields.Many2many('res.groups', string="Access Rights")
|
||||
custom_group_label = fields.Char(string="Group Label")
|
||||
link_qr = fields.Binary("QR Link", compute='_generate_qrcode', store=False)
|
||||
file_name = fields.Char(string="ឈ្មោះឯកសារយោង")
|
||||
files = fields.Binary(string="ឯកសារយោង")
|
||||
check_con = fields.Boolean(string="បន្ដការសិក្សាថ្នាក់ឧត្ដមសិក្សា")
|
||||
selection_data = fields.Selection([
|
||||
('0', 'ថ្នាក់មហាវិទ្យាល័យ'),
|
||||
('01', 'ថ្នាក់មត្ដេយ្យ, មធ្យម និងមធ្យមសិក្សាទុតិយភូមិ'),
|
||||
('1', 'សិស្សបន្ដការសិក្សា(មកពីប្រទេសថៃ)')
|
||||
], string="កម្រិតអាហារូបករណ៍", default='0')
|
||||
school_kind = fields.Many2one('univer.univer', string="សាលាដែលទទួលបាន",
|
||||
domain="[('grade_study','in',('01','1','2','3','4'))]")
|
||||
pass_percent = fields.Float(string="%")
|
||||
requester = fields.Char(string="គោលដៅ")
|
||||
|
||||
# ✅ FIXED: Removed 'id' dependency. Empty depends() means "compute on access"
|
||||
@api.depends()
|
||||
def _generate_qrcode(self):
|
||||
login_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url',
|
||||
'https://reg.amt.live') + '/web/login'
|
||||
for record in self:
|
||||
record.link_qr = False
|
||||
if not (qrcode and ERROR_CORRECT_L):
|
||||
continue
|
||||
try:
|
||||
qr = qrcode.QRCode(version=1, error_correction=ERROR_CORRECT_L, box_size=4, border=2)
|
||||
qr.add_data(login_url)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image(fill_color="black", back_color="white")
|
||||
buffered = BytesIO()
|
||||
img.save(buffered, format="PNG")
|
||||
record.link_qr = base64.b64encode(buffered.getvalue())
|
||||
except Exception as e:
|
||||
_logger.error(f"QR generation failed for {record.id}: {e}")
|
||||
|
||||
@api.onchange('data_term')
|
||||
def _onchange_data_term(self):
|
||||
default_group = self.env.ref("register_v15.groups_amt", raise_if_not_found=False)
|
||||
if default_group:
|
||||
self.groups_id = [(6, 0, [default_group.id])]
|
||||
self.custom_group_label = 'ផ្គូផ្គង'
|
||||
|
||||
@api.constrains('data_term')
|
||||
def _check_data_term(self):
|
||||
for rec in self:
|
||||
if rec.data_term < 1:
|
||||
raise UserError(_("ចំនួនប្រតិបត្ដិការត្រូវតែយ៉ាងតិច 1"))
|
||||
if rec.data_term > 1000:
|
||||
raise UserError(_("ចំនួនប្រតិបត្ដិការអតិបរមាគឺ 1000"))
|
||||
|
||||
def compute_code(self):
|
||||
self.ensure_one()
|
||||
if not self.data_term or self.data_term < 1:
|
||||
raise UserError(_("សូមបញ្ចូលចំនួនប្រតិបត្ដិការ"))
|
||||
|
||||
target_group = self.env.ref("register_v15.groups_amt", raise_if_not_found=False)
|
||||
pin_records = []
|
||||
created_users = []
|
||||
failed_count = 0
|
||||
|
||||
for i in range(1, self.data_term + 1):
|
||||
pin_code = str(random.randint(100000, 999999))
|
||||
identifier = f"{self.name or 'PIN'}{pin_code}{i:03d}"
|
||||
valid_email = f"{identifier.lower()}@reg.amt.live"
|
||||
|
||||
pin_records.append((0, 0, {
|
||||
'name': identifier,
|
||||
'data_rec': self.name or '',
|
||||
'main_id': self.id,
|
||||
}))
|
||||
|
||||
user_vals = {
|
||||
'name': identifier,
|
||||
'login': identifier,
|
||||
'email': valid_email,
|
||||
'password': identifier,
|
||||
'active': True,
|
||||
'first_login': True,
|
||||
'kind': self.selection_data,
|
||||
'pin_code': pin_code,
|
||||
'groups': self.custom_group_label or 'ប្រឡង',
|
||||
}
|
||||
|
||||
# ✅ Use standard Odoo field name: groups_id
|
||||
if target_group:
|
||||
user_vals['group_ids'] = [(4, target_group.id)]
|
||||
elif self.groups_id:
|
||||
user_vals['group_ids'] = [(6, 0, self.groups_id.ids)]
|
||||
|
||||
try:
|
||||
# 🔒 Prevent password reset emails from triggering
|
||||
user = self.env['res.users'].sudo().with_context(no_reset_password=True).create(user_vals)
|
||||
|
||||
# 📝 Optional: Log for verification
|
||||
_logger.info(f"✅ Created: {user.login} | Password={pin_code} | Groups={user.group_ids.mapped('name')}")
|
||||
created_users.append(user)
|
||||
except Exception as e:
|
||||
failed_count += 1
|
||||
_logger.error(f"❌ Failed to create '{identifier}': {e}", exc_info=True)
|
||||
continue
|
||||
|
||||
if pin_records:
|
||||
self.pin_code_id = pin_records
|
||||
|
||||
if failed_count > 0:
|
||||
return {
|
||||
'type': 'ir.actions.client', 'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('បញ្ហា!'),
|
||||
'message': _('បានបង្កើត %d, បរាជ័យ %d។ ពិនិត្យ log!') % (len(created_users), failed_count),
|
||||
'type': 'warning', 'sticky': True,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client', 'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('ជោគជ័យ!'),
|
||||
'message': _('បានបង្កើត %d លេខកូដ និងគណនីដោយជោគជ័យ') % len(created_users),
|
||||
'type': 'success', 'sticky': False,
|
||||
}
|
||||
}
|
||||
|
||||
def get_spm_code(self):
|
||||
target_group = self.env.ref("register_v15.groups_amt", raise_if_not_found=False)
|
||||
for code in self.pin_code_id.filtered(lambda c: not c.status):
|
||||
user = self.env['res.users'].sudo().search([('login', '=', code.name), ('active', '=', False)], limit=1)
|
||||
if not user:
|
||||
continue
|
||||
update_vals = {'active': True, 'first_login': True, 'kind': self.selection_data}
|
||||
if target_group and target_group not in user.groups_id:
|
||||
update_vals['groups_id'] = [(4, target_group.id)]
|
||||
user.write(update_vals)
|
||||
code.write({'status': True})
|
||||
return True
|
||||
|
||||
|
||||
class PinSPM(models.Model):
|
||||
_name = "pin.spm"
|
||||
_description = "Pin Code for Scholarship"
|
||||
_inherit = ['mail.thread']
|
||||
|
||||
name = fields.Char(index=True, default=lambda self: _('New'), string="លេខកូដ", readonly=True)
|
||||
data = fields.Integer(string="ចំនួនប្រតិបត្ដិការ")
|
||||
status = fields.Boolean(default=False, string="Used")
|
||||
reviewer_ids = fields.Many2many('res.users', string="អ្នកត្រួតពិនិត្យលើ")
|
||||
main_id = fields.Many2one('main.pin', string="Main Reference", ondelete='cascade', required=True)
|
||||
data_rec = fields.Char(string="ឈ្មោះខេត្ដ/ក្រុង ផ្សេងៗ")
|
||||
reviewer = fields.Many2one("res.users", string="អ្នកទទួលលេខកូដ")
|
||||
user_use_code = fields.Many2one('res.users', string="ឈ្មោះអ្នកប្រើប្រាស់", readonly=True)
|
||||
info_name = fields.Many2one('info.info', string="ឈ្មោះក្នុងទំរងបំពេញពាក្យ")
|
||||
|
||||
name_info = fields.Char(related="info_name.name", store=True, readonly=False, string="Name")
|
||||
email = fields.Char(related="info_name.email", store=True, readonly=True, string="Email")
|
||||
gender = fields.Many2one(related="info_name.gender", store=True, readonly=False, string="Gender")
|
||||
eng_name = fields.Char(related="info_name.eng_name", store=True, readonly=False, string="English Name")
|
||||
dob = fields.Date(related="info_name.dob", store=True, readonly=False, string="DOB")
|
||||
id_card = fields.Char(related="info_name.id_card", store=True, readonly=False, string="ID Card")
|
||||
phone = fields.Char(related="info_name.phone", store=True, readonly=False, string="Phone")
|
||||
study_level = fields.Selection(related="info_name.grade_study", store=True, readonly=False, string="Study Level")
|
||||
create_uids = fields.Many2one(related="info_name.create_uid", store=True, readonly=False, string="Created By")
|
||||
group_register = fields.Char(related="info_name.groups", store=True, readonly=False, string="Registration Group")
|
||||
|
||||
def check_use_code(self):
|
||||
active_ids = self.env.context.get('active_ids')
|
||||
if not active_ids:
|
||||
return False
|
||||
success = 0
|
||||
for code in self.browse(active_ids):
|
||||
if code.status:
|
||||
continue
|
||||
user = self.env['res.users'].sudo().search([('login', '=', code.name), ('active', '=', False)], limit=1)
|
||||
if not user:
|
||||
continue
|
||||
user.write({'active': True, 'x_pin_code_spm': code.id, 'first_login': True})
|
||||
info_user = self.env['info.info'].sudo().search(
|
||||
['|', ('create_uid', '=', user.id), ('email', '=', user.login)], limit=1)
|
||||
code.write({'info_name': info_user.id if info_user else False, 'user_use_code': user.id, 'status': True})
|
||||
if info_user and not info_user.x_manager and code.reviewer:
|
||||
info_user.x_manager = code.reviewer
|
||||
success += 1
|
||||
return {
|
||||
'type': 'ir.actions.client', 'tag': 'display_notification',
|
||||
'params': {'title': _('ជោគជ័យ'), 'message': _('បានផ្ទៀងផ្ទាត់ %d លេខកូដ') % success, 'type': 'success'}
|
||||
} if success else False
|
||||
|
||||
|
||||
class ReviewGroups(models.Model):
|
||||
_name = 'rev.groups'
|
||||
_description = 'Groups Review'
|
||||
name = fields.Char(string="SHS Name", required=True, translate=True)
|
||||
active = fields.Boolean(default=True)
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_name = "res.users"
|
||||
_inherit = ["res.users", "mail.thread", "mail.activity.mixin"]
|
||||
_description = "Signup User"
|
||||
|
||||
pin_code = fields.Char(string='PIN Code', size=6)
|
||||
is_sending_email = fields.Boolean(string="Email Sent", default=False)
|
||||
count_request_pin_code = fields.Integer(string="PIN Request Count", default=0)
|
||||
groups = fields.Char(string="Group Label")
|
||||
kind = fields.Char(string="Kind/Type")
|
||||
first_login = fields.Boolean(default=True)
|
||||
x_pin_code_spm = fields.Many2one('pin.spm', string="Pin Code SPM",
|
||||
domain="[('name','=',login), ('status','=',False)]")
|
||||
x_code_name = fields.Char(related='x_pin_code_spm.name', string='Code Name', store=True, readonly=True)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
users = super(ResUsers, self).create(vals_list)
|
||||
template = self.env.ref('ck_signup.sending_pin_code_template', raise_if_not_found=False)
|
||||
for user in users:
|
||||
if self._context.get('skip_email_sending') or not template or not user.email:
|
||||
continue
|
||||
pin = str(random.randint(100000, 999999))
|
||||
user.write({'pin_code': pin, 'active': False, 'first_login': True, 'groups': 'ប្រឡង',
|
||||
'is_sending_email': True})
|
||||
self._send_pin_email(user, pin, template)
|
||||
return users
|
||||
|
||||
def _send_pin_email(self, user, pin_code, template):
|
||||
try:
|
||||
company = self.env.company
|
||||
mail_from = company.email or tools.config.get('email_from') or 'noreply@localhost'
|
||||
body = f"""
|
||||
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: auto; padding: 20px; border: 1px solid #eee; border-radius: 8px;">
|
||||
<h3 style="color: #2c3e50;">{_('Pin Code ដើម្បីផ្ទៀងផ្ទាត់គណនី')}</h3>
|
||||
<p>{template.body_html or ''}</p>
|
||||
<div style="background: #f8f9fa; padding: 15px; border-left: 4px solid #3498db; margin: 20px 0; text-align: center;">
|
||||
<strong style="font-size: 18px;">លេខកូដផ្ទៀងផ្ទាត់:</strong><br>
|
||||
<span style="font-size: 28px; letter-spacing: 6px; font-weight: bold; color: #e74c3c;">{pin_code}</span>
|
||||
</div>
|
||||
<p>{_('សូមបញ្ចូលលេខកូដខាងលើ រួចចុច ផ្ទៀងផ្ទាត់!')}</p>
|
||||
</div>"""
|
||||
self.env['mail.mail'].sudo().create({
|
||||
'subject': _('Pin Code ដើម្បីផ្ទៀងផ្ទាត់ - %s') % company.name,
|
||||
'email_from': mail_from, 'email_to': user.email, 'body_html': body, 'auto_delete': True,
|
||||
}).send()
|
||||
except Exception as e:
|
||||
_logger.error(f"Failed to send PIN to {user.email}: {e}")
|
||||
|
||||
@api.model
|
||||
def signup(self, values, token=None):
|
||||
if token:
|
||||
partner = self.env['res.partner'].sudo()._signup_retrieve_partner(token, check_validity=True,
|
||||
raise_exception=True)
|
||||
partner.write({'signup_token': False, 'signup_type': False, 'signup_expiration': False})
|
||||
user = self.env['res.users'].sudo().search([('partner_id', '=', partner.id), ('active', '=', False)],
|
||||
limit=1)
|
||||
for f in ['city', 'country_id', 'lang', 'tz']: values.pop(f, None)
|
||||
if user:
|
||||
values.pop('login', None);
|
||||
values.pop('name', None)
|
||||
user.write(values)
|
||||
return self.env.cr.dbname, user.login, values.get('password')
|
||||
else:
|
||||
values.update({'name': partner.name, 'partner_id': partner.id,
|
||||
'email': values.get('email') or values.get('login')})
|
||||
if partner.company_id:
|
||||
values['company_id'] = partner.company_id.id
|
||||
values['company_ids'] = [(6, 0, [partner.company_id.id])]
|
||||
return self._signup_create_user(values)
|
||||
else:
|
||||
values['email'] = values.get('email') or values.get('login')
|
||||
return self._signup_create_user(values)
|
||||
|
||||
def _signup_create_user(self, values):
|
||||
values.setdefault('active', False)
|
||||
values.setdefault('first_login', True)
|
||||
user = self.with_context(skip_email_sending=True).sudo().create(values)
|
||||
return self.env.cr.dbname, user.login, values.get('password')
|
||||
|
||||
def generate_and_send_new_pin_code(self, login=None):
|
||||
user = self.env['res.users'].sudo().search([('login', '=', login), ('active', '=', False)],
|
||||
limit=1) if login else self
|
||||
if not user or user.count_request_pin_code >= 5: return False
|
||||
template = self.env.ref('ck_signup.sending_pin_code_template', raise_if_not_found=False)
|
||||
if not template: return False
|
||||
new_pin = str(random.randint(100000, 999999))
|
||||
user.write({'pin_code': new_pin, 'count_request_pin_code': user.count_request_pin_code + 1})
|
||||
self._send_pin_email(user, new_pin, template)
|
||||
return True
|
||||
|
||||
def verify_pin_code(self, pin_input):
|
||||
self.ensure_one()
|
||||
if not self.pin_code or pin_input != self.pin_code:
|
||||
return False
|
||||
self.write({'active': True, 'pin_code': False, 'first_login': True})
|
||||
return True
|
||||
Reference in New Issue
Block a user