Commit ed5de1a0 by 龚桂斌

Merge branch 'master' into 'tht-project'

# Conflicts:
#   tht_project/static/src/view/equipment_status.html
parents bb40424e 6f51b7e9
...@@ -3,3 +3,4 @@ from . import inherit_production_task ...@@ -3,3 +3,4 @@ from . import inherit_production_task
from . import inherit_workcenter from . import inherit_workcenter
from . import work_log from . import work_log
from . import inherit_roke_routing from . import inherit_roke_routing
from . import inherit_ir_http
import base64
import hashlib
import os
import re
from odoo import models, fields, http, api, _
from odoo.modules.module import get_resource_path, get_module_path
from odoo.tools.mimetypes import guess_mimetype
from odoo.tools import consteq, pycompat
class InheritIrHttp(models.AbstractModel):
_inherit = 'ir.http'
@classmethod
def _binary_ir_attachment_redirect_content(cls, record, default_mimetype='application/octet-stream'):
# mainly used for theme images attachemnts
base = http.request.env['ir.config_parameter'].sudo().get_param('web.base.url', '')
if record.type == 'url' and record.url and base.startswith("https") and "http://121.37.69.162:9000" in record.url:
filename = filehash = None
mimetype = getattr(record, 'mimetype', False)
url = record.url.replace("http://121.37.69.162:9000", "https://minio.xbg.rokeris.com")
status = 301
content = url
else:
status = content = filename = filehash = None
mimetype = getattr(record, 'mimetype', False)
if record.type == 'url' and record.url:
# if url in in the form /somehint server locally
url_match = re.match("^/(\w+)/(.+)$", record.url)
if url_match:
module = url_match.group(1)
module_path = get_module_path(module)
module_resource_path = get_resource_path(module, url_match.group(2))
if module_path and module_resource_path:
module_path = os.path.join(os.path.normpath(module_path),
'') # join ensures the path ends with '/'
module_resource_path = os.path.normpath(module_resource_path)
if module_resource_path.startswith(module_path):
with open(module_resource_path, 'rb') as f:
content = base64.b64encode(f.read())
status = 200
filename = os.path.basename(module_resource_path)
mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype)
filehash = '"%s"' % hashlib.md5(pycompat.to_text(content).encode('utf-8')).hexdigest()
if not content:
status = 301
content = record.url
return status, content, filename, mimetype, filehash
...@@ -9,9 +9,10 @@ ...@@ -9,9 +9,10 @@
<div id="jzjx_work_center_state" class="row" style="display:flex;justify-content: center;align-items: center;font-size: 30px;"> <div id="jzjx_work_center_state" class="row" style="display:flex;justify-content: center;align-items: center;font-size: 30px;">
<p style="color:#dee2e6;"><field name="deviceState"/></p> <p style="color:#dee2e6;"><field name="deviceState"/></p>
</div> </div>
<div id="work_center_wo"/>
</xpath> </xpath>
<xpath expr="//div[@id='work_center_empty']" position="replace"> <xpath expr="//div[@id='work_center_empty']" position="replace">
<div/> <div id="work_center_empty"/>
</xpath> </xpath>
</field> </field>
</record> </record>
......
# -*- coding: utf-8 -*-
from . import controllers
from . import models
\ No newline at end of file
# -*- coding: utf-8 -*-
{
'name': "融科-荏原",
'summary': """
Short (1 phrase/line) summary of the module's purpose, used as
subtitle on modules listing or apps.openerp.com""",
'description': """
Long description of module's purpose
""",
'author': "My Company",
'website': "http://www.yourcompany.com",
# Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/14.0/odoo/addons/base/data/ir_module_category_data.xml
# for the full list
'category': 'Uncategorized',
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['base'],
# always loaded
'data': [
# 'security/ir.model.access.csv',
'views/views.xml',
'views/templates.xml',
],
# only loaded in demonstration mode
'demo': [
'demo/demo.xml',
],
}
# -*- coding: utf-8 -*-
from . import controllers
\ No newline at end of file
import os
import datetime
import logging
import requests
from odoo.addons.roke_mes_client.controller import login as mes_login
from odoo import http, tools, SUPERUSER_ID
from jinja2 import FileSystemLoader, Environment
import pytz
from dateutil.relativedelta import relativedelta
_logger = logging.getLogger(__name__)
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
templateloader = FileSystemLoader(searchpath=BASE_DIR + "/static/src/view")
env = Environment(loader=templateloader)
class RokeMesThreeColourLight(http.Controller):
@http.route("/roke/three_color_light/device_state_list", type="http", auth='none', cors='*', csrf=False)
def device_state_list(self, **kwargs):
_self = http.request
factory_code = http.request.env(user=SUPERUSER_ID)['ir.config_parameter'].get_param('database.uuid', default="")
data = {"code": 1, "message": "请求通过", "data": {"factory_code": factory_code}}
template = env.get_template('equipment_status_qdry.html')
return template.render(data)
@http.route('/roke/workstation/plant/tree', type='json', auth='none', csrf=False, cors="*")
def get_roke_workstation_plant(self):
_self = http.request
no_icon = _self.jsonrequest.get("no_icon", False)
data = []
workshop_ids = http.request.env(user=SUPERUSER_ID)['roke.workshop'].search([
("plant_id", "=", False)
], order="name asc")
if len(workshop_ids) > 0:
data.append({
"id": 0,
"name": "未分配至车间",
"type": "plant",
"file_list": [],
"workshops": [
{
"id": workshop_id.id,
"name": workshop_id.name or "",
"type": "workshop",
"workshop_icon": workshop_id.workshop_icon or "",
"classes_id": workshop_id.classes_id.id,
"classes_name": workshop_id.classes_id.name or "",
"center_count": len(workshop_id.center_ids),
"file_list": [{
"name": attachment.name,
"file_type": attachment.mimetype,
"data": f"data:{attachment.mimetype};base64,{attachment.datas.decode('utf-8')}" if
not no_icon else "",
"url": self._get_attachment_file_url(attachment)
} for attachment in workshop_id.attachment_ids]
} for workshop_id in workshop_ids
]
})
plant_ids = http.request.env(user=SUPERUSER_ID)['roke.plant'].search([
], order="name asc")
for plant_id in plant_ids:
# print("plant_id", plant_id.company_ids)
data.append({
"id": plant_id.id,
"name": plant_id.name or "未分配至车间",
"type": "plant",
"file_list": [{
"name": attachment.name,
"file_type": attachment.mimetype,
"data": f"data:{attachment.mimetype};base64,{attachment.datas.decode('utf-8')}" if not no_icon
else "",
"url": self._get_attachment_file_url(attachment)
} for attachment in plant_id.attachment_ids],
"workshops": [
{
"id": workshop_id.id,
"name": workshop_id.name or "",
"type": "workshop",
"workshop_icon": workshop_id.workshop_icon or "",
"classes_id": workshop_id.classes_id.id,
"classes_name": workshop_id.classes_id.name or "",
"center_count": len(workshop_id.center_ids),
"file_list": [{
"name": attachment.name,
"file_type": attachment.mimetype,
"data": f"data:{attachment.mimetype};base64,{attachment.datas.decode('utf-8')}" if
not no_icon else "",
"url": self._get_attachment_file_url(attachment)
} for attachment in workshop_id.attachment_ids]
} for workshop_id in plant_id.workshop_ids
]
})
return {"code": 0, "message": "获取车间列表成功", "data": data}
\ No newline at end of file
<odoo>
<data>
<!--
<record id="object0" model="qdry_project.qdry_project">
<field name="name">Object 0</field>
<field name="value">0</field>
</record>
<record id="object1" model="qdry_project.qdry_project">
<field name="name">Object 1</field>
<field name="value">10</field>
</record>
<record id="object2" model="qdry_project.qdry_project">
<field name="name">Object 2</field>
<field name="value">20</field>
</record>
<record id="object3" model="qdry_project.qdry_project">
<field name="name">Object 3</field>
<field name="value">30</field>
</record>
<record id="object4" model="qdry_project.qdry_project">
<field name="name">Object 4</field>
<field name="value">40</field>
</record>
-->
</data>
</odoo>
\ No newline at end of file
# -*- coding: utf-8 -*-
from . import models
\ No newline at end of file
# -*- coding: utf-8 -*-
# from odoo import models, fields, api
# class qdry_project(models.Model):
# _name = 'qdry_project.qdry_project'
# _description = 'qdry_project.qdry_project'
# name = fields.Char()
# value = fields.Integer()
# value2 = fields.Float(compute="_value_pc", store=True)
# description = fields.Text()
#
# @api.depends('value')
# def _value_pc(self):
# for record in self:
# record.value2 = float(record.value) / 100
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_qdry_project_qdry_project,qdry_project.qdry_project,model_qdry_project_qdry_project,base.group_user,1,1,1,1
\ No newline at end of file
<odoo>
<data>
<!--
<template id="listing">
<ul>
<li t-foreach="objects" t-as="object">
<a t-attf-href="#{ root }/objects/#{ object.id }">
<t t-esc="object.display_name"/>
</a>
</li>
</ul>
</template>
<template id="object">
<h1><t t-esc="object.display_name"/></h1>
<dl>
<t t-foreach="object._fields" t-as="field">
<dt><t t-esc="field"/></dt>
<dd><t t-esc="object[field]"/></dd>
</t>
</dl>
</template>
-->
</data>
</odoo>
\ No newline at end of file
<odoo>
<data>
<!-- explicit list view definition -->
<!--
<record model="ir.ui.view" id="qdry_project.list">
<field name="name">qdry_project list</field>
<field name="model">qdry_project.qdry_project</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="value"/>
<field name="value2"/>
</tree>
</field>
</record>
-->
<!-- actions opening views on models -->
<!--
<record model="ir.actions.act_window" id="qdry_project.action_window">
<field name="name">qdry_project window</field>
<field name="res_model">qdry_project.qdry_project</field>
<field name="view_mode">tree,form</field>
</record>
-->
<!-- server action to the one above -->
<!--
<record model="ir.actions.server" id="qdry_project.action_server">
<field name="name">qdry_project server</field>
<field name="model_id" ref="model_qdry_project_qdry_project"/>
<field name="state">code</field>
<field name="code">
action = {
"type": "ir.actions.act_window",
"view_mode": "tree,form",
"res_model": model._name,
}
</field>
</record>
-->
<!-- Top menu item -->
<!--
<menuitem name="qdry_project" id="qdry_project.menu_root"/>
-->
<!-- menu categories -->
<!--
<menuitem name="Menu 1" id="qdry_project.menu_1" parent="qdry_project.menu_root"/>
<menuitem name="Menu 2" id="qdry_project.menu_2" parent="qdry_project.menu_root"/>
-->
<!-- actions -->
<!--
<menuitem name="List" id="qdry_project.menu_1_list" parent="qdry_project.menu_1"
action="qdry_project.action_window"/>
<menuitem name="Server to list" id="qdry_project" parent="qdry_project.menu_2"
action="qdry_project.action_server"/>
-->
</data>
</odoo>
\ No newline at end of file
import datetime import datetime
import pandas as pd
import xlsxwriter
from odoo import http, tools from odoo import http, tools
from odoo.http import content_disposition, request
import os import os
import io
from jinja2 import FileSystemLoader, Environment from jinja2 import FileSystemLoader, Environment
import logging import logging
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
...@@ -32,10 +35,19 @@ class ProductIncomeExpenseIframe(http.Controller): ...@@ -32,10 +35,19 @@ class ProductIncomeExpenseIframe(http.Controller):
"business_date": v.get("business_date", False), "business_date": v.get("business_date", False),
"abstract": v.get("abstract", False), "abstract": v.get("abstract", False),
"income": v.get("income", False), "income": v.get("income", False),
"expenditure": v.get("expenditure", False) "machinery_type": v.get("machinery_type", "其他"),
"expenditure": v.get("expenditure", False),
"customer": v.get("customer", False)
} }
_self.env(user=v.get("user_id"))["roke.product.income.expense"].create(data) # 看是否有id,如果有的话就说明是更新,没有的话就说明是创建
return {"code": 0, "message": "创建成功!"} if v.get("id", False):
expense_obj = _self.env["roke.product.income.expense"].sudo().search([("id", "=", v.get("id"))])
if not expense_obj:
return {"code": 1, "message": "更新失败,没找到对应数据。"}
expense_obj.write(data)
else:
_self.env(user=v.get("user_id"))["roke.product.income.expense"].create(data)
return {"code": 0, "message": "操作成功!"}
@http.route("/roke/product/product_income_expense/get", type="json", auth='none', cors='*', csrf=False) @http.route("/roke/product/product_income_expense/get", type="json", auth='none', cors='*', csrf=False)
def product_income_expense_get_list(self): def product_income_expense_get_list(self):
...@@ -44,10 +56,22 @@ class ProductIncomeExpenseIframe(http.Controller): ...@@ -44,10 +56,22 @@ class ProductIncomeExpenseIframe(http.Controller):
page = _self.jsonrequest.get("page", 1) page = _self.jsonrequest.get("page", 1)
start_date = _self.jsonrequest.get("start_date", "") start_date = _self.jsonrequest.get("start_date", "")
end_date = _self.jsonrequest.get("end_date", "") end_date = _self.jsonrequest.get("end_date", "")
type_str = _self.jsonrequest.get("type_str", False) # income收入/expenditure支出
machinery_type = _self.jsonrequest.get("machinery_type", False)
customer = _self.jsonrequest.get("customer", False)
abstract = _self.jsonrequest.get("abstract", False)
domain = [] domain = []
if start_date and end_date: if start_date and end_date:
domain.append(("business_date", ">=", start_date)) domain.append(("business_date", ">=", start_date))
domain.append(("business_date", "<=", end_date)) domain.append(("business_date", "<=", end_date))
if type_str:
domain.append((type_str, ">", 0))
if machinery_type:
domain.append(("machinery_type", "=", machinery_type))
if customer:
domain.append(("customer", "ilike", customer))
if abstract:
domain.append(("abstract", "ilike", abstract))
data_list = _self.env["roke.product.income.expense"].sudo().search(domain, limit=limit, data_list = _self.env["roke.product.income.expense"].sudo().search(domain, limit=limit,
offset=(page - 1) * limit, offset=(page - 1) * limit,
order="business_date desc, create_date desc") order="business_date desc, create_date desc")
...@@ -58,9 +82,11 @@ class ProductIncomeExpenseIframe(http.Controller): ...@@ -58,9 +82,11 @@ class ProductIncomeExpenseIframe(http.Controller):
"id": v.id, "id": v.id,
"business_date": v.business_date and v.business_date.strftime('%Y-%m-%d'), "business_date": v.business_date and v.business_date.strftime('%Y-%m-%d'),
"abstract": v.abstract or "", "abstract": v.abstract or "",
"income": v.income or 0, "customer": v.customer or "",
"expenditure": v.expenditure or 0, "income": round(v.income, 2) or 0,
"balance": v.balance or 0, "machinery_type": v.machinery_type or "其他",
"expenditure": round(v.expenditure) or 0,
"balance": round(v.balance, 2) or 0,
"user_name": v.create_uid.name or "", "user_name": v.create_uid.name or "",
"create_date": (v.create_date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'), "create_date": (v.create_date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'),
}) })
...@@ -77,3 +103,88 @@ class ProductIncomeExpenseIframe(http.Controller): ...@@ -77,3 +103,88 @@ class ProductIncomeExpenseIframe(http.Controller):
return {"code": 1, "message": "删除失败,没找到对应数据。"} return {"code": 1, "message": "删除失败,没找到对应数据。"}
data.unlink() data.unlink()
return {"code": 0, "message": "删除成功!"} return {"code": 0, "message": "删除成功!"}
@http.route("/roke/product/product_income_expense/export", type="http", auth='none', cors='*', csrf=False)
def get_product_income_expense_export(self, **kwargs):
_self = http.request
start_date = kwargs.get("start_date", "")
end_date = kwargs.get("end_date", "")
type_str = kwargs.get("type_str", False) # income收入/expenditure支出
machinery_type = kwargs.get("machinery_type", False)
customer = kwargs.get("customer", False)
abstract = kwargs.get("abstract", False)
domain = []
if start_date and end_date:
domain.append(("business_date", ">=", start_date))
domain.append(("business_date", "<=", end_date))
if type_str:
domain.append((type_str, ">", 0.0))
if machinery_type:
domain.append(("machinery_type", "=", machinery_type))
if customer:
domain.append(("customer", "ilike", customer))
if abstract:
domain.append(("abstract", "ilike", abstract))
data_list = _self.env["roke.product.income.expense"].sudo().search(domain, order="business_date desc, create_date desc")
data = []
for v in data_list:
data.append({
"business_date": v.business_date,
"abstract": v.abstract or "",
"customer": v.customer or "",
"income": v.income or 0,
"expenditure": v.expenditure or 0,
"balance": v.balance or 0,
"machinery_type": v.machinery_type or '其他',
"user_name": v.create_uid.name or "",
"create_date": v.create_date + datetime.timedelta(hours=8),
})
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
worksheet = workbook.add_worksheet('Sheet1')
header_format = workbook.add_format({
'bold': True, 'border': 1,
'fg_color': '#17a2b8', 'font_color': '#FFFFFF',
'align': 'center', 'valign': 'vcenter'
})
date_format = workbook.add_format({'num_format': 'YYYY-MM-DD'})
datetime_format = workbook.add_format({'num_format': 'YYYY-MM-DD HH:MM'})
currency_format = workbook.add_format({'num_format': '#,##0.00'}) # 逗号作为千分位分隔符
worksheet.write(0, 0, "业务日期", header_format)
worksheet.write(0, 1, "摘要", header_format)
worksheet.write(0, 2, "客户", header_format)
worksheet.write(0, 3, "收入", header_format)
worksheet.write(0, 4, "支出", header_format)
worksheet.write(0, 5, "结余", header_format)
worksheet.write(0, 6, "类型", header_format)
worksheet.write(0, 7, "创建人", header_format)
worksheet.write(0, 8, "创建时间", header_format)
for row_num, row_data in enumerate(data):
worksheet.write_datetime(row_num + 1, 0, row_data.get("business_date"), date_format)
worksheet.write(row_num + 1, 1, row_data.get("abstract"))
worksheet.write(row_num + 1, 2, row_data.get("customer"))
worksheet.write_number(row_num + 1, 3, row_data.get("income"), currency_format)
worksheet.write_number(row_num + 1, 4, row_data.get("expenditure"), currency_format)
worksheet.write_number(row_num + 1, 5, row_data.get("balance"), currency_format)
worksheet.write(row_num + 1, 6, row_data.get("machinery_type"))
worksheet.write(row_num + 1, 7, row_data.get("user_name"))
worksheet.write_datetime(row_num + 1, 8, row_data.get("create_date"), datetime_format)
workbook.close()
output.seek(0)
file_name = '财务收支记录.xlsx'
response = request.make_response(
None,
headers=[
('Content-Type', 'application/vnd.ms-excel'),
('Content-Disposition', content_disposition(file_name))
]
)
response.stream.write(output.read())
output.close()
return response
...@@ -14,10 +14,13 @@ class ProductIncomeExpense(models.Model): ...@@ -14,10 +14,13 @@ class ProductIncomeExpense(models.Model):
income = fields.Float(string="收入") income = fields.Float(string="收入")
expenditure = fields.Float(string="支出") expenditure = fields.Float(string="支出")
balance = fields.Float(string="结余", compute="_compute_balance") balance = fields.Float(string="结余", compute="_compute_balance")
machinery_type = fields.Selection([("烘干桶", "烘干桶"), ("钣金", "钣金"), ("颗粒机", "颗粒机"), ("其他", "其他")],
default="其他", string="类型")
customer = fields.Char(string="客户")
@api.depends("income", "expenditure") @api.depends("income", "expenditure")
def _compute_balance(self): def _compute_balance(self):
data = self.search([("id", "in", self.ids)], order="business_date asc, create_date asc") data = self.search([], order="business_date asc, create_date asc")
for v in data: for v in data:
last_data = self.search([ last_data = self.search([
"|", "|",
...@@ -28,6 +31,6 @@ class ProductIncomeExpense(models.Model): ...@@ -28,6 +31,6 @@ class ProductIncomeExpense(models.Model):
("id", "!=", v.id) ("id", "!=", v.id)
], limit=1, order="business_date desc, create_date desc") ], limit=1, order="business_date desc, create_date desc")
if not last_data: if not last_data:
v.balance = 0 + v.income - v.expenditure v.balance = round(0 + v.income - v.expenditure, 2)
else: else:
v.balance = last_data.balance + v.income - v.expenditure v.balance = round(last_data.balance + v.income - v.expenditure, 2)
...@@ -589,6 +589,8 @@ ...@@ -589,6 +589,8 @@
// 如果找到匹配的设备,使用其名称 // 如果找到匹配的设备,使用其名称
if (matchedDevice && matchedDevice.name) { if (matchedDevice && matchedDevice.name) {
deviceName = device.name ? matchedDevice.name : device.code deviceName = device.name ? matchedDevice.name : device.code
} else {
return false
} }
} }
return { return {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment