添加功能

This commit is contained in:
李鹏宇
2025-09-01 19:50:27 +08:00
parent 2a1ffbe07a
commit 1d20a7bf0b
9 changed files with 214 additions and 19 deletions
+1
View File
@@ -0,0 +1 @@
# -*- coding: utf-8 -*-
+37
View File
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
{
'name': "funenc_json_widget",
'summary': """
json widget for odoo
""",
'description': """
json widget for odoo
json
template widget
template
color widget
color
""",
'author': "Funenc",
'website': "http://odoo.funenc.com",
"images": [
"static/description/description.gif"
],
'category': 'App/json',
'version': '17.0.0.1',
'price': 5,
'license': 'OPL-1',
'depends': ['base', 'web'],
'data': [],
'assets': {
'web.assets_backend': [
'funenc_json_widget/static/src/json_widget.js',
]
}
}
@@ -0,0 +1,76 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { _t } from "@web/core/l10n/translation";
import { standardFieldProps } from "@web/views/fields/standard_field_props";
import { Component, xml, onWillUpdateProps } from "@odoo/owl";
export class JsonTemplateWidget extends Component {
setup() {
this.parseValue();
onWillUpdateProps(() => {
this.parseValue();
});
}
parseValue() {
try {
let name = this.props.name;
let data = this.props.record.data;
let value = data[name] || "{}";
this.jsonData = JSON.parse(value);
console.log('JsonTemplateWidget - 解析的JSON数据:', this.jsonData);
} catch (e) {
console.error('JsonTemplateWidget - JSON解析错误:', e.message);
this.jsonData = { error: e.message };
}
}
get templateName() {
if (this.jsonData && this.jsonData.template) {
return this.jsonData.template;
}
return null;
}
get hasValidTemplate() {
return this.templateName !== null;
}
static template = xml`
<div class="json-template-widget">
<t t-if="hasValidTemplate">
<t t-call="{{ templateName }}" t-call-context="jsonData" />
</t>
<t t-else="">
<div class="alert alert-warning">
<t t-if="jsonData.error">
错误: <t t-esc="jsonData.error" />
</t>
<t t-else="">
未找到有效模板
</t>
</div>
</t>
</div>
`;
static props = {
...standardFieldProps,
};
get isReadonly() {
return true;
}
}
export const JsonTemplateField = {
component: JsonTemplateWidget,
displayName: _t("Json Template"),
supportedTypes: ["char", "text"],
isEmpty: () => false
};
registry.category("fields").add("json_template", JsonTemplateField);
@@ -29,15 +29,13 @@ class OvertimeApprovals(models.Model):
related_issues_id = fields.Many2one('issue.library', string="关联议题")
documents_ids = fields.Many2many('ir.attachment', string="附件")
duration = fields.Float(string="时长", compute='_compute_duration', store=True, help="如果时长大于8则按8小时算")
real_duration = fields.Float(string="实际时长", compute='_compute_duration', store=True,
help="如果时长大于8则按实际时长算")
overtime_hours = fields.Float(string="本月加班时长")
start_time = fields.Datetime(string="开始时间")
start_week = fields.Char(string="星期", compute='_compute_weekday')
end_time = fields.Datetime(string="结束时间")
end_week = fields.Char(string="星期", compute='_compute_weekday')
type_overtime = fields.Selection([('work', '工作日加班'), ('weekend', '周末加班'), ('holiday', '节假日加班')],
string="加班类型", compute="_compute_overtime_type")
string="加班类型", compute="_compute_overtime_type", store=True)
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
active = fields.Boolean('Active', default=True, tracking=True)
@@ -72,15 +70,24 @@ class OvertimeApprovals(models.Model):
@api.depends('start_time', 'end_time')
def _compute_duration(self):
for rec in self:
if rec.start_time and rec.end_time:
rec.duration = round((rec.end_time - rec.start_time).total_seconds() / 3600, 1)
rec.real_duration = rec.duration
else:
rec.duration = 0.0
if not (rec.start_time and rec.end_time):
continue
total_seconds = (rec.end_time - rec.start_time).total_seconds()
original_hours = total_seconds / 3600
# 加班起步一小时
if original_hours < 1.0:
rec.duration = 0.0
rec.real_duration = 0.0
if rec.duration > 8:
rec.real_duration = 8
continue
excess = original_hours - 1.0
# 每半小时为一个单位,不足半小时不计
excess_units = int(excess // 0.5)
calculated_hours = 1.0 + (excess_units * 0.5)
if rec.type_overtime == 'work':
max_hours = 3.0
else:
max_hours = 8.0
rec.duration = min(calculated_hours, max_hours)
@api.depends('start_time', 'end_time')
def _compute_weekday(self):
@@ -177,10 +184,10 @@ class OvertimeApprovals(models.Model):
allocation = self.env['hr.leave.allocation'].create({
'employee_id': employee_id.id,
'name': '补休',
'number_of_days': self.real_duration / 8,
'number_of_days': self.duration / 8,
'holiday_status_id': holiday_status_id.id,
'allocation_type': 'regular',
"number_of_days_display": self.real_duration / 8,
"number_of_days_display": self.duration / 8,
})
if allocation:
allocation.sudo().action_validate()
@@ -200,11 +207,11 @@ class OvertimeApprovals(models.Model):
public_holidays = 0.0
if record.type_overtime == 'work':
workday = record.real_duration
workday = record.duration
elif record.type_overtime == 'weekend':
public_holidays = record.real_duration
public_holidays = record.duration
elif record.type_overtime == 'holiday':
legal_day = record.real_duration
legal_day = record.duration
overtime_data = {
'vacation_id': reports_id.id,
@@ -55,7 +55,6 @@
<field name="users_id"/>
<field name="work_end" invisible="1"/>
<field name="reason_application"/>
<field name="real_duration"/>
<field name="issues_result" invisible="is_issues == False"/>
<field name="documents_ids" widget="preview_many2many"/>
</group>
+6 -1
View File
@@ -6,7 +6,7 @@
'category': 'zhou',
'version': '0.1',
'license': 'LGPL-3',
'depends': ['base', 'stock', 'documents', 'maintenance'],
'depends': ['base', 'stock', 'documents', 'maintenance', 'funenc_json_widget'],
'data': [
'security/ir.model.access.csv',
'views/menu.xml',
@@ -14,5 +14,10 @@
],
'installable': True,
'application': True,
'assets': {
'web.assets_backend': [
'yuthon_stock/static/xml/misc.xml'
],
}
}
+29 -1
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models
import json
class StockPicking(models.Model):
@@ -7,6 +8,33 @@ class StockPicking(models.Model):
document_ids = fields.Many2many('ir.attachment', string="附件")
employee_id = fields.Many2one('hr.employee', string="领用人")
json_display = fields.Char(
string="物品详情",
compute='_compute_json_display',
store=True
)
@api.depends(
'move_ids_without_package.product_id',
'move_ids_without_package.product_uom_qty',
'move_ids_without_package.product_uom',
)
def _compute_json_display(self):
for record in self:
json_data = {
"template": "json_widget_stock.table_stock",
"title": f"{record.name}的明细数据",
"lines": [
{
'sequence': idx + 1,
'barcode': line.product_id.barcode or '',
'product_id': line.product_id.name or '',
'product_qty': line.product_uom_qty or '',
'price_unit': line.product_uom.name or '',
'standard_price' : line.product_id.standard_price or '',
}
for idx, line in enumerate(record.move_ids_without_package)
]
}
record.json_display = json.dumps(json_data, ensure_ascii=False)
+39
View File
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="json_widget_stock.table_stock" owl="1">
<div class="mb-3">
<t t-if="lines and lines.length">
<table class="table table-striped">
<thead class="table-dark">
<tr>
<th scope="col">序号</th>
<th scope="col">物业编号</th>
<th scope="col">产品</th>
<th scope="col">数量</th>
<th scope="col">单位</th>
<th scope="col">金额</th>
</tr>
</thead>
<tbody>
<tr t-foreach="lines" t-as="line" t-key="line_index">
<td><t t-esc="line.sequence || (line_index + 1)"/></td>
<td><strong><t t-esc="line.barcode || '-'"/></strong></td>
<td><strong><t t-esc="line.product_id || '-'"/></strong></td>
<td><strong><t t-esc="line.product_qty || '-'"/></strong></td>
<td><strong><t t-esc="line.price_unit || '-'"/></strong></td>
<td><strong><t t-esc="line.standard_price || '-'"/></strong></td>
</tr>
</tbody>
</table>
</t>
<t t-else="">
<div class="alert alert-info" role="alert">
<i class="fa fa-info-circle"></i> 暂无物品数据
</div>
</t>
</div>
</t>
</templates>
@@ -35,6 +35,9 @@
<xpath expr="//field[@name='user_id']" position="after">
<field name="employee_id"/>
</xpath>
<xpath expr="//field[@name='origin']" position="after">
<field name="json_display" widget="json_template"/>
</xpath>
<xpath expr="//field[@name='picking_type_id']" position="attributes">
<attribute name="column_invisible">1</attribute>
</xpath>