添加功能

This commit is contained in:
zhou
2025-08-18 18:25:29 +08:00
parent 6246ef9bc9
commit 7ee22ea008
16 changed files with 425 additions and 736 deletions
@@ -77,7 +77,7 @@ class PropertyBankStatements(models.Model):
'remark':None,
})
penalty_records = self.env['property.accounts.receivable'].search([
('payout_date', '=', start_date),
('due_date', '=', start_date),
('lessee_id', '=', tenant_id),
('contract_id', 'in', rec.contract_ids.ids),
('property_id', 'in', rec.property_ids.ids),
@@ -222,7 +222,7 @@ class PropertyBankStatements(models.Model):
# 跳过已处理的合同
if contract_id and contract_id in processed_contracts:
continue
# 获取合同的实际开始日期作为到期日
# 获取合同的实际结束日期作为到期日
due_date = False
if contract_id:
due_date = sub_record.contract_id.actual_start_time
@@ -31,18 +31,90 @@ class PropertyReconciliationWizard(models.Model):
# else:
# rec.amount_reconciled = 0.0
@api.onchange('actual_total', 'actual_date')
@api.onchange('actual_total')
def _onchange_reconciliation_line_ids(self):
if not self.reconciliation_line_ids:
return
# 提取已存在的违约金行用于去重判断
existing_penalty_lines = [
line for line in self.reconciliation_line_ids
if line.collection_type == 'penalty'
]
new_lines = []
# 违约金生成
for contract_id in self.bank_id.contract_ids:
if not contract_id.lease_ids:
continue
last_lease_line = contract_id.lease_ids[-1]
property_id = last_lease_line.address_id.id if last_lease_line.address_id else False
start_time = self.bank_id.start_time
first_day_of_last_month = (start_time.replace(day=1) - relativedelta(months=1))
last_day_of_last_month = start_time.replace(day=1) - relativedelta(days=1)
contract_receivables = self.env['property.accounts.receivable'].search([
('contract_id', '=', contract_id.id),
('property_id', '=', property_id),
('due_date', '>=', first_day_of_last_month.strftime('%Y-%m-%d')),
('due_date', '<=', last_day_of_last_month.strftime('%Y-%m-%d')),
('management_type_id.name', '=', '租金')
], limit=1)
# 计算应收日期的下月1号
next_month_first = (fields.Date.from_string(contract_receivables.due_date) +
relativedelta(months=1)).replace(day=1)
# 检查是否产生违约
if fields.Date.from_string(self.actual_date) > next_month_first:
# 计算违约天数和违约金
late_days = (fields.Date.from_string(self.actual_date) - next_month_first).days + 1
penalty_amount = late_days * round(
contract_id.rent * float(contract_id.percentage_liquidated_damages.name), 2
)
start_date_str = fields.Date.to_string(next_month_first)
end_date_str = self.actual_date
contract_penalties = []
# 1. 处理新产生的违约金
if penalty_amount > 0:
contract_penalties.append({
'property_id': property_id,
'contract_id': contract_id.id,
'rent_month': 0,
'due_date': self.actual_date,
'rent': penalty_amount,
'amount': 0,
'collection_type': 'penalty',
'remake': f'违约金({start_date_str}至{end_date_str},共{late_days}天)',
})
# 2. 处理上月未对账的违约金延续
receivable_penalties = self.env['property.accounts.receivable'].search([
('property_id', '=', property_id),
('contract_id', '=', contract_id.id),
('is_reconciliation', '=', False),
('management_type_id.name', '=', '违约金')
])
for penalty in receivable_penalties:
exists = any(p['rent'] == penalty.submitted and
p['due_date'] == penalty.due_date and
p['contract_id'] == penalty.contract_id.id
for p in contract_penalties)
if not exists:
contract_penalties.append({
'property_id': penalty.property_id.id,
'contract_id': penalty.contract_id.id,
'rent_month': 0,
'due_date': penalty.due_date,
'rent': penalty.submitted,
'amount': 0,
'collection_type': 'penalty',
'remake': penalty.remark,
})
# 3. 添加到总列表
for vals in contract_penalties:
new_lines.append((0, 0, vals))
if new_lines:
keep_lines = [
(4, line.id) for line in self.reconciliation_line_ids
if line.collection_type != 'penalty'
]
self.reconciliation_line_ids = keep_lines + new_lines
if self.reconciliation_line_ids:
self.reconciliation_line_ids.sorted(key=lambda r: r.sequence)
remaining_amount = self.actual_total
# 检查是否有单行的rent等于实际金额
@@ -88,73 +160,6 @@ class PropertyReconciliationWizard(models.Model):
line.amount = assign_amount
remaining_amount -= assign_amount
# 检查是否违约并创建违约金行(带去重)
if (line.due_date and self.actual_date and line.collection_type != 'deposit'):
# 计算应收日期的下月1号
next_month_first = (fields.Date.from_string(line.due_date) + relativedelta(months=1)).replace(day=1)
# 如果实收日期晚于下月1号,产生违约
if fields.Date.from_string(self.actual_date) > next_month_first:
# 计算违约天数
late_days = (fields.Date.from_string(self.actual_date) - next_month_first).days + 1
# 计算违约金
penalty_amount = late_days * round(
line.rent * float(line.contract_id.percentage_liquidated_damages.name), 2
)
start_date_str = fields.Date.to_string(next_month_first)
end_date_str = self.actual_date
if penalty_amount > 0:
# 检查是否已存在相同条件的违约金行
is_duplicate = any(
pl.contract_id.id == line.contract_id.id
and pl.property_id.id == line.property_id.id
and pl.due_date == self.actual_date
and pl.collection_type == 'penalty'
for pl in existing_penalty_lines
)
if not is_duplicate:
# 创建新的违约金记录
penalty_line_vals = {
'property_id': line.property_id.id,
'contract_id': line.contract_id.id,
'rent_month': 0,
'due_date': self.actual_date,
'rent': penalty_amount,
'amount': 0,
'collection_type': 'penalty',
'remake': f'违约金({start_date_str}至{end_date_str},共{late_days}天)',
'sequence': int(line.sequence) + 1,
}
new_lines.append((0, 0, penalty_line_vals))
# 上月违约金未对账延续
receivable_penalties = self.env['property.accounts.receivable'].search([
('property_id', 'in', self.bank.property_ids.ids),
('contract_id', 'in', self.bank.contract_ids.ids),
('is_reconciliation', '=', False),
('management_type_id.name', '=', '违约金')
])
for penalty in receivable_penalties:
receivable_line_vals = {
'property_id': penalty.property_id.id,
'contract_id': penalty.contract_id.id,
'rent_month': 0,
'due_date': penalty.due_date,
'rent': penalty.submitted,
'amount': 0,
'collection_type': 'penalty',
'remake': penalty.remark,
'sequence': int(line.sequence) + 2,
}
new_lines.append((0, 0, receivable_line_vals))
if new_lines:
keep_lines = [
(4, line.id) for line in self.reconciliation_line_ids
if line.collection_type != 'penalty'
]
self.reconciliation_line_ids = keep_lines + new_lines
if self.reconciliation_line_ids:
self.reconciliation_line_ids.sorted(key=lambda r: r.sequence)
def confirm(self):
for rec in self:
bank_lines = self.env['property.bank.line'].search([
+2 -5
View File
@@ -6,14 +6,11 @@
'category': 'zhou',
'version': '0.1',
'license': 'LGPL-3',
'depends': ['base', 'soong_workflow', 'hr', 'product', 'documents', 'purchase', 'contacts'],
'depends': ['base', 'soong_workflow', 'hr', 'product', 'documents', 'purchase'],
'data': [
'security/ir.model.access.csv',
'data/purchase_data.xml',
'views/purchase_fixed_assets_views.xml',
'views/purchase_low_orders_views.xml',
'views/inherit_res_partner_views.xml',
'views/purchase_service_orders_views.xml',
'views/purchase_workflow_views.xml',
'views/menu.xml',
],
'installable': True,
+1 -4
View File
@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from . import purchase_fixed_assets
from . import purchase_low_orders
from . import purchase_service_orders
from . import inherit_purchase_order
# from . import inherit_res_partner
from . import purchase_workflow
@@ -1,8 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models
class InheritResPartner(models.Model):
_inherit = 'res.partner'
partner_category = fields.Selection([('party', '乙方'), ('suppliers', '供应商')], string='类型')
@@ -1,87 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models
class PurchaseFixedAssets(models.Model):
_name = 'purchase.fixed.assets'
_description = '固定资产采购单'
_inherit = ['soong.workflow.mixin']
code = fields.Char(string="流水号",
default=lambda self: self.env['ir.sequence'].next_by_code('purchase_order_sequence_code'))
name = fields.Char(string="名称")
company_id = fields.Many2one('res.company', string="公司", default=lambda self: self.env.company)
user_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user)
department_id = fields.Many2one(related='user_id.employee_id.department_id', string="部门")
partner_id = fields.Many2one('res.partner', string="供应商")
date_order = fields.Datetime(string="订单日期")
date_planned = fields.Datetime(string="预计到货日期")
start_date = fields.Date(string="申请日期", default=fields.Date.today)
reason_text = fields.Text(string='申请事由')
document_ids = fields.Many2many('ir.attachment', string="附件")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
active = fields.Boolean('Active', default=True, tracking=True)
pay_way = fields.Selection([('onetime', '一次性'), ('installment', '分期')], string='付款方式', default='onetime')
purchase_order_models_ids = fields.One2many('purchase.order.pay.line', 'purchase_id', string="付款详情")
fixed_ids = fields.One2many('purchase.fixed.line', 'purchase_id', string="采购明细")
work_end = fields.Boolean(string="结束")
def _get_default_name_title(self):
return self._description if self._description else self._name
name_title = fields.Char(default=_get_default_name_title, string="标题")
def end_approval(self):
for rec in self:
purchase_order = self.env['purchase.order'].create({
'partner_id': rec.partner_id.id,
'date_order': rec.date_order if rec.date_order else None,
'date_planned': rec.date_planned if rec.date_planned else None,
'company_id': rec.company_id.id,
'user_id': rec.user_id.id,
})
order_lines = []
for fixed_line in rec.fixed_ids:
if not fixed_line.product_id:
continue
order_lines.append((0, 0, {
'order_id': purchase_order.id,
'product_id': fixed_line.product_id.id,
'product_qty': fixed_line.number,
'name': fixed_line.name,
'price_unit':fixed_line.price_unit,
'product_packaging_id': fixed_line.product_packaging_id.id,
'taxes_id': fixed_line.taxes_id,
}))
if order_lines:
purchase_order.order_line = order_lines
class PurchaseOrderPayLine(models.Model):
_name = "purchase.order.pay.line"
_description = "付款详情"
purchase_id = fields.Many2one('purchase.fixed.assets', string="关联采购单")
low_id = fields.Many2one('purchase.low.orders', string="关联低值易耗采购单")
service_id = fields.Many2one('purchase.service.orders', string="关联服务采购单")
payment_stage = fields.Char(string="付款阶段")
amount = fields.Char(string="比例/金额")
payment_date = fields.Date(string="付款日期")
remake = fields.Char(string="条件")
class PurchaseFixedLine(models.Model):
_name = 'purchase.fixed.line'
_description = '固定资产采购单明细'
purchase_id = fields.Many2one('purchase.fixed.assets', string="关联采购单")
product_id = fields.Many2one('product.product', string="物品名称")
brand = fields.Char(string="品牌")
specs = fields.Char(string="规格")
number = fields.Integer(string="数量")
name = fields.Text(string="描述")
product_packaging_id = fields.Many2one('product.packaging', string="包装")
taxes_id = fields.Many2one('account.tax', string='税项')
unit_id = fields.Many2one(related='product_id.uom_id', string="单位")
price = fields.Float(related='product_id.standard_price', string="单价", stroe=True)
@@ -1,81 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models
from datetime import datetime
class PurchaseLowOrders(models.Model):
_name = 'purchase.low.orders'
_description = '低值易耗采购单'
_inherit = ['soong.workflow.mixin']
name = fields.Char(string="标题")
code = fields.Char(string="合同编号", default=lambda self: self.env['ir.sequence'].next_by_code('purchase_low_orders_code'))
user_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
date_application = fields.Date(string="申请日期", default=fields.Date.today())
company_id = fields.Many2one('res.company', string='公司', index=True, default=lambda self: self.env.company)
reason_application = fields.Text(string="申请事由")
department_id = fields.Many2one(related='user_id.employee_id.department_id', string="申请部门")
party_id = fields.Many2one('res.partner', string="乙方")
document_ids = fields.Many2many('ir.attachment', string="附件")
pay_way = fields.Selection([('staging', '分期'), ('full', '一次性')], string='付款方式', default='full')
total = fields.Float(string="合计")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
work_end = fields.Boolean(string="结束")
active = fields.Boolean('Active', default=True, tracking=True)
low_line_ids = fields.One2many('purchase.low.line', 'purchase_id', string="采购明细")
purchase_ids = fields.One2many('purchase.order.pay.line', 'low_id', string="采购单")
def _get_default_name_title(self):
return self._description if self._description else self._name
name_title = fields.Char(default=_get_default_name_title)
def end_approval(self):
for rec in self:
date_with_time = datetime.combine(
fields.Date.from_string(rec.date_application),
datetime.min.time().replace(hour=0)
)
purchase_order = self.env['purchase.order'].create({
'partner_id': rec.party_id.id,
'date_order': date_with_time,
'company_id': rec.company_id.id,
'user_id': rec.user_id.id,
})
order_lines = []
for low_line in rec.low_line_ids:
if not low_line.product_id:
continue
order_lines.append((0, 0, {
'order_id': purchase_order.id,
'product_id': low_line.product_id.id,
'product_qty': low_line.number,
'product_uom': low_line.unit_id.id,
'price_unit': low_line.price,
'name': low_line.name,
'product_packaging_id': low_line.product_packaging_id.id,
'taxes_id': low_line.taxes_id,
}))
if order_lines:
purchase_order.order_line = order_lines
class PurchaseLowLine(models.Model):
_name = 'purchase.low.line'
_description = '低值易耗采购单明细'
purchase_id = fields.Many2one('purchase.low.orders', string="关联采购单")
product_id = fields.Many2one('product.product', string="物品名称")
brand = fields.Char(string="品牌")
specs = fields.Char(string="规格")
name = fields.Text(string="描述")
product_packaging_id = fields.Many2one('product.packaging', string="包装")
taxes_id = fields.Many2one('account.tax', string='税项')
number = fields.Integer(string="数量")
unit_id = fields.Many2one(related='product_id.uom_id', string="单位")
price = fields.Float(related='product_id.standard_price', string="单价")
@@ -1,87 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models
from datetime import datetime
class PurchaseServiceOrders(models.Model):
_name = 'purchase.service.orders'
_description = '服务采购单'
_inherit = ['soong.workflow.mixin']
name = fields.Char(string="标题")
code = fields.Char(string="合同编号", default=lambda self: self.env['ir.sequence'].next_by_code('purchase_service_orders_code'))
user_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
date_application = fields.Date(string="申请日期", default=fields.Date.today())
company_id = fields.Many2one('res.company', string='公司', index=True, default=lambda self: self.env.company)
reason_application = fields.Text(string="申请事由")
service_content = fields.Text(string="服务内容")
service_start_date = fields.Date(string="服务开始日期")
service_end_date = fields.Date(string="服务结束日期")
service_year = fields.Char(string="服务年限")
department_id = fields.Many2one(related='user_id.employee_id.department_id', string="申请部门")
party_id = fields.Many2one('res.partner', string="乙方")
license_id = fields.Many2one('ir.attachment', string='营业执照')
aptitude_id = fields.Many2one('ir.attachment', string='资质')
contract_id = fields.Many2one('ir.attachment', string='合同')
other_id = fields.Many2one('ir.attachment', string='其他')
pay_way = fields.Selection([('staging', '分期'), ('full', '一次性')], string='付款方式', default='full')
total = fields.Float(string="合计")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
work_end = fields.Boolean(string="结束")
active = fields.Boolean('Active', default=True, tracking=True)
service_line_ids = fields.One2many('purchase.service.line', 'service_id', string="采购明细")
purchase_ids = fields.One2many('purchase.order.pay.line', 'service_id', string="采购单")
def _get_default_name_title(self):
return self._description if self._description else self._name
name_title = fields.Char(default=_get_default_name_title)
def end_approval(self):
for rec in self:
date_with_time = datetime.combine(
fields.Date.from_string(rec.date_application),
datetime.min.time().replace(hour=0)
)
purchase_order = self.env['purchase.order'].create({
'partner_id': rec.party_id.id,
'date_order': date_with_time,
'company_id': rec.company_id.id,
'user_id': rec.user_id.id,
})
order_lines = []
for service_line in rec.service_line_ids:
if not service_line.product_id:
continue
order_lines.append((0, 0, {
'order_id': purchase_order.id,
'product_id': service_line.product_id.id,
'name': service_line.name,
'product_packaging_id': service_line.product_packaging_id.id,
'taxes_id': service_line.taxes_id,
'price_unit': service_line.price,
}))
if order_lines:
purchase_order.order_line = order_lines
class PurchaseServiceLine(models.Model):
_name = 'purchase.service.line'
_description = '服务采购单明细'
service_id = fields.Many2one('purchase.service.orders', string="关联采购单")
product_id = fields.Many2one('product.product', string="服务项目")
frequency = fields.Char(string='频次')
fee = fields.Float(string="费用")
name = fields.Text(string="描述")
product_packaging_id = fields.Many2one('product.packaging', string="包装")
taxes_id = fields.Many2one('account.tax', string='税项')
unit_id = fields.Many2one(related='product_id.uom_id', string="单位")
party_id = fields.Many2one('res.partner', string="供应商")
price = fields.Float(related='product_id.standard_price', string="单价")
+189
View File
@@ -0,0 +1,189 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models
class PurchaseWorkflow(models.Model):
_name = 'purchase.workflow'
_description = '采购工作流'
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('purchase_order_sequence_code'))
name = fields.Char(string="标题")
name_title = fields.Char(string="默认标题", default=lambda self: self._description, readonly=True)
user_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user, required=True)
department_id = fields.Many2one(related='user_id.employee_id.department_id', string="申请部门", store=True,
readonly=True)
company_id = fields.Many2one('res.company', string="公司", default=lambda self: self.env.company, required=True)
start_date = fields.Date(string="申请日期", default=fields.Date.today(), required=True)
date_order = fields.Datetime(string="订单日期")
date_planned = fields.Datetime(string="预计到货日期")
date_application = fields.Date(string="申请日期", default=fields.Date.today(), readonly=True)
partner_id = fields.Many2one('res.partner', string="供应商/乙方", required=True)
reason_text = fields.Text(string="申请事由")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string="紧急度",
default='normal', required=True)
pay_way = fields.Selection([('onetime', '一次性'), ('installment', '分期')], string="付款方式", default='onetime',
required=True)
total = fields.Float(string="合计金额", readonly=True)
document_ids = fields.Many2many('ir.attachment', string="附件")
active = fields.Boolean('启用', default=True, tracking=True)
work_end = fields.Boolean(string="审批结束", default=False, tracking=True)
purchase_type = fields.Selection([('fixed', '固定资产'), ('low', '低值易耗'), ('service', '服务')],
string="采购类型", required=True, default='fixed')
service_content = fields.Text(string="服务内容")
service_start_date = fields.Date(string="服务开始日期")
service_end_date = fields.Date(string="服务结束日期")
service_year = fields.Char(string="服务年限")
license_id = fields.Many2one('ir.attachment', string='营业执照')
aptitude_id = fields.Many2one('ir.attachment', string='资质')
contract_id = fields.Many2one('ir.attachment', string='合同')
fixed_line_ids = fields.One2many('purchase.fixed.line', 'purchase_id', string="固定资产明细")
low_line_ids = fields.One2many('purchase.low.line', 'purchase_id', string="低值易耗明细")
service_line_ids = fields.One2many('purchase.service.line', 'service_id', string="服务明细")
pay_line_ids = fields.One2many('purchase.order.pay.line', 'purchase_id', string="付款详情")
@api.onchange('purchase_type')
def _onchange_purchase_type(self):
if self.purchase_type == 'fixed':
self.low_line_ids = [(5, 0, 0)]
self.service_line_ids = [(5, 0, 0)]
elif self.purchase_type == 'low':
self.fixed_line_ids = [(5, 0, 0)]
self.service_line_ids = [(5, 0, 0)]
elif self.purchase_type == 'service':
self.fixed_line_ids = [(5, 0, 0)]
self.low_line_ids = [(5, 0, 0)]
def end_approval(self):
for rec in self:
purchase_order = self.env['purchase.order'].create({
'partner_id': rec.partner_id.id,
'date_order': rec.date_order,
'date_planned': rec.date_planned,
'company_id': rec.company_id.id,
'user_id': rec.user_id.id,
'origin': f"{rec.code}({dict(rec._fields['purchase_type'].selection).get(rec.purchase_type)})"
})
order_lines = []
if rec.purchase_type == 'fixed':
for line in rec.fixed_line_ids:
if not line.product_id:
continue
order_lines.append((0, 0, {
'product_id': line.product_id.id,
'product_qty': line.number,
'name': line.name,
'price_unit': line.price_unit,
'product_packaging_id': line.product_packaging_id.id,
'taxes_id': [(6, 0, line.taxes_id.ids)] if line.taxes_id else False
}))
elif rec.purchase_type == 'low':
for line in rec.low_line_ids:
if not line.product_id:
continue
order_lines.append((0, 0, {
'product_id': line.product_id.id,
'product_qty': line.number,
'product_uom': line.unit_id.id,
'name': line.name,
'price_unit': line.price,
'product_packaging_id': line.product_packaging_id.id,
'taxes_id': [(6, 0, line.taxes_id.ids)] if line.taxes_id else False
}))
elif rec.purchase_type == 'service':
for line in rec.service_line_ids:
if not line.product_id:
continue
order_lines.append((0, 0, {
'product_id': line.product_id.id,
'name': line.name,
'price_unit': line.price,
'product_packaging_id': line.product_packaging_id.id,
'taxes_id': [(6, 0, line.taxes_id.ids)] if line.taxes_id else False
}))
if order_lines:
purchase_order.order_line = order_lines
class PurchaseOrderPayLine(models.Model):
_name = "purchase.order.pay.line"
_description = "付款详情"
purchase_id = fields.Many2one('purchase.workflow', string="关联采购工作流")
payment_stage = fields.Char(string="付款阶段")
amount = fields.Char(string="比例/金额")
payment_date = fields.Date(string="付款日期")
remake = fields.Char(string="条件")
class PurchaseFixedLine(models.Model):
_name = 'purchase.fixed.line'
_description = '固定资产采购明细'
purchase_id = fields.Many2one('purchase.workflow', string="关联采购工作流")
product_id = fields.Many2one('product.product', string="物品名称")
brand = fields.Char(string="品牌")
specs = fields.Char(string="规格")
number = fields.Integer(string="数量",)
name = fields.Text(string="描述")
product_packaging_id = fields.Many2one('product.packaging', string="包装")
taxes_id = fields.Many2one('account.tax', string='税项')
unit_id = fields.Many2one(related='product_id.uom_id', string="单位")
price_unit = fields.Float(related='product_id.standard_price', string="单价", store=True)
total = fields.Float(string="合计", compute='_compute_total', store=True, )
@api.depends('price_unit', 'number')
def _compute_total(self):
for line in self:
line.total = round(line.price_unit * line.number, 2)
class PurchaseLowLine(models.Model):
_name = 'purchase.low.line'
_description = '低值易耗采购明细'
purchase_id = fields.Many2one('purchase.workflow', string="关联采购工作流")
product_id = fields.Many2one('product.product', string="物品名称")
brand = fields.Char(string="品牌")
specs = fields.Char(string="规格")
name = fields.Text(string="描述")
product_packaging_id = fields.Many2one('product.packaging', string="包装")
taxes_id = fields.Many2one('account.tax', string='税项')
number = fields.Integer(string="数量")
unit_id = fields.Many2one(related='product_id.uom_id', string="单位")
price = fields.Float(related='product_id.standard_price', string="单价", store=True)
total = fields.Float(string="合计", compute='_compute_total', store=True)
@api.depends('price', 'number')
def _compute_total(self):
for line in self:
line.total = round(line.price * line.number, 2)
class PurchaseServiceLine(models.Model):
_name = 'purchase.service.line'
_description = '服务采购明细'
service_id = fields.Many2one('purchase.workflow', string="关联采购工作流")
product_id = fields.Many2one('product.product', string="服务项目")
frequency = fields.Integer(string='频次')
fee = fields.Float(string="费用")
name = fields.Text(string="描述")
product_packaging_id = fields.Many2one('product.packaging', string="包装")
taxes_id = fields.Many2one('account.tax', string='税项')
unit_id = fields.Many2one(related='product_id.uom_id', string="单位")
price = fields.Float(related='product_id.standard_price', string="单价", store=True)
total = fields.Float(string="合计", compute='_compute_total', store=True)
@api.depends('price', 'frequency')
def _compute_total(self):
for line in self:
line.total = round(line.price * line.frequency, 2)
class PurchaseFixedAssets(models.Model):
_name = 'purchase.fixed.assets'
class PurchaseServiceOrders(models.Model):
_name = 'purchase.service.orders'
class PurchaseLowOrders(models.Model):
_name = 'purchase.low.orders'
+2 -4
View File
@@ -1,8 +1,6 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_purchase_fixed_assets,purchase_fixed_assets,model_purchase_fixed_assets,,1,1,1,1
access_purchase_fixed_line, purchase_fixed_line,model_purchase_fixed_line,,1,1,1,1
access_purchase_order_pay_line,purchase_order_pay_line,model_purchase_order_pay_line,,1,1,1,1
access_purchase_low_orders, purchase_low_orders,model_purchase_low_orders,,1,1,1,1
access_purchase_service_orders, purchase_service_orders,model_purchase_service_orders,,1,1,1,1
access_purchase_low_line, purchase_low_line,model_purchase_low_line,,1,1,1,1
access_purchase_service_line, purchase_service_line,model_purchase_service_line,,1,1,1,1
access_purchase_service_line, purchase_service_line,model_purchase_service_line,,1,1,1,1
access_purchase_workflow, purchase_workflow,model_purchase_workflow,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
access_purchase_fixed_assets purchase_fixed_assets model_purchase_fixed_assets 1 1 1 1
2 access_purchase_fixed_line purchase_fixed_line model_purchase_fixed_line 1 1 1 1
3 access_purchase_order_pay_line purchase_order_pay_line model_purchase_order_pay_line 1 1 1 1
access_purchase_low_orders purchase_low_orders model_purchase_low_orders 1 1 1 1
access_purchase_service_orders purchase_service_orders model_purchase_service_orders 1 1 1 1
4 access_purchase_low_line purchase_low_line model_purchase_low_line 1 1 1 1
5 access_purchase_service_line purchase_service_line model_purchase_service_line 1 1 1 1
6 access_purchase_workflow purchase_workflow model_purchase_workflow 1 1 1 1
@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_res_partner_form_inherit" model="ir.ui.view">
<field name="name">res.partner.form.inherit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='vat']" position="after">
<field name="partner_category" widget="radio"/>
</xpath>
</field>
</record>
<record id="view_res_partner_search_inherit" model="ir.ui.view">
<field name="name">res.partner.search.inherit</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_res_partner_filter"/>
<field name="arch" type="xml">
<xpath expr="//filter[@name='type_person']" position="after">
<filter string="供应商" name="partner_category" domain="['|', ('category', '=', 'party'), ('category', '=', 'suppliers')]"/>
</xpath>
</field>
</record>
</odoo>
@@ -1,114 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_purchase_fixed_assets_tree" model="ir.ui.view">
<field name="name">purchase.fixed.assets.tree</field>
<field name="model">purchase.fixed.assets</field>
<field name="arch" type="xml">
<tree string="固定资产采购单">
<field name="name"/>
<field name="user_id"/>
<field name="partner_id"/>
<field name="pay_way"/>
<field name="date_order"/>
</tree>
</field>
</record>
<record id="view_purchase_fixed_assets_form" model="ir.ui.view">
<field name="name">purchase.fixed.assets.form</field>
<field name="model">purchase.fixed.assets</field>
<field name="arch" type="xml">
<form string="固定资产采购单">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
invisible="urgency_level != 'normal'"/>
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
invisible="urgency_level != 'urgent'"/>
<widget name="web_ribbon" title="特级" bg_color="text-bg-danger"
invisible="urgency_level != 'emergency'"/>
<!-- <header>-->
<!-- <button name="end_approval" type="object" string="结束" dclass="oe_highlight"/>-->
<!-- </header>-->
<group col="3">
<group>
<field name="code" string="流水号" readonly="1"/>
</group>
<group>
<field name="urgency_level" readonly="1"/>
</group>
<group>
<field name="start_date"/>
</group>
</group>
<div class="col-12 text-center">
<h1>
<field name="name_title" readonly="1"/>
</h1>
</div>
<div class="oe_title">
<label for="name"/>
<h1>
<field name="name" string="标题"/>
</h1>
</div>
<group string="审批信息" col="2">
<group>
<field name="work_end" invisible="1"/>
<field name="state" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="user_id"/>
<field name="partner_id" domain="[('company_id', '=', company_id), ('user_ids', '=', False)]" required="1"/>
<field name="pay_way"/>
</group>
<group>
<field name="date_order"/>
<field name="date_planned"/>
<field name="department_id" invisible="1"/>
</group>
</group>
<group>
<field name="reason_text"/>
</group>
<notebook>
<page string="采购明细">
<field name="fixed_ids">
<tree editable="bottom">
<field name="purchase_id" column_invisible="1"/>
<field name="product_id"/>
<field name="name" required="1"/>
<field name="brand"/>
<field name="specs"/>
<field name="product_packaging_id"/>
<field name="number"/>
<field name="unit_id"/>
<field name="price"/>
<field name="taxes_id"/>
</tree>
</field>
</page>
</notebook>
<notebook>
<page string="付款详情" invisible="pay_way == 'onetime'">
<field name="purchase_order_models_ids">
<tree editable="bottom">
<field name="purchase_id" column_invisible="1"/>
<field name="payment_stage"/>
<field name="amount"/>
<field name="payment_date"/>
<field name="remake"/>
</tree>
</field>
</page>
</notebook>
<group>
<field name="document_ids" widget="preview_many2many"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_purchase_fixed_assets_action" model="ir.actions.act_window">
<field name="name">固定资产采购单</field>
<field name="res_model">purchase.fixed.assets</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
@@ -1,103 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_purchase_low_orders_tree" model="ir.ui.view">
<field name="name">purchase.low.orders.tree</field>
<field name="model">purchase.low.orders</field>
<field name="arch" type="xml">
<tree string="低值易耗采购单">
<field name="name"/>
<field name="user_id"/>
<field name="party_id"/>
<field name="reason_application"/>
<field name="pay_way"/>
<field name="total"/>
</tree>
</field>
</record>
<record id="view_purchase_low_orders_form" model="ir.ui.view">
<field name="name">purchase.low.orders.form</field>
<field name="model">purchase.low.orders</field>
<field name="arch" type="xml">
<form string="低值易耗采购单">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
invisible="urgency_level != 'normal'"/>
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
invisible="urgency_level != 'urgent'"/>
<widget name="web_ribbon" title="特级" bg_color="text-bg-danger"
invisible="urgency_level != 'emergency'"/>
<!-- <header>-->
<!-- <button name="end_approval" type="object" string="结束" dclass="oe_highlight"/>-->
<!-- </header>-->
<group col="4">
<group>
<field name="code" string="流水号" readonly="1"/>
</group>
<group>
<field name="urgency_level" readonly="1"/>
</group>
<group/>
</group>
<div class="col-12 text-center">
<h1>
<field name="name_title" readonly="1"/>
</h1>
</div>
<group string="申请事项" col="2">
<group>
<field name="name"/>
<field name="user_id"/>
<field name="company_id" invisible="1"/>
<field name="department_id" invisible="1"/>
<field name="work_end" invisible="1"/>
<field name="party_id" required="1" domain="[('company_id', '=', company_id), ('user_ids', '=', False)]"/>
</group>
<group>
<field name="date_application"/>
<field name="pay_way"/>
</group>
</group>
<group>
<field name="reason_application"/>
<field name="document_ids" widget="preview_many2many"/>
<field name="total"/>
</group>
<notebook>
<page string="采购明细">
<field name="low_line_ids" string=" ">
<tree editable="bottom">
<field name="purchase_id" column_invisible="1"/>
<field name="product_id"/>
<field name="name" required="1"/>
<field name="brand"/>
<field name="specs"/>
<field name="number"/>
<field name="product_packaging_id"/>
<field name="unit_id"/>
<field name="price"/>
<field name="taxes_id"/>
</tree>
</field>
</page>
<page string="付款明细">
<field name="purchase_ids">
<tree editable="bottom">
<field name="low_id" column_invisible="1"/>
<field name="payment_stage"/>
<field name="amount"/>
<field name="payment_date"/>
<field name="remake"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_purchase_low_orders_action" model="ir.actions.act_window">
<field name="name">低值易耗品采购单</field>
<field name="res_model">purchase.low.orders</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
@@ -1,128 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_purchase_service_orders_tree" model="ir.ui.view">
<field name="name">purchase.service.orders.tree</field>
<field name="model">purchase.service.orders</field>
<field name="arch" type="xml">
<tree string="服务采购单">
<field name="name"/>
<field name="user_id"/>
<field name="service_year"/>
<field name="service_content"/>
<field name="pay_way"/>
<field name="total"/>
</tree>
</field>
</record>
<record id="view_purchase_service_orders_form" model="ir.ui.view">
<field name="name">purchase.service.orders.form</field>
<field name="model">purchase.service.orders</field>
<field name="arch" type="xml">
<form string="服务采购单">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
invisible="urgency_level != 'normal'"/>
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
invisible="urgency_level != 'urgent'"/>
<widget name="web_ribbon" title="特级" bg_color="text-bg-danger"
invisible="urgency_level != 'emergency'"/>
<!-- <header>-->
<!-- <button name="end_approval" type="object" string="结束" dclass="oe_highlight"/>-->
<!-- </header>-->
<group col="4">
<group>
<field name="code" string="流水号" readonly="1"/>
</group>
<group>
<field name="urgency_level" readonly="1"/>
</group>
<group/>
</group>
<div class="col-12 text-center">
<h1>
<field name="name_title" readonly="1"/>
</h1>
</div>
<group string="申请事项">
<field name="name"/>
<field name="user_id"/>
<field name="party_id" required="1" domain="[('company_id', '=', company_id), ('user_ids', '=', False)]"/>
<field name="company_id" invisible="1"/>
<field name="department_id" invisible="1"/>
<field name="work_end" invisible="1"/>
<field name="service_content"/>
<field name="date_application"/>
<label for="service_start_date"/>
<div class="d-inline-flex w-100">
<field name="service_start_date" string="服务周期:" class="me-2"
style="max-width: 8rem !important;"/>到
<field name="service_end_date" string=" " class="ms-2"
style="max-width: 8rem !important;"/>
<field name="service_year" string=" " class="ms-2"
style="max-width: 2rem !important;"/>年
</div>
<field name="reason_application"/>
</group>
<group string="服务项目">
</group>
<group col="2">
<group>
<field name="pay_way"/>
</group>
<group>
<field name="total"/>
</group>
</group>
<notebook>
<page string="服务项目">
<field name="service_line_ids">
<tree editable="bottom">
<field name="service_id" column_invisible="1"/>
<field name="product_id"/>
<field name="name" required="1"/>
<field name="frequency"/>
<field name="fee"/>
<field name="product_packaging_id"/>
<field name="unit_id"/>
<field name="party_id"/>
<field name="price"/>
<field name="taxes_id"/>
</tree>
</field>
</page>
<page string="付款明细">
<field name="purchase_ids">
<tree editable="bottom">
<field name="service_id" column_invisible="1"/>
<field name="payment_stage"/>
<field name="amount"/>
<field name="payment_date"/>
<field name="remake"/>
</tree>
</field>
</page>
</notebook>
<group col="2">
<group>
<field name="license_id" widget="preview_many2one"/>
<field name="aptitude_id" widget="preview_many2one"/>
</group>
<group>
<field name="contract_id" widget="preview_many2one"/>
<field name="other_id" widget="preview_many2one"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_purchase_service_orders_action" model="ir.actions.act_window">
<field name="name">服务采购单</field>
<field name="res_model">purchase.service.orders</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_purchase_workflow_tree" model="ir.ui.view">
<field name="name">purchase.workflow.tree</field>
<field name="model">purchase.workflow</field>
<field name="arch" type="xml">
<tree string="采购工作流">
<field name="name"/>
<field name="user_id"/>
<field name="partner_id"/>
<field name="pay_way"/>
<field name="purchase_type"/>
</tree>
</field>
</record>
<record id="view_purchase_workflow_form" model="ir.ui.view">
<field name="name">purchase.workflow.form</field>
<field name="model">purchase.workflow</field>
<field name="arch" type="xml">
<form string="采购工作流表单">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success" invisible="urgency_level != 'normal'"/>
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning" invisible="urgency_level != 'urgent'"/>
<widget name="web_ribbon" title="特急" bg_color="text-bg-danger" invisible="urgency_level != 'emergency'"/>
<group col="2">
<group>
<field name="code" string="流水号" readonly="1"/>
</group>
<group>
<field name="urgency_level" readonly="1"/>
</group>
</group>
<div class="col-12 text-center mb-3">
<h1>
<field name="name_title" readonly="1"/>
</h1>
</div>
<div class="oe_title mb-4">
<label for="name"/>
<h1>
<field name="name" string="标题" required="1"/>
</h1>
</div>
<group string="审批信息" col="2" class="mb-4">
<group>
<field name="work_end" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="start_date"/>
<field name="user_id" string="申请人" required="1"/>
<field name="purchase_type" required="1"/>
<field name="partner_id" domain="[('company_id', '=', company_id)]" required="1"/>
<field name="pay_way" required="1"/>
</group>
<group>
<field name="date_order" string="订单日期"/>
<field name="date_planned" string="预计到货日期" invisible="purchase_type != 'fixed'"/>
<field name="service_start_date" string="服务开始时间" invisible="purchase_type != 'service'"/>
<field name="service_end_date" string="服务结束时间" invisible="purchase_type != 'service'"/>
<field name="service_year" string="服务年限" invisible="purchase_type != 'service'"/>
<field name="department_id" invisible="1"/>
</group>
</group>
<group>
<field name="reason_text"/>
</group>
<notebook string="采购明细" >
<page string="固定资产明细" invisible="purchase_type != 'fixed'">
<field name="fixed_line_ids">
<tree editable="bottom">
<field name="purchase_id" column_invisible="1"/>
<field name="product_id" required="1"/>
<field name="name" string="描述" required="1"/>
<field name="brand"/>
<field name="specs"/>
<field name="product_packaging_id"/>
<field name="number"/>
<field name="unit_id"/>
<field name="price_unit"/>
<field name="taxes_id"/>
<field name="total"/>
</tree>
</field>
</page>
<page string="低值易耗明细" invisible="purchase_type != 'low'">
<field name="low_line_ids">
<tree editable="bottom">
<field name="purchase_id" column_invisible="1"/>
<field name="product_id" string="物品名称" required="1"/>
<field name="name"/>
<field name="brand"/>
<field name="specs"/>
<field name="product_packaging_id"/>
<field name="number"/>
<field name="unit_id"/>
<field name="price"/>
<field name="taxes_id"/>
<field name="total"/>
</tree>
</field>
</page>
<page string="服务明细" invisible="purchase_type != 'service'">
<field name="service_line_ids">
<tree editable="bottom">
<field name="service_id" column_invisible="1"/>
<field name="product_id" required="1"/>
<field name="name" string="描述" required="1"/>
<field name="frequency"/>
<field name="fee"/>
<field name="product_packaging_id"/>
<field name="unit_id"/>
<field name="price"/>
<field name="taxes_id"/>
<field name="total"/>
</tree>
</field>
</page>
<page string="付款详情" invisible="pay_way == 'onetime'">
<field name="pay_line_ids">
<tree editable="bottom">
<field name="purchase_id" column_invisible="1"/>
<field name="payment_stage" required="1"/>
<field name="amount"/>
<field name="payment_date"/>
<field name="remake"/>
</tree>
</field>
</page>
</notebook>
<group>
<field name="document_ids" string="附件" widget="preview_many2many"/>
<field name="license_id" invisible="purchase_type != 'service'" widget="preview_many2one"/>
<field name="aptitude_id" invisible="purchase_type != 'service'" widget="preview_many2one"/>
<field name="contract_id" string="服务合同" invisible="purchase_type != 'service'" widget="preview_many2one"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_purchase_workflow_action" model="ir.actions.act_window">
<field name="name">采购申请单</field>
<field name="res_model">purchase.workflow</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
+3 -13
View File
@@ -18,21 +18,11 @@
parent="purchase_menus_order_root"
action="purchase.purchase_form_action"
sequence="5"/>
<menuitem id="purchase_fixed_assets_root"
name="固定资产采购单"
<menuitem id="purchase_fixe_assets_approval_root"
name="采购申请单"
parent="purchase_menus_order_root"
action="yuthon_purchase.view_purchase_fixed_assets_action"
action="yuthon_purchase.view_purchase_workflow_action"
sequence="7"/>
<menuitem id="purchase_low_orders_root"
name="低值易耗品采购单"
parent="purchase_menus_order_root"
action="yuthon_purchase.view_purchase_low_orders_action"
sequence="10"/>
<menuitem id="purchase_service_orders_root"
name="服务采购单"
parent="purchase_menus_order_root"
action="yuthon_purchase.view_purchase_service_orders_action"
sequence="15"/>
<menuitem id="purchase_suppliers_root"
name="供应商"
parent="purchase_menus_order_root"