添加功能

This commit is contained in:
李鹏宇
2026-01-06 20:57:35 +08:00
parent 4e9d03107e
commit 08e3d611b3
22 changed files with 509 additions and 12 deletions
+6
View File
@@ -31,10 +31,14 @@
'views/yuthon_salary_documents_views.xml',
'views/yuthon_welfare_expenses_views.xml',
'views/yuthon_payroll_retired_views.xml',
'views/yuthon_meal_expenses_views.xml',
'views/yuthon_salary_year_views.xml',
'wizard/rank_log_wizard_views.xml',
'wizard/salary_meal_wizard_views.xml',
'wizard/yuthon_salary_wizard_views.xml',
'wizard/salary_party_wizard_views.xml',
'wizard/party_send_wizard_views.xml',
'wizard/party_meal_wizard_views.xml',
'wizard/temporary_payslip_wizard_views.xml',
'wizard/salary_import_wizard_views.xml',
'wizard/yuthon_payroll_wizard_views.xml',
@@ -64,6 +68,8 @@
'yuthon_salary/static/src/js/salary_validation_button.js',
'yuthon_salary/static/src/js/salary_year_button.js',
'yuthon_salary/static/src/js/salary_import_button.js',
'yuthon_salary/static/src/js/salary_meal_button.js',
'yuthon_salary/static/src/xml/salary_meal_button.xml',
'yuthon_salary/static/src/xml/salary_create_button.xml',
'yuthon_salary/static/src/xml/salary_labor_button.xml',
'yuthon_salary/static/src/xml/salary_import_button.xml',
+2 -1
View File
@@ -15,4 +15,5 @@ from . import yuthon_welfare_expenses
from . import inherit_hr_payslip_run
from . import inherit_hr_payslip_line
from . import yuthon_salary_party
from . import yuthon_individual_tax
from . import yuthon_individual_tax
from . import yuthon_meal_expenses
@@ -0,0 +1,45 @@
from odoo import api, fields, models
from datetime import datetime
import calendar
class YuthonMealExpenses(models.Model):
_name = 'yuthon.meal.expenses'
_description = '餐费'
employee_id = fields.Many2one('hr.employee', string='姓名')
card = fields.Char(string='身份证')
number_breakfasts = fields.Integer(string='早餐次数')
number_lunches = fields.Integer(string='午餐次数')
total_payment = fields.Float(string='合计缴费')
company_id = fields.Many2one(related='employee_id.company_id', string="公司")
select_time = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'),
('5', '五月'), ('6', '六月'), ('7', '七月'), ('8', '八月'),
('9', '九月'), ('10', '十月'), ('11', '十一月'),
('12', '十二月')], string='月份',
default=lambda self: self._get_default_month())
select_year = fields.Selection(selection=[(str(i), str(i)) for i in range(2024, 2040)], string='年份',
default=lambda self: str(datetime.now().year))
meal_state = fields.Selection([('to_do', '待发送'), ('done', '已发送')], string='状态', default='to_do')
def _get_default_month(self):
current_month = datetime.now().month
return str(current_month)
def send_meal(self):
year = self.select_year or datetime.now().year
month = self.select_time or datetime.now().month
last_day = calendar.monthrange(year, month)[1]
message = f"""致{self.employee_id.name}:
{self.select_year}年{self.select_time}月 早餐{self.number_breakfasts} 次、午餐{self.number_lunches} 次,按餐标核算,
本月餐费合计{self.total_payment}元。缴费截止{self.select_year}年{self.select_time}月{last_day}日],可汇入账户:[账户信息]。异议请联系行政部 [联系方式]。
办公室
{fields.Date.today()}"""
self.sudo().env["wecom.apps"].sync_send_message(
category='att',
user_id=self.employee_id.wecom_userid,
message=message,
)
self.write({'party_state': 'done'})
+25 -1
View File
@@ -1,4 +1,5 @@
from odoo import api, fields, models
from datetime import datetime
class YuthonSalaryParty(models.Model):
@@ -6,12 +7,35 @@ class YuthonSalaryParty(models.Model):
_description = '党建'
employee_id = fields.Many2one('hr.employee', string='姓名')
phone = fields.Char(string='手机')
card = fields.Char(string='身份找')
fee = fields.Float(string='党费')
payment = fields.Float(string='补缴党费')
total_payment = fields.Float(string='合计缴费')
company_id = fields.Many2one(related='employee_id.company_id', string="公司")
select_time = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'),
('5', '五月'), ('6', '六月'), ('7', '七月'), ('8', '八月'),
('9', '九月'), ('10', '十月'), ('11', '十一月'),
('12', '十二月')], string='月份',
default=lambda self: self._get_default_month())
select_year = fields.Selection(selection=[(str(i), str(i)) for i in range(2024, 2040)], string='年份',
default=lambda self: str(datetime.now().year))
party_state = fields.Selection([('to_do', '待发送'), ('done', '已发送')], string='状态', default='to_do')
def _get_default_month(self):
current_month = datetime.now().month
return str(current_month)
def send_party(self):
pay_year_month = self.select_year + '年' + self.select_time + '月'
message = f"""【{pay_year_month}缴纳党费通知】:
请于{fields.Date.today()}(今天)15:00前将党费按时汇入账户:44001580909059000222 广州市天河投资集团有限公司,
并在群里告知汇款完毕。
您当月的缴费金额为{self.total_payment},其中党费{self.fee},补缴党费{self.payment}。"""
self.sudo().env["wecom.apps"].sync_send_message(
category='att',
user_id=self.employee_id.wecom_userid,
message=message,
)
self.write({'party_state': 'done'})
+6 -1
View File
@@ -39,4 +39,9 @@ access_yuthon_salary_party,access_yuthon_salary_party,model_yuthon_salary_party,
access_salary_party_wizard,access_salary_party_wizard,model_salary_party_wizard,base.group_user,1,1,1,1
access_salary_import_wizard,access_salary_import_wizard,model_salary_import_wizard,base.group_user,1,1,1,1
access_yuthon_individual_tax,access_yuthon_individual_tax,model_yuthon_individual_tax,base.group_user,1,1,1,1
access_yuthon_individual_tax,access_yuthon_individual_tax,model_yuthon_individual_tax,base.group_user,1,1,1,1
access_party_send_wizard,access_party_send_wizard,model_party_send_wizard,base.group_user,1,1,1,1
access_yuthon_meal_expenses,access_yuthon_meal_expenses,model_yuthon_meal_expenses,base.group_user,1,1,1,1
access_party_meal_wizard,access_party_meal_wizard,model_party_meal_wizard,base.group_user,1,1,1,1
access_salary_meal_wizard,access_salary_meal_wizard,model_salary_meal_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
39 access_party_send_wizard access_party_send_wizard model_party_send_wizard base.group_user 1 1 1 1
40 access_yuthon_meal_expenses access_yuthon_meal_expenses model_yuthon_meal_expenses base.group_user 1 1 1 1
41 access_party_meal_wizard access_party_meal_wizard model_party_meal_wizard base.group_user 1 1 1 1
42 access_salary_meal_wizard access_salary_meal_wizard model_salary_meal_wizard base.group_user 1 1 1 1
43
44
45
46
47
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,42 @@
/** @odoo-module */
import {ListController} from "@web/views/list/list_controller";
import {registry} from '@web/core/registry';
import {listView} from '@web/views/list/list_view';
export class CustomSalaryMealController extends ListController {
setup() {
super.setup();
}
openMealWizard() {
this.actionService.doAction({
type: 'ir.actions.act_window',
res_model: 'salary.meal.wizard',
name: '餐费导入',
view_mode: 'form',
view_type: 'form',
views: [[false, 'form']],
target: 'new',
context: {},
});
}
openMealSendWizard() {
this.actionService.doAction({
type: 'ir.actions.act_window',
res_model: 'party.meal.wizard',
name: '发送弹窗',
view_mode: 'form',
view_type: 'form',
views: [[false, 'form']],
target: 'new',
context: {},
});
}
}
registry.category("views").add("custom_meal_button", {
...listView,
Controller: CustomSalaryMealController,
buttonTemplate: "meal_module.ListView.Buttons"
});
@@ -20,6 +20,19 @@ export class CustomSalaryPartyController extends ListController {
context: {},
});
}
openPartySendWizard() {
this.actionService.doAction({
type: 'ir.actions.act_window',
res_model: 'party.send.wizard',
name: '发送弹窗',
view_mode: 'form',
view_type: 'form',
views: [[false, 'form']],
target: 'new',
context: {},
});
}
}
registry.category("views").add("custom_party_button", {
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<templates>
<t t-name="meal_module.ListView.Buttons" t-inherit="web.ListView.Buttons">
<xpath expr="//div[hasclass('o_list_buttons')]" position="after">
<button type="button" class="btn btn-primary" style="margin-left: 10px;" t-on-click="openMealWizard">
餐费导入
</button>
<button type="button" class="btn btn-primary" style="margin-left: 10px;" t-on-click="openMealSendWizard">
发送提醒
</button>
</xpath>
</t>
</templates>
@@ -5,6 +5,9 @@
<button type="button" class="btn btn-primary" style="margin-left: 10px;" t-on-click="openPartyWizard">
党建导入
</button>
<button type="button" class="btn btn-primary" style="margin-left: 10px;" t-on-click="openPartySendWizard">
发送提醒
</button>
</xpath>
</t>
</templates>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_yuthon_meal_expenses_tree" model="ir.ui.view">
<field name="name">yuthon.meal.expenses.tree</field>
<field name="model">yuthon.meal.expenses</field>
<field name="arch" type="xml">
<tree string="餐费" editable="bottom" js_class="custom_meal_button">
<field name="select_year"/>
<field name="select_time"/>
<field name="employee_id"/>
<field name="card"/>
<field name="number_breakfasts"/>
<field name="number_lunches"/>
<field name="total_payment"/>
<field name="company_id"/>
<field name="meal_state"/>
<button name="send_meal" string="发送" type="object" class="oe_highlight"/>
</tree>
</field>
</record>
<record id="view_yuthon_meal_expenses_action" model="ir.actions.act_window">
<field name="name">餐费</field>
<field name="res_model">yuthon.meal.expenses</field>
<field name="view_mode">tree</field>
</record>
</odoo>
@@ -5,12 +5,16 @@
<field name="model">yuthon.salary.party</field>
<field name="arch" type="xml">
<tree string="党建" editable="bottom" js_class="custom_party_button">
<field name="select_time"/>
<field name="select_year"/>
<field name="employee_id"/>
<field name="phone"/>
<field name="card"/>
<field name="fee"/>
<field name="payment"/>
<field name="total_payment"/>
<field name="company_id"/>
<field name="party_state"/>
<button name="send_party" string="发送" type="object" class="oe_highlight"/>
</tree>
</field>
</record>
+4 -1
View File
@@ -14,4 +14,7 @@ from . import initialize_payroll_wizard
from . import rank_log_wizard
from . import basic_pension_wizard
from . import salary_party_wizard
from . import salary_import_wizard
from . import salary_import_wizard
from . import party_send_wizard
from . import party_meal_wizard
from . import salary_meal_wizard
+74
View File
@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import ValidationError, UserError
from pypinyin import pinyin, Style
import xlrd
import base64
import datetime
from datetime import datetime
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import ValidationError, UserError
from pypinyin import pinyin, Style
import xlrd
import base64
import datetime
from datetime import datetime
import calendar
class PartyMealWizard(models.TransientModel):
_name = 'party.meal.wizard'
_description = '发送弹窗'
select_time = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'),
('5', '五月'), ('6', '六月'), ('7', '七月'), ('8', '八月'),
('9', '九月'), ('10', '十月'), ('11', '十一月'),
('12', '十二月')], string='月份',
default=lambda self: self._get_default_month())
select_year = fields.Selection(selection=[(str(i), str(i)) for i in range(2024, 2040)], string='年份',
default=lambda self: str(datetime.now().year))
employee_ids = fields.Many2many('hr.employee', string='员工')
def confirm(self):
year = self.select_year or datetime.now().year
month = self.select_time or datetime.now().month
last_day = calendar.monthrange(year, month)[1]
if self.select_time and self.select_year and not self.employee_ids:
meal_ids = self.env['yuthon.meal.expenses'].search([('select_time', '=', self.select_time),
('select_year', '=', self.select_year)])
for meal in meal_ids:
message = f"""致{meal.employee_id.name}:
{self.select_year}年{self.select_time}月 早餐{meal.number_breakfasts} 次、午餐{meal.number_lunches} 次,按餐标核算,
本月餐费合计{meal.total_payment}元。缴费截止{self.select_year}年{self.select_time}月{last_day}日],可汇入账户:[账户信息]。异议请联系行政部 [联系方式]。
办公室
{fields.Date.today()}"""
self.sudo().env["wecom.apps"].sync_send_message(
category='att',
user_id=meal.employee_id.wecom_userid,
message=message,
)
meal.write({'meal_state': 'done'})
if self.employee_ids:
for employee in self.employee_ids:
meal = self.env['yuthon.meal.expenses'].search([('employee_id', '=', employee.id),
('select_time', '=', self.select_time),
('select_year', '=', self.select_year)])
message = f"""致{meal.employee_id.name}:
{self.select_year}年{self.select_time}月 早餐{meal.number_breakfasts} 次、午餐{meal.number_lunches} 次,按餐标核算,
本月餐费合计{meal.total_payment}元。缴费截止{self.select_year}年{self.select_time}月{last_day}日],可汇入账户:[账户信息]。异议请联系行政部 [联系方式]。
办公室
{fields.Date.today()}"""
self.sudo().env["wecom.apps"].sync_send_message(
category='att',
user_id=employee.wecom_userid,
message=message,
)
meal.write({'meal_state': 'done'})
def _get_default_month(self):
current_month = datetime.now().month
return str(current_month)
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="party_meal_wizard_form_view" model="ir.ui.view">
<field name="name">party.meal.wizard.form</field>
<field name="model">party.meal.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<group>
<field name="select_year"/>
<field name="select_time"/>
<field name="employee_ids" widget="many2many_tags" options="{'no_create': True}"/>
</group>
</group>
<footer>
<button type="object" name="confirm" string="确认" class="oe_highlight"/>
<button string="返回" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>
+69
View File
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import ValidationError, UserError
from pypinyin import pinyin, Style
import xlrd
import base64
import datetime
from datetime import datetime
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import ValidationError, UserError
from pypinyin import pinyin, Style
import xlrd
import base64
import datetime
from datetime import datetime
class PartySendWizard(models.TransientModel):
_name = 'party.send.wizard'
_description = '发送弹窗'
select_time = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'),
('5', '五月'), ('6', '六月'), ('7', '七月'), ('8', '八月'),
('9', '九月'), ('10', '十月'), ('11', '十一月'),
('12', '十二月')], string='月份',
default=lambda self: self._get_default_month())
select_year = fields.Selection(selection=[(str(i), str(i)) for i in range(2024, 2040)], string='年份',
default=lambda self: str(datetime.now().year))
employee_ids = fields.Many2many('hr.employee', string='员工')
def confirm(self):
pay_year_month = self.select_year + '年' + self.select_time + '月'
if self.select_time and self.select_year and not self.employee_ids:
party_ids = self.env['yuthon.salary.party'].search([('select_time', '=', self.select_time),
('select_year', '=', self.select_year)])
for party in party_ids:
message = f"""【{pay_year_month}缴纳党费通知】:
请于{fields.Date.today()}(今天)15:00前将党费按时汇入账户:44001580909059000222 广州市天河投资集团有限公司,
并在群里告知汇款完毕。
您当月的缴费金额为{party.total_payment},其中党费{party.fee},补缴党费{party.payment}。"""
self.sudo().env["wecom.apps"].sync_send_message(
category='att',
user_id=party.employee_id.wecom_userid,
message=message,
)
party.write({'party_state': 'done'})
if self.employee_ids:
for employee in self.employee_ids:
party = self.env['yuthon.salary.party'].search([('employee_id', '=', employee.id),
('select_time', '=', self.select_time),
('select_year', '=', self.select_year)])
message = f"""【{pay_year_month}缴纳党费通知】:
请于{fields.Date.today()}(今天)15:00前将党费按时汇入账户:44001580909059000222 广州市天河投资集团有限公司,
并在群里告知汇款完毕。
您当月的缴费金额为{party.total_payment},其中党费{party.fee},补缴党费{party.payment}。"""
self.sudo().env["wecom.apps"].sync_send_message(
category='att',
user_id=employee.wecom_userid,
message=message,
)
party.write({'party_state': 'done'})
def _get_default_month(self):
current_month = datetime.now().month
return str(current_month)
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="party_send_wizard_form_view" model="ir.ui.view">
<field name="name">party.send.wizard.form</field>
<field name="model">party.send.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<group>
<field name="select_year"/>
<field name="select_time"/>
<field name="employee_ids" widget="many2many_tags" options="{'no_create': True}"/>
</group>
</group>
<footer>
<button type="object" name="confirm" string="确认" class="oe_highlight"/>
<button string="返回" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>
@@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import ValidationError, UserError
from pypinyin import pinyin, Style
import xlrd
import base64
import datetime
from datetime import datetime
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import ValidationError, UserError
from pypinyin import pinyin, Style
import xlrd
import base64
import datetime
from datetime import datetime
import calendar
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _, SUPERUSER_ID
from odoo.exceptions import ValidationError, UserError
from pypinyin import pinyin, Style
import xlrd
import base64
import datetime
from datetime import datetime, timedelta
class SalaryMealWizard(models.TransientModel):
_name = 'salary.meal.wizard'
_description = '餐费导入弹窗'
excel_file = fields.Binary(string="上传Excel表")
excel_name = fields.Char(string="文件名")
def confirm(self):
if not self.excel_file:
raise ValidationError('请上传文件。')
book = xlrd.open_workbook(file_contents=base64.decodebytes(self.excel_file))
sh = book.sheet_by_index(0)
for rx in range(1, sh.nrows):
row = sh.row(rx)
self.salary_meal_data(row)
def salary_meal_data(self, row):
select_year = row[0].value
select_time = row[1].value
employee_id = self.env['hr.employee'].search([('identification_id', '=', row[3].value)], limit=1)
card = row[3].value
number_breakfasts = row[4].value
number_lunches = row[5].value
total_payment = row[6].value
if employee_id:
party_id = self.env['yuthon.meal.expenses'].search([
('employee_id', '=', employee_id.id),
('select_year', '=', select_year),
('select_time', '=', select_time)
])
if not party_id:
self.env['yuthon.meal.expenses'].create({
'employee_id': employee_id.id,
'select_year': select_year,
'select_time': select_time,
'card': card,
'number_breakfasts': number_breakfasts,
'number_lunches': number_lunches,
'total_payment': total_payment,
})
else:
party_id.write({
'card': card,
'number_breakfasts': number_breakfasts,
'number_lunches': number_lunches,
'total_payment': total_payment,
}
)
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="salary_meal_wizard_downloads_action" model="ir.actions.act_url">
<field name="name">模板下载</field>
<field name="target">self</field>
<field name="url">/yuthon_salary/static/others/salary_meal.xlsx</field>
</record>
<record id="salary_meal_wizard_form" model="ir.ui.view">
<field name="name">弹窗</field>
<field name="model">salary.meal.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<header>
<button name="%(salary_meal_wizard_downloads_action)d" string="模板下载" type="action"
class="btn btn-primary"/>
</header>
<group>
<group>
<field name="excel_file" filename="excel_name"/>
<field name="excel_name" invisible="1"/>
</group>
<group>
</group>
</group>
</sheet>
<footer>
<button name="confirm" string="确认" type="object" class="oe_highlight"/>
<button string="返回" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>
+13 -7
View File
@@ -24,26 +24,32 @@ class SalaryPartyWizard(models.TransientModel):
self.salary_year_ttjt_data(row)
def salary_party_data(self, row):
employee_id = self.env['hr.employee'].search([('name', '=', row[0].value)], limit=1)
phone = row[1].value
fee = row[2].value
payment = row[3].value
total_payment = row[4].value
select_year = row[0].value
select_time = row[1].value
employee_id = self.env['hr.employee'].search([('identification_id', '=', row[3].value)], limit=1)
card = row[3].value
fee = row[4].value
payment = row[5].value
total_payment = row[6].value
if employee_id:
party_id = self.env['yuthon.salary.party'].search([
('employee_id', '=', employee_id.id),
('select_year', '=', select_year),
('select_time', '=', select_time)
])
if not party_id:
self.env['yuthon.salary.party'].create({
'employee_id': employee_id.id,
'phone': phone,
'card': card,
'select_year': select_year,
'select_time': select_time,
'fee': fee,
'payment': payment,
'total_payment': total_payment,
})
else:
party_id.write({
'phone': phone,
'card': card,
'fee': fee,
'payment': payment,
'total_payment': total_payment,
+5
View File
@@ -338,6 +338,11 @@
parent="human_resources_salary_root_board"
action="yuthon_salary.action_view_hr_payslip_month_form2"
sequence="3"/>
<menuitem id="yuthon_salary_meal_views_menu"
name="餐费"
parent="human_resources_salary_root_board"
action="yuthon_salary.view_yuthon_meal_expenses_action"
sequence="4"/>
<menuitem id="yuthon_salary_party_views_menu"
name="党建"
parent="human_resources_salary_root_board"