Files
gzth/reportbro/models/report.py
T
2024-05-29 16:13:44 +08:00

459 lines
20 KiB
Python

import json, uuid, requests, os
from odoo import models, fields, api
from odoo.exceptions import UserError
from . import datasource
from PyPDF2 import PdfFileWriter, PdfFileReader
FIELD_TYPES = [(key, key) for key in sorted(fields.Field.by_type)]
import tempfile
#################
dir = tempfile.gettempdir()
# dir='/opt/odoo'
login = 'test'
password = 'test'
##################
class BaseModelExtend(models.AbstractModel):
_name = 'base.model.extend'
_description = '继承基类模型'
def _register_hook(self):
def GetUrl(self):
self._cr.execute("select value from ir_config_parameter where key ='web.base.url'")
dicts = self._cr.dictfetchall()
return str(dicts[0]['value'])
def getOdooToken(self):
url = GetUrl(self) + "/web/session/authenticate"
# 传入需要访问的数据库名称,登录账号与密码
data = {
"params": {
"db": self._cr.dbname,
"login": login,
"password": password,
}
}
headers = {'Content-type': 'application/json'}
response = requests.post(url, headers=headers, json=data)
return response.cookies["session_id"]
def report_pdf_prints(self, args, types):
'''
PDF打印公共方法
:param self:
:return:
'''
# 模型数据ID
# 模型名称
report_id = args
print_type = 'pdf' if types == 0 else 'xlsx'
data_id = self._context.get('active_ids', None)
report_report = self.env['report.report'].browse(report_id)
data_model = self._context.get('active_model', None)
data_model_details = report_report.model_detail_id.model if report_report.report_type == 'bill' else ''
if data_model is None:
raise UserError('获取数据源失败')
res_id = self.env[data_model].read_group([('id', 'in', data_id)], [report_report.group_field],
[report_report.group_field])
headers = {
'Connection': 'keep-alive',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36',
'Cookie': 'session_id=' + getOdooToken(self)
}
inFileList = []
for s_code in res_id:
s_id = []
wheres_id = self.env[data_model].search(
[('id', 'in', data_id), (report_report.group_field, '=', s_code[report_report.group_field])])
for wid in wheres_id:
s_id.append(wid.id)
dic = {}
dic['report'] = json.loads(report_report.report_data)
dic['data'] = datasource.wms_datasource.get_data(self, report_id, s_id, data_model, data_model_details,
report_report.model_main_key)
dic['outputFormat'] = print_type
dic['isTestData'] = True
res = requests.post(self.GetUrl() + '/api/report/report_server/run',
data={'data': str(json.dumps(dic))}, headers=headers, allow_redirects=True)
print(res.text)
key = str(res.text.split(':')[1])
url = self.GetUrl() + '/api/report/report_server/run?key=' + key + '&outputFormat=' + print_type
r = requests.get(url, stream=True, cookies={'session_id': getOdooToken(self)})
pdf = "/%s.pdf" % key
# 获取temp临时文件路径
pdf = dir + pdf
inFileList.append(pdf)
with open(pdf, "wb") as pdf:
for chunk in r.iter_content(chunk_size=1024):
if chunk:
pdf.write(chunk)
filename = dir + "/print.pdf"
pdfFileWriter = PdfFileWriter()
for inFile in inFileList:
with open(inFile, 'rb') as f:
pdfReader = PdfFileReader(f)
numPages = pdfReader.getNumPages()
for index in range(0, numPages):
pageObj = pdfReader.getPage(index)
pdfFileWriter.addPage(pageObj)
pdfFileWriter.write(open(filename, 'wb'))
os.unlink(inFile)
with open(filename, 'rb') as pdf_document:
pdf_content = pdf_document.read()
os.unlink(filename)
key_uid = str(uuid.uuid4())
self.env['wms.print.list'].create({'p_key': key_uid, 'report_file_pdf': pdf_content})
if print_type == 'pdf':
# 打开新页面
# return {
# 'type': 'ir.actions.act_url',
# 'title':'打印预览',
# 'name': '打印预览',
# 'url': self.GetUrl() + '/api/report/report_server/run?key=' +key_uid+'&outputFormat=' + print_type + '&report_id='+str(args),
# 'target': 'new'
#
# }
return {
'type': 'ir.actions.act_window',
'name': '打印预览',
'res_model': 'wms.print.list',
'views': [[False, "form"]],
'target': 'new',
'context': {
'default_name': '<iframe src="' + self.GetUrl() + '/api/report/report_server/run?key=' + key_uid + '&outputFormat=' + print_type + '&report_id=' + str(
args) + '" marginheight="0" marginwidth="0" width="100%" height="700px" />'}
}
models.BaseModel.GetUrl = GetUrl
models.BaseModel.report_pdf_prints = report_pdf_prints
return super(BaseModelExtend, self)._register_hook()
class wmsprintlist(models.Model):
_name = 'wms.print.list'
_description = '打印服务表'
p_key = fields.Char('内容键')
report_file_pdf = fields.Binary('PDF', attachment=False)
report_file_xlsx = fields.Binary('XLSX', attachment=False)
print_status = fields.Boolean('打印状态', default=False)
name = fields.Html('预览', store=False, sanitize=False)
class ReportReport(models.Model):
_name = "report.report"
_description = "Report"
name = fields.Char(string='报表名称', required=True)
model_id = fields.Many2one('ir.model', string='主表模型', ondelete="cascade", required=True,
help='至少要存在一个数据模型')
model_detail_id = fields.Many2one('ir.model', string='明细表模型', ondelete="cascade")
report = fields.Text(string='报表')
model_main_key = fields.Char('主模型Key', help='主数据模型和明细模型的关联字段名称', default='order_id')
model_ids = fields.One2many('report.report.main', 'report_main_id', string='主表字段')
model_detail_ids = fields.One2many('report.report.detail', 'report_detail_id', string='明细字段')
display_complete = fields.Boolean(string='动作添加', default=False)
display_completes = fields.Boolean(string='批量动作添加', default=False)
reset_designer = fields.Boolean(string='重新设计', default=False, help='勾选上会进入空白模板,不再读取存储的配置')
report_data = fields.Text('模板数据')
data_source = fields.Char(string='数据源')
test_data = fields.Text('数据结构')
pdf_name = fields.Text('PDF名称')
report_type = fields.Selection(selection=[('bill', '单据'), ('report', '报表')], string='报表类型',
help='一般带主表,明细表模型的为单据类报表,单个模型的为纯报表类型')
group_field = fields.Char(string='套打字段', help='用于批量打印时,区分每页的关键字段')
@api.model
def default_get(self, fields):
res = super(ReportReport, self).default_get(fields)
res['data_source'] = 'a' + ''.join(str(uuid.uuid4()).split('-'))
return res
def add_print_actions(self):
self.del_print_actions()
res = self.env['report.report'].search([('id', '=', self.id)])
if res.group_field is False:
raise UserError('汇总打印字段不能为空')
model = self.env['ir.model'].search([('model', '=', 'report.report')])
res.write({'display_completes': True})
act_type = 'list,form' if res.report_type == 'bill' else 'list'
sql_pdf = "insert into ir_act_server (name,type,binding_model_id,binding_type,binding_view_types,usage,state,sequence,model_id,model_name,code,activity_date_deadline_range_type,activity_user_type) values ('" + json.dumps(
{'zh_CN': self.name}) + "','ir.actions.server', " + str(
res.model_id.id) + ",'action', '" + act_type + "','ir_actions_server','code',5, " + str(
model.id) + ",'report.report','action = model.report_pdf_prints(" + str(
self.id) + ",0)','days','specific');"
self._cr.execute(sql_pdf)
def del_print_actions(self):
res = self.env['report.report'].search([('id', '=', self.id)])
res.write({'display_completes': False})
self._cr.execute('delete from ir_act_server where name=%s', (json.dumps({'zh_CN': self.name}),))
def button_designer(self):
res = self.env['report.report'].search([('id', '=', self.id)])
# 重新设置模板参数
if res.reset_designer:
report_main = self.env['report.report.main'].search(
[('report_main_id', '=', self.id), ('is_report', '=', True)])
report_detail = self.env['report.report.detail'].search(
[('report_detail_id', '=', self.id), ('is_report', '=', True)])
res_main = []
res_detail = []
for r in report_main:
res_main.append(r.field_id.id)
for r2 in report_detail:
res_detail.append(r2.field_id.id)
# report_main_names = self.env['ir.model.fields'].search([('id', 'in', res_main)])
# report_detail_names = self.env['ir.model.fields'].search([('id', 'in', res_detail)])
parameters = [{
'id': 1, 'name': 'page_count', 'type': 'number', 'arrayItemType': 'string', 'eval': False,
'nullable': False, 'pattern': '', 'expression': '', 'showOnlyNameType': True,
'testData': ''
},
{
'id': 2, 'name': 'page_number', 'type': 'number', 'arrayItemType': 'string', 'eval': False,
'nullable': False, 'pattern': '', 'expression': '', 'showOnlyNameType': True,
'testData': ''
}]
data = {}
index = 3
# 主表
for rmn in report_main:
data[rmn.field_params] = ''
parameters.append({
'id': index,
'name': rmn.field_params,
'type': self.get_type(rmn.ttype),
'arrayItemType': self.get_type(rmn.ttype),
'eval': False,
'nullable': False,
'pattern': '',
'expression': '',
'showOnlyNameType': False,
'testData': ''
})
index += 1
# 序号
children = [{
'id': 888,
'name': 'index',
'type': 'string',
'arrayItemType': 'string',
'eval': False,
'nullable': False,
'pattern': '',
'expression': '',
'showOnlyNameType': False,
'testData': ''}]
test_data2 = []
# 明细表
r = {}
for rmn in report_detail:
r[rmn.field_params] = ''
children.append({
'id': index,
'name': rmn.field_params,
'type': self.get_type(rmn.ttype),
'arrayItemType': self.get_type(rmn.ttype),
'eval': False,
'nullable': False,
'pattern': '',
'expression': '',
'showOnlyNameType': False,
'testData': ''})
index += 1
test_data2.append(r)
parameters.append({
'id': 9999,
'name': 'res_detail',
'type': 'array',
'arrayItemType': 'array',
'eval': False,
'nullable': False,
'pattern': '',
'expression': '',
'showOnlyNameType': False,
'testData': '',
'children': children
})
data['res_detail'] = test_data2
r_data = res.report_data
if res.report_data is False:
r_data = str(json.dumps({'docElements': [], 'parameters': [
{
'id': 1, 'name': 'page_count', 'type': 'number', 'arrayItemType': 'string', 'eval': False,
'nullable': False, 'pattern': '', 'expression': '', 'showOnlyNameType': True,
'testData': ''
},
{
'id': 2, 'name': 'page_number', 'type': 'number', 'arrayItemType': 'string', 'eval': False,
'nullable': False, 'pattern': '', 'expression': '', 'showOnlyNameType': True,
'testData': ''
}],
'styles': [], 'version': 3,
'documentProperties': {
'pageFormat': 'A4', 'pageWidth': '', 'pageHeight': '',
'unit': 'mm', 'orientation': 'portrait', 'contentHeight': '',
'marginLeft': '', 'marginTop': '', 'marginRight': '',
'marginBottom': '', 'header': True, 'headerSize': '80',
'headerDisplay': 'always', 'footer': True, 'footerSize': '80',
'footerDisplay': 'always', 'patternLocale': 'en',
'patternCurrencySymbol': '$'}}))
report_data = json.loads(r_data)
report_data['parameters'] = parameters
res.write({'report_data': json.dumps(report_data), 'test_data': data, 'reset_designer': False})
self.env['report.designer'].sudo().create({'name': str(self.id)})
return {
'type': 'ir.actions.client',
'name': '报表设计',
'tag': 'report_designer',
'target': 'current',
'params': {
'report_id': self.id
}
}
def get_type(self, type_name):
res = {'char': 'string',
'text': 'string',
'one2many': 'string',
'many2one': 'string',
'many2many': 'string',
'integer': 'number',
'float': 'number',
'datetime': 'string',
'date': 'string',
'boolean': 'boolean',
'selection': 'string',
'monetary': 'number',
'binary': 'string',
'html': 'string',
'reference': 'string',
'image': 'image',
'image_url': 'string',
'json': 'string'
}
return res[type_name]
class ReportReportMain(models.Model):
_name = "report.report.main"
_description = "Report Main"
report_main_id = fields.Many2one('report.report', string='Report Main')
model_id = fields.Many2one('ir.model', string='Model', ondelete="cascade")
field_domain = fields.Many2many('ir.model.fields', string='Field Domain', compute='_compute_field_domain')
field_id = fields.Many2one('ir.model.fields', string='字段名称', ondelete="cascade", required=True)
field_description = fields.Char(string='字段', related='field_id.name')
field_params = fields.Char(string='参数')
field_value = fields.Char(string='字段取值', compute='_field_custom', store=True, inverse='_field_custom_inverse')
ttype = fields.Selection(selection=FIELD_TYPES, string='类型', related='field_id.ttype')
is_report = fields.Boolean(string='报表', default=True)
@api.depends('field_id')
def _field_custom(self):
for s in self:
s.field_params = s.field_description
if s.ttype in ['text', 'char', 'html']:
s.field_value = "str(s." + str(s.field_id.name) + ") or ''"
elif s.ttype in ['date', 'datetime', 'boolean']:
s.field_value = "str(s." + str(s.field_id.name) + ") or ''"
elif s.ttype in ['integer', 'float', 'monetary']:
s.field_value = "s." + str(s.field_id.name) + " or 0"
elif s.ttype in ['one2many', 'many2one', 'many2many']:
s.field_value = "str(s." + str(s.field_id.name) + ".name) or ''"
elif s.ttype == 'selection':
s.field_value = "str(dict(self.env['" + str(s.model_id.model) + "'].fields_get(allfields=['" + str(
s.field_id.name) + "'])['" + str(s.field_id.name) + "']['selection'])[s." + str(
s.field_id.name) + "]) or ''"
else:
s.field_value = "s." + str(s.field_id.name)
def _field_custom_inverse(self):
pass
@api.depends('model_id')
def _compute_field_domain(self):
for record in self:
fields = []
record.field_domain = self._get_fields(fields=fields, model=record.model_id)
def _get_fields(self, fields=None, model=None):
for field in model.field_id:
if field.ttype != 'one2many':
fields.append(field.id)
return fields
class ReportReportDetail(models.Model):
_name = "report.report.detail"
_description = "Report detail"
report_detail_id = fields.Many2one('report.report', string='Report detail')
model_id = fields.Many2one('ir.model', string='Model', ondelete="cascade")
field_domain = fields.Many2many('ir.model.fields', string='Field Domain', compute='_compute_field_domain')
field_id = fields.Many2one('ir.model.fields', string='字段名称', ondelete="cascade", required=True)
field_description = fields.Char(string='字段', related='field_id.name')
field_params = fields.Char(string='参数')
field_value = fields.Char(string='字段取值', compute='_field_custom', store=True, inverse='_field_custom_inverse')
ttype = fields.Selection(selection=FIELD_TYPES, string='类型', related='field_id.ttype')
is_report = fields.Boolean(string='报表', default=True)
@api.depends('field_id')
def _field_custom(self):
for s in self:
s.field_params = s.field_description
if s.ttype in ['text', 'char', 'html']:
s.field_value = "str(s." + str(s.field_id.name) + ") or ''"
elif s.ttype in ['date', 'datetime', 'boolean']:
s.field_value = "str(s." + str(s.field_id.name) + ") or ''"
elif s.ttype in ['integer', 'float', 'monetary']:
s.field_value = "s." + str(s.field_id.name) + " or 0"
elif s.ttype in ['one2many', 'many2one', 'many2many']:
s.field_value = "str(s." + str(s.field_id.name) + ".name) or ''"
elif s.ttype == 'selection':
s.field_value = "str(dict(self.env['" + str(s.model_id.model) + "'].fields_get(allfields=['" + str(
s.field_id.name) + "'])['" + str(s.field_id.name) + "']['selection'])[s." + str(
s.field_id.name) + "]) or ''"
else:
s.field_value = "s." + str(s.field_id.name)
def _field_custom_inverse(self):
pass
@api.depends('model_id')
def _compute_field_domain(self):
for record in self:
fields = []
record.field_domain = self._get_fields(fields=fields, model=record.model_id)
def _get_fields(self, fields=None, model=None):
for field in model.field_id:
if field.ttype != 'one2many':
fields.append(field.id)
return fields