提交 883f16f6 authored 作者: 伍姿英's avatar 伍姿英

Merge branch 'release/V2.3.0'

......@@ -29,6 +29,7 @@
'views/cc_big_package_view.xml',
'views/cc_node_exception_reason_view.xml',
'views/cc_bl_view.xml',
'views/res_config_setting.xml',
# 'views/cc_customers_declaration_order_view.xml',
'templates/login.xml',
],
......
......@@ -6,3 +6,6 @@ from . import cc_node_exception_reason
from . import mail_thread
from . import common_common
from . import fetch_mail
from . import order_state_change_rule
from . import res_config_setting
......@@ -2,7 +2,7 @@
import ast
import base64
import re
from datetime import timedelta
from datetime import timedelta, datetime
from pygtrans import Translate
import xlrd
import pytz
......@@ -898,6 +898,72 @@ class CcBL(models.Model):
# 定义清关国家,关联到国家字段
cc_country_id = fields.Many2one('res.country', string='CC Country')
def push_clear_customs_start(self, utc_time):
# 创建向导
push_node_obj = self.env['cc.node'].sudo().search([('node_type', '=', 'package'), ('tk_code', '=', 'cb_imcustoms_start')], limit=1)
node_obj = self.env['cc.node'].sudo().search([('node_type', '=', 'package'), ('seq', '<', push_node_obj.seq)], order='seq desc',
limit=1)
vals = {
'bl_id': self.id,
'bl_count': 1,
'current_status': node_obj.id,
'update_status': push_node_obj.id,
'process_time': utc_time,
'is_ok': True
}
wizard_obj = self.env['batch.input.ship.package.status.wizard'].sudo().create(vals)
wizard_obj.change_ship_package_ids()
wizard_obj = wizard_obj.with_context(dict(self._context, active_id=self.id))
wizard_obj.submit()
def push_clear_customs_end(self, utc_time):
# 创建向导
push_node_obj = self.env['cc.node'].sudo().search([('node_type', '=', 'package'), ('tk_code', '=', 'cb_imcustoms_finished')], limit=1)
node_obj = self.env['cc.node'].sudo().search([('node_type', '=', 'package'), ('seq', '<', push_node_obj.seq)],
order='seq desc',
limit=1)
vals = {
'bl_id': self.id,
'bl_count': 1,
'current_status': node_obj.id,
'update_status': push_node_obj.id,
'process_time': utc_time,
'is_ok': True
}
wizard_obj = self.env['batch.input.ship.package.status.wizard'].sudo().create(vals)
wizard_obj.change_ship_package_ids()
wizard_obj = wizard_obj.with_context(dict(self._context, active_id=self.id))
# print(wizard_obj.get_order())
wizard_obj.submit()
def try_callback_track(self, max_retries=3):
""" 封装的重试逻辑 """
for i in range(max_retries):
is_ok = self.callback_track()
if is_ok:
return True
logging.warning(f"Attempt {i + 1}/{max_retries} failed. Retrying...")
return False
def mail_auto_push(self, mail_time):
self = self.with_context(dict(self._context, is_mail=True))
for item in self:
try:
utc_time = datetime.strptime(mail_time, "%Y-%m-%d %H:%M:%S")
before_min = self.env['ir.config_parameter'].sudo().get_param('before_min') or 10
before_utc_time = utc_time - timedelta(minutes=int(before_min))
item.push_clear_customs_start(before_utc_time)
# 尝试调用 callback_track
if self.try_callback_track():
item.push_clear_customs_end(utc_time)
# 再次尝试调用 callback_track
if not self.try_callback_track():
logging.error(f"Failed to push item after {3} attempts.")
else:
logging.error(f"Failed to start process for item after {3} attempts.")
except Exception as err:
logging.error('fetch_mail_dlv--error:%s' % str(err))
# 增加一个清关进度的业务对象,继承自models.Model, 用于管理业务数据.业务数据包括提单号、清关节点(业务对象)、进度日期、进度描述、更新人
class CcProgress(models.Model):
......
......@@ -3,9 +3,9 @@ import datetime
import re
from odoo import fields, models, exceptions, api, tools
import logging
from .redis_connection import redis_connection
__author__ = 'zd'
r = redis_connection()
_logger = logging.getLogger(__name__)
......@@ -22,3 +22,10 @@ class CommonCommon(models.Model):
d = dt + datetime.timedelta(hours=8)
nTime = d.strftime("%Y-%m-%d %H:%M:%S")
return nTime
def get_redis(self):
"""
连接redis
:return:
"""
return r
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
import poplib
import time
from ssl import SSLError
from socket import gaierror, timeout
from imaplib import IMAP4, IMAP4_SSL
from poplib import POP3, POP3_SSL
import email
from odoo import api, fields, models, tools, _
from odoo.exceptions import UserError
from datetime import datetime, timedelta
from email.utils import parseaddr
import pytz
_logger = logging.getLogger(__name__)
MAX_POP_MESSAGES = 50
MAIL_TIMEOUT = 60
# Workaround for Python 2.7.8 bug https://bugs.python.org/issue23906
poplib._MAXLINE = 65536
month_dict = {
'Jan': '1',
'Feb': '2',
'Mar': '3',
'Apr': '4',
'May': '5',
'Jun': '6',
'Jul': '7',
'Aug': '8',
'Sep': '9',
'Oct': '10',
'Nov': '11',
'Dec': '12',
'1': 'Jan',
'2': 'Feb',
'3': 'Mar',
'4': 'Apr',
'5': 'May',
'6': 'Jun',
'7': 'Jul',
'8': 'Aug',
'9': 'Sep',
'10': 'Oct',
'11': 'Nov',
'12': 'Dec',
}
class FetchmailServer(models.Model):
"""Incoming POP/IMAP mail server account"""
_inherit = 'fetchmail.server'
_description = 'Incoming Mail Server'
_order = 'priority'
def get_location_time(self):
"""
获取当前时区时间(带时区)
:return:
"""
now_time = datetime.utcnow()
tz = self.env.user.tz or 'Asia/Shanghai'
return now_time.replace(tzinfo=pytz.timezone(tz))
def fetch_mail(self):
""" WARNING: meant for cron usage only - will commit() after each email! """
additionnal_context = {
'fetchmail_cron_running': True
}
MailThread = self.env['mail.thread']
for server in self:
_logger.info('start checking for new emails on %s server %s', server.server_type, server.name)
additionnal_context['default_fetchmail_server_id'] = server.id
count, failed = 0, 0
imap_server = None
pop_server = None
if server.server_type == 'imap':
try:
imap_server = server.connect()
imap_server.select()
# 匹配时间
mail_send_timezone = self.env['ir.config_parameter'].sudo().get_param('mail_send_timezone') or '+1'
mail_match_minute = self.env['ir.config_parameter'].sudo().get_param('mail_match_minute') or 180
utc_now = self.get_location_time()
if mail_send_timezone[0] == '+':
now = utc_now + timedelta(hours=int(mail_send_timezone[1:]))
else:
now = utc_now - timedelta(hours=int(mail_send_timezone[1:]))
before_now = (now - timedelta(minutes=int(mail_match_minute))).strftime("%Y-%m-%d %H:%M:%S")
# 今天 mail_before_day查询多少天以前的
today = datetime.now()
mail_before_day = int(self.env['ir.config_parameter'].sudo().get_param('mail_before_day') or 0)
offset = timedelta(days=-mail_before_day)
last_day = (today + offset).strftime('%d-%b-%Y')
_logger.info('last_day:%s,before_now:%s' % (last_day, before_now))
# imap_server._mode_utf8()
# result, data = imap_server.search(None, 'SINCE', last_day)
result, data = imap_server.search(None, '(UNSEEN)', last_day)
# result, data = imap_server.search(None, '(UNSEEN)')
_logger.info('mail_data:%s' % data[0])
for num in data[0].split():
result, data = imap_server.fetch(num, '(RFC822)')
msg = email.message_from_string(data[0][1].decode('utf-8', 'ignore'))
subject = msg.get('subject') # 标题
date = email.header.decode_header(msg.get('date')) # 发件时间
time_list = date[0][0].split(',')[1].split(' ')
# date里面的空格可能是一个两个
time_list = list(filter(None, time_list))
year = time_list[2] # 发件时间的年份
# 取8分钟之内接收的邮件
b_time = '%s %s %s %s' % (time_list[0], time_list[1], time_list[2], time_list[3])
_logger.info('--b_time:%s--' % b_time)
try:
a_time = time.strftime("%Y-%m-%d %H:%M:%S", time.strptime(b_time, "%d %b %Y %H:%M:%S"))
except Exception as e:
b_time = '%s-%s-%s %s' % (time_list[2], month_dict[time_list[1]], time_list[0], time_list[3])
a_time = time.strftime("%Y-%m-%d %H:%M:%S", time.strptime(b_time, "%Y-%m-%d %H:%M:%S"))
# print(a_time, before_now)
if a_time > before_now:
hdr, sender_email = parseaddr(msg.get('From')) # 获取发件人邮箱
email_body = ''
for part in msg.walk():
# 如果ture的话内容是没用的
if not part.is_multipart():
# 解码出内容
# email_body = part.get_payload(decode=True).decode('utf-8', 'ignore')
email_body = part.get_payload(decode=True).decode('gbk', 'ignore')
break
if email_body:
if 'CDS REPORT' in subject.upper():
rule_obj = self.env['order.state.change.rule'].sudo()
rule_obj.fetch_mail_dlv(email_body=email_body, year=year)
imap_server.store(num, '-FLAGS', '\\Seen')
try:
pass
# res_id = MailThread.with_context(**additionnal_context).message_process(server.object_id.model, data[0][1], save_original=server.original, strip_attachments=(not server.attach))
except Exception:
_logger.info('Failed to process mail from %s server %s.', server.server_type,
server.name,
exc_info=True)
failed += 1
imap_server.store(num, '+FLAGS', '\\Seen')
self._cr.commit()
count += 1
_logger.info("Fetched %d email(s) on %s server %s; %d succeeded, %d failed.", count,
server.server_type, server.name, (count - failed), failed)
except Exception as e:
_logger.info("General failure when trying to fetch mail from %s server %s.error:%s",
server.server_type,
server.name, e, exc_info=True)
finally:
if imap_server:
try:
imap_server.close()
imap_server.logout()
except OSError:
_logger.warning('Failed to properly finish imap connection: %s.', server.name,
exc_info=True)
elif server.server_type == 'pop':
try:
while True:
pop_server = server.connect()
(num_messages, total_size) = pop_server.stat()
pop_server.list()
for num in range(1, min(MAX_POP_MESSAGES, num_messages) + 1):
(header, messages, octets) = pop_server.retr(num)
message = (b'\n').join(messages)
res_id = None
try:
res_id = MailThread.with_context(**additionnal_context).message_process(
server.object_id.model, message, save_original=server.original,
strip_attachments=(not server.attach))
pop_server.dele(num)
except Exception:
_logger.info('Failed to process mail from %s server %s.', server.server_type,
server.name, exc_info=True)
failed += 1
self.env.cr.commit()
if num_messages < MAX_POP_MESSAGES:
break
pop_server.quit()
_logger.info("Fetched %d email(s) on %s server %s; %d succeeded, %d failed.", num_messages,
server.server_type, server.name, (num_messages - failed), failed)
except Exception:
_logger.info("General failure when trying to fetch mail from %s server %s.", server.server_type,
server.name, exc_info=True)
finally:
if pop_server:
pop_server.quit()
server.write({'date': fields.Datetime.now()})
return True
......@@ -101,3 +101,33 @@ class MailThread(models.AbstractModel):
# raise exceptions.UserError(_("Unable to send message, please configure the sender's email address."))
return author_id, email_from
@api.model
def message_new(self, msg_dict, custom_values=None):
"""Called by ``message_process`` when a new message is received
for a given thread model, if the message did not belong to
an existing thread.
The default behavior is to create a new record of the corresponding
model (based on some very basic info extracted from the message).
Additional behavior may be implemented by overriding this method.
:param dict msg_dict: a map containing the email details and
attachments. See ``message_process`` and
``mail.message.parse`` for details.
:param dict custom_values: optional dictionary of additional
field values to pass to create()
when creating the new thread record.
Be careful, these values may override
any other values coming from the message.
:rtype: int
:return: the id of the newly created thread object
"""
data = {}
if isinstance(custom_values, dict):
data = custom_values.copy()
fields = self.fields_get()
name_field = self._rec_name or 'name'
if name_field in fields and not data.get('name'):
data[name_field] = msg_dict.get('subject', '')
# return self.create(data)
return True
\ No newline at end of file
# -*- coding: utf-8 -*-
# © <2016> <ToproERP hy>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from datetime import datetime
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError, Warning
import logging
import json
import re
import demjson
from datetime import datetime, timedelta
import re
_logger = logging.getLogger(__name__)
import html
class OrderStateChangeRule(models.Model):
_name = "order.state.change.rule"
_inherit = ['mail.thread']
_description = '提单状态变更规则'
# @api.constrains('email_subject', 'change_order_state')
# def check_change_order_state(self):
# if self.email_subject == 'DLV':
# if self.change_order_state != '已提货':
# raise ValidationError('邮件主题包含字段为DLV时,变更后提单状态必须是 已提货')
#
# name = fields.Char('变更规则名称', index=True, tracking=True)
# email_address = fields.Char('发件人邮箱', tracking=True)
# email_subject = fields.Selection([('DLV', 'DLV'), ('FFM', 'FFM'), ('RCF', 'RCF')], string='邮件主题包含字段', tracking=True)
# change_subject = fields.Selection([('提单', '提单'), ('配舱单', '配舱单')], string='变更主体', default='提单', tracking=True)
# order_state = fields.Selection(
# [('待提交', '待提交'), ('待审核', '待审核'), ('已订舱', '已订舱'), ('已发出', '已发出'), ('已收货', '已收货'), ('已安检', '已安检'), ('已入库', '已入库'),
# ('已组板', '已组板'), ('已发货', '已发货'),
# ('已落地', '已落地'), ('已卸机', '已卸机'), ('已提货', '已提货'), ('已完成', '已完成'), ('已取消', '已取消')], string='提单所属状态', index=True, tracking=True)
# change_order_state = fields.Selection(
# [('待提交', '待提交'), ('待审核', '待审核'), ('已订舱', '已订舱'), ('已发出', '已发出'), ('已收货', '已收货'), ('已安检', '已安检'), ('已入库', '已入库'),
# ('已组板', '已组板'), ('已发货', '已发货'),
# ('已落地', '已落地'), ('已提货', '已提货'), ('已完成', '已完成'), ('已取消', '已取消')], string='变更后提单状态', default='已提货', index=True,
# tracking=True)
# method = fields.Char('方法')
# regular_expression = fields.Char('正则表达式')
# active = fields.Boolean('有效性', default=True)
# 函数处理输出
def print_match(self, text):
# 正则表达式
pattern = r'([A-Za-z]+\d+)\s+(\d{3}-\d+)\s+(\d{4})?\.?(\d{1,2})\.(\d{1,2})\s+(\d{2}:\d{2})\s+\(([\+\-]?\d+)\)'
match = re.match(pattern, text)
if match:
return match
else:
return False
def find_text(self, email_body):
pattern = r'([A-Za-z]+\d+)\s+(\d{3}-\d+)\s+(\d{4})?[\.\。]?(\d{1,2})[\.\。](\d{1,2})\s+(\d{1,2}[::]\d{2})?\s*[\(\(]([\+\-]?\d+)[\)\)]'
data_re = re.compile(pattern)
data_arr = data_re.findall(email_body)
return data_arr
def fetch_mail_dlv(self, **kwargs):
email_body = kwargs['email_body']
year = kwargs['year']
# datas = demjson.decode(kwargs['datas'])
current_year = datetime.now().year
email_body = html.unescape(email_body)
text_arr = self.find_text(email_body)
# text_arr = email_body.split('\r\n') if '\r\n' in email_body else email_body.split('\n')
logging.info('data_arr: %s' % text_arr)
for text in text_arr:
try:
# text = html.unescape(text)
# match = self.print_match(text)
if text:
voyage_name = text[0] # SE901
order_no = text[1] # 436-10133970
year = text[2] # 11 或 2024
month = text[3] # 11
day = text[4] # 20
time = text[5].replace(':', ':') # 12:41
timezone_offset = int(text[6]) # +1 或 -8
# voyage_name = match.group(1) # SE901
# order_no = match.group(2) # 436-10133970
# year = match.group(3) # 11 或 2024
# month = match.group(4) # 11
# day = match.group(5) # 20
# time = match.group(6) # 12:41
# timezone_offset = int(match.group(7)) # +1 或 -8
# 如果没有提供年份,则使用当前年份
if not year: # 只给了月份和日,默认使用当前年份
year = str(current_year)
# 拼接日期时间字符串
date_str = f"{year}-{month}-{day} {time}"
# 转换为 datetime 对象
local_time = datetime.strptime(date_str, "%Y-%m-%d %H:%M")
# 调整时区
utc_time = local_time - timedelta(hours=timezone_offset)
sql = "select id from cc_bl where UPPER(REPLACE(REPLACE(REPLACE(bl_no, ' ', ''), '-', ''), '/', '')) = '{0}' " \
"and transport_tool_name='{1}' order by create_date desc limit 1".format(order_no.replace(' ', '').replace('-', '').replace('/', ''), voyage_name)
self._cr.execute(sql)
result = self._cr.fetchall()
print(result)
# bl_obj = self.env['cc.bl'].sudo().search([('bl_no', '=', order_no), ('transport_tool_name', '=', voyage_name)], order='create_date desc', limit=1)
bl_obj = self.env['cc.bl'].sudo().search([('id', '=', result[0][0])]) if result else False
if bl_obj and bl_obj.state != 'done':
redis_conn = self.env['common.common'].sudo().get_redis()
if redis_conn == 'no':
raise ValidationError('未连接redis')
else:
redis_conn.lpush('mail_push_package_list', json.dumps({'id': bl_obj.id, 'utc_time': utc_time.strftime("%Y-%m-%d %H:%M:%S")}))
except Exception as err:
logging.error('fetch_mail_dlv--error:%s' % str(err))
def calc_date(self, pick_date_text):
"""
获取月份
:param pick_date_text:
:return:
"""
month_abbr_arr = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
for mon in month_abbr_arr:
if mon != '':
month = mon.upper()
if month in pick_date_text:
return int(month_abbr_arr.index(mon))
return 0
# -*- coding: utf-8 -*-
from odoo.tools import config
import redis
import logging
import psycopg2
_logger = logging.getLogger(__name__)
def redis_connection():
# 连接redis
redis_config = config.misc.get("redis", {})
if redis_config:
try:
redis_options = dict(
host=redis_config.get('redis_host'),
port=redis_config.get('redis_port'),
password=redis_config.get('password'),
decode_responses=True,
db=redis_config.get('db'),
)
pool = redis.ConnectionPool(**redis_options)
r = redis.Redis(connection_pool=pool)
return r
except Exception as e:
_logger.error(u'连接redis失败,原因:%s' % str(e))
return 'no'
else:
_logger.error(u'conf文件中未配置redis连接信息')
return 'no'
# def yhj_psql_connection():
# # 连接yhj数据库
# yhj_config = config.misc.get("yhj", {})
# if yhj_config:
# try:
# db_ip = yhj_config.get('db_ip')
# db_port = yhj_config.get('db_port')
# database = yhj_config.get('db_name')
# password = yhj_config.get('db_password')
# username = yhj_config.get('db_user')
# psql_connection = psycopg2.connect(user=username, password=password, dbname=database, host=db_ip,
# port=db_port)
# # psql_cur = psql_connection.cursor()
# return psql_connection
# except Exception as e:
# _logger.error(u'连接yhj数据库失败,原因:%s' % str(e))
# return 'no'
# else:
# _logger.error(u'conf文件中未配置yhj数据库连接信息')
# return 'no'
# -*- coding: utf-8 -*-
# Part of SmartGo. See LICENSE file for full copyright and licensing details.
import logging
from odoo import api, fields, models, _
_logger = logging.getLogger(__name__)
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
before_min = fields.Integer('清关时间取值(早于清关结束)')
@api.model
def get_values(self):
"""
重载获取参数的方法,参数都存在系统参数中
:return:
"""
values = super(ResConfigSettings, self).get_values()
config = self.env['ir.config_parameter'].sudo()
before_min = config.get_param('before_min', default=10)
values.update(
before_min=before_min,
)
return values
def set_values(self):
super(ResConfigSettings, self).set_values()
ir_config = self.env['ir.config_parameter'].sudo()
ir_config.set_param("before_min", self.before_min or 10)
......@@ -56,3 +56,5 @@ access_cc_clearance_file_base.group_user,cc_clearance_file base.group_user,ccs_b
access_cc_clearance_file_base.group_erp_manager,cc_clearance_file base.group_erp_manager,ccs_base.model_cc_clearance_file,base.group_erp_manager,1,1,1,1
access_cc_clearance_file_ccs_base.group_clearance_of_customs_manager,cc_clearance_file ccs_base.group_clearance_of_customs_manager,ccs_base.model_cc_clearance_file,ccs_base.group_clearance_of_customs_manager,1,1,1,1
access_cc_clearance_file_ccs_base.group_clearance_of_customs_user,cc_clearance_file ccs_base.group_clearance_of_customs_user,ccs_base.model_cc_clearance_file,ccs_base.group_clearance_of_customs_user,1,0,0,0
order_state_change_rule_group_user,order_state_change_rule_group_user,ccs_base.model_order_state_change_rule,base.group_user,1,1,1,1
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="res_config_settings_view_form_auto_push" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.auto.push</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('app_settings_block')]/div" position="before">
<div>
<h2>自动推送配置</h2>
<div class="row mt16 o_settings_container" id="auto_push">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<div class="text-muted">
<label for="before_min"/>
<field name="before_min"/>
</div>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</data>
</odoo>
......@@ -115,13 +115,17 @@ class CcShipPackageSyncLog(models.Model):
# 添加一个新增日志的方法,传入小包ID,API客户,操作状态,操作备注,操作时间
@api.model
def create_sync_log(self, package_id, api_customer, process_code, operate_remark, operate_time):
return self.create({
vals = {
'package_id': package_id,
'api_customer': api_customer,
'process_code': process_code,
'operate_remark': operate_remark,
'operate_time': operate_time
})
}
if self._context.get('is_mail'):
public_user = self.env.ref('base.public_user')
vals['operate_user'] = public_user.id
return self.create(vals)
# 继承小包对象,并重载action_sync方法, 增加is_sync字段
......@@ -247,6 +251,7 @@ class CcBl(models.Model):
# 定义一个方法, 获取提单下的所有未同步的小包,并回传小包状态
def callback_track(self):
is_ok = True
for item in self:
ship_packages = self.env['cc.ship.package'].search([('bl_id', '=', item.id), ('is_sync', '=', False)])
# for package in ship_packages:
......@@ -279,6 +284,7 @@ class CcBl(models.Model):
self.env['ao.tt.api.log'].sudo().create_api_log(
package_order.tracking_no or '', '小包状态轨迹回传:' + error_msg, data, code, request_id,
source='推出')
is_ok = False
else:
# 回传成功
package_order.is_sync = True
......@@ -288,6 +294,7 @@ class CcBl(models.Model):
request_id = response_data['requestID']
self.env['ao.tt.api.log'].sudo().create_api_log(
package_order.tracking_no or '', '', data, 0, request_id, source='推出')
return is_ok
def deal_ship_package_state(self):
for item in self:
......
......@@ -150,10 +150,18 @@ class BatchInputShipPackageStatusWizard(models.TransientModel):
# if self.bl_id.state == 'draft' and self.bl_id.ship_package_ids.filtered(
# lambda line: line.state.tk_code == 'cb_imcustoms_start'):
# self.bl_id.ccing_func()
public_user = self.env.ref('base.public_user')
for bl_obj in bl_objs:
bl_obj.message_post(body=_('[%s]%sUpdate to[%s]%s') % (
self.current_status.tk_code or '', self.current_status.name or '', self.update_status.tk_code or '',
self.update_status.name or ''))
# print(self._context)
if self._context.get('is_mail'):
bl_obj.message_post(body=_('[%s]%sUpdate to[%s]%s') % (
self.current_status.tk_code or '', self.current_status.name or '', self.update_status.tk_code or '',
self.update_status.name or ''), author_id=public_user.id,
email_from=public_user.display_name)
else:
bl_obj.message_post(body=_('[%s]%sUpdate to[%s]%s') % (
self.current_status.tk_code or '', self.current_status.name or '', self.update_status.tk_code or '',
self.update_status.name or ''))
# 如果提单有小包变成了清关开始,提单状态变为清关中
if bl_obj.state == 'draft' and bl_obj.ship_package_ids.filtered(
lambda line: line.state.tk_code == 'cb_imcustoms_start'):
......
# coding=utf-8
# 本地
db_ip = "127.0.0.1"
db_port = "8888"
db_name = "hh_ccs_test"
db_user = "admin"
db_password = "admin"
redis_options = dict(
host='127.0.0.1',
port=6379,
# password='topodoo1314',
decode_responses=True,
db=0
)
# 测试
# db_ip = "121.199.167.133"
# db_port = "8369"
# db_name = "airorder0309"
# db_user = "admin"
# db_password = "123123"
#
# redis_options = dict(
# host='172.18.0.6',
# port=6379,
# # password='top123',
# decode_responses=True,
# db=3
# )
# product
# db_ip = "172.18.183.214"
# db_port = "9169"
# db_name = "air_order"
# db_user = "admin"
# db_password = "YHB1408ups"
#
# redis_options = dict(
# host='172.18.183.214',
# port=32768,
# password='top123',
# decode_responses=True,
# db=3
# )
# coding=utf-8
import json
import logging
import redis
import time
import requests
import odoorpc
from requests.adapters import HTTPAdapter
from datetime import datetime
import config
# 默认字符gbk
# logging.basicConfig(filename='./push_data_logger.log', level=logging.INFO)
# 设置文件字符为utf-8
logging.basicConfig(handlers=[logging.FileHandler('logs/mail_push.log', 'a', 'utf-8')],
format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO)
class Order_dispose(object):
def __init__(self):
# rpc连接
self.odoo_db = odoorpc.ODOO(config.db_ip, port=config.db_port)
self.odoo_db.login(config.db_name, config.db_user, config.db_password)
def order_data(self, data):
res_data = []
try:
data = json.loads(data)
logging.info('mail_push_data: %s', data)
bl_obj = self.odoo_db.env['cc.bl']
bl_record = bl_obj.browse(data['id'])
# utc_time = datetime.strptime(data['utc_time'], "%Y-%m-%d %H:%M:%S")
utc_time = data['utc_time']
bl_record.mail_auto_push(utc_time)
except Exception as ex:
logging.error('mail_auto_push error:%s' % str(ex))
return res_data
try:
pool = redis.ConnectionPool(**config.redis_options)
r = redis.Redis(connection_pool=pool)
logging.info(u'redis连接成功')
Order_dispose = Order_dispose()
while 1:
try:
result = r.brpop('mail_push_package_list', 0)
data1 = result[1]
response_data = Order_dispose.order_data(data1)
except Exception as e:
logging.error(e)
continue
except Exception as e:
logging.error("登录失败")
logging.error(e)
[program:mail_push_consumer_1]
process_name=%(program_name)s_%(process_num)02d ; 进程名称
directory = /mnt/extra-addons ; 程序的启动目录
command = /usr/bin/python3 /mnt/extra-addons/mail_push.py ; 启动命令
autostart = true ; 在 supervisord 启动的时候也自动启动
startsecs = 5 ; 启动 5 秒后没有异常退出,就当作已经正常启动了
autorestart = true ; 程序异常退出后自动重启
startretries = 3 ; 启动失败自动重试次数,默认是 3
user = root ; 用哪个用户启动
numprocs=1 ; 进程数
redirect_stderr = true ; 把 stderr 重定向到 stdout,默认 false
stdout_logfile_maxbytes = 20MB ; stdout 日志文件大小,默认 50MB
stdout_logfile_backups = 20 ; stdout 日志文件备份数
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile = /var/log/supervisor/mail_push.log
; supervisor config file
[unix_http_server]
file=/var/run/supervisor.sock ; (the path to the socket file)
chmod=0700 ; sockef file mode (default 0700)
[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP)
; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket
; The [include] section can just contain the "files" setting. This
; setting can list multiple files (separated by whitespace or
; newlines). It can also contain wildcards. The filenames are
; interpreted as relative to this file. Included files *cannot*
; include files themselves.
[inet_http_server]
port=9001
username=admin
password=admin
[include]
files = /mnt/extra-addons/supervisord_conf/conf.d/*.conf
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论