提交 132ed07a authored 作者: 伍姿英's avatar 伍姿英

Merge branch 'release/3.7.0'

from . import wizard
from . import models
from . import wizard
from . import controllers
......@@ -45,6 +45,7 @@
'views/cc_history_ship_package_view.xml',
'views/cc_history_package_sync_log_view.xml',
'views/history_tt_api_log.xml',
'views/res_partner_view.xml',
'views/menu_view.xml',
# 'views/cc_customers_declaration_order_view.xml',
'templates/login.xml',
......@@ -62,8 +63,10 @@
'web.assets_backend': [
'ccs_base/static/src/mixins/link_pallet.js',
'ccs_base/static/src/mixins/link_transfer_bl_no.js',
# 'ccs_base/static/src/mixins/create_temu_bl.js',
'ccs_base/static/src/views/big_package_list_controller.js',
'ccs_base/static/src/views/bl_list_controller.js',
# 'ccs_base/static/src/views/temu_bl_list_controller.js',
'ccs_base/static/src/views/list.xml',
],
},
......
......@@ -6,11 +6,11 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-31 02:13+0000\n"
"PO-Revision-Date: 2025-10-31 10:14+0800\n"
"POT-Creation-Date: 2025-12-04 01:28+0000\n"
"PO-Revision-Date: 2025-12-04 09:36+0800\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: zh_CN\n"
"Language: zh\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
......@@ -60,13 +60,6 @@ msgstr "%s %s 操作了异常信息,异常原因:%s,未发送%s邮件"
msgid "%s bill of loading cannot find release note file"
msgstr "%s 提单无法找到release note文件"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/wizard/batch_get_pod_info_wizard.py:0
#, python-format
msgid "%s bill of loading cannot get node operation time,please manually upload push tk"
msgstr "%s提单号没有获取到节点操作时间,请手动上传推送tk"
#. module: ccs_base
#: model:mail.template,body_html:ccs_base.email_template_exception_notification_en
msgid ""
......@@ -199,11 +192,22 @@ msgstr ""
" </span>"
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_create_and_get_pod_info_wizard_form
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_get_pod_info_wizard_form
msgid "<strong>Description:</strong>"
msgstr "<strong>说明:</strong>"
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_create_and_get_pod_info_wizard_form
msgid ""
"<strong>Get Last Mile POD:</strong>\n"
" Generate a last mile POD (Proof of Delivery) attachment "
"information, including\n"
" big package quantities and container numbers"
msgstr "<strong>获取尾程POD:</strong>生成一条尾程交接POD(待大包数量和箱号)的附件信息"
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_create_and_get_pod_info_wizard_form
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_get_pod_info_wizard_form
msgid ""
"<strong>Remove Specified Text:</strong>\n"
......@@ -298,6 +302,7 @@ msgstr ""
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_add_exception_info_wizard__action_type
#: model:ir.model.fields,field_description:ccs_base.field_batch_get_pod_info_wizard__action_type
#: model:ir.model.fields,field_description:ccs_base.field_export_bl_big_package_xlsx_wizard__action_type
msgid "Action Type"
msgstr "动作类型"
......@@ -567,6 +572,17 @@ msgstr "提单号和转单号重复"
msgid "B/L No is required"
msgstr "提单号必填"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_cc_bl__bl_type
#: model_terms:ir.ui.view,arch_db:ccs_base.form_cc_bl_view
msgid "B/L Type"
msgstr "提单类型"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_batch_get_pod_info_wizard__bl_numbers
msgid "BL Number"
msgstr "提单号"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_cc_bl__bl_attachment_ids
msgid "B\\L Attachments"
......@@ -594,6 +610,23 @@ msgstr "批量添加异常信息"
msgid "Batch Complete"
msgstr "批量完成"
#. module: ccs_base
#. odoo-javascript
#: code:addons/ccs_base/static/src/views/list.xml:0
#, python-format
msgid "Batch Create B/L"
msgstr "批量创建提单"
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_create_and_get_pod_info_wizard_form
msgid "Batch Create and Get POD Info"
msgstr "批量创建提单并获取尾程POD信息"
#. module: ccs_base
#: model:ir.actions.server,name:ccs_base.bl_download_pod_server_action
msgid "Batch Download POD"
msgstr "批量下载POD"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/models/cc_bill_loading.py:0
......@@ -708,7 +741,7 @@ msgid "Bill Of Loading Last Process Time"
msgstr "提单最后推送时间"
#. module: ccs_base
#: model:ir.actions.act_window,name:ccs_base.action_cc_bl model:ir.model,name:ccs_base.model_cc_bl
#: model:ir.model,name:ccs_base.model_cc_bl
#: model:ir.model.fields,field_description:ccs_base.field_batch_input_ship_package_status_wizard__bl_id
#: model:ir.model.fields,field_description:ccs_base.field_cc_big_package__bl_id
#: model:ir.model.fields,field_description:ccs_base.field_cc_clearance_file__bl_id
......@@ -720,7 +753,6 @@ msgstr "提单最后推送时间"
#: model:ir.model.fields,field_description:ccs_base.field_cc_ship_package__bl_id
#: model:ir.model.fields,field_description:ccs_base.field_update_bl_status_wizard__bl_id
#: model:ir.model.fields.selection,name:ccs_base.selection__cc_node__node_type__bl
#: model:ir.ui.menu,name:ccs_base.menu_cc_bl
#: model_terms:ir.ui.view,arch_db:ccs_base.calendar_cc_bl_view
#: model_terms:ir.ui.view,arch_db:ccs_base.form_cc_big_package_view
#: model_terms:ir.ui.view,arch_db:ccs_base.form_cc_bl_view
......@@ -739,7 +771,6 @@ msgstr "提单最后推送时间"
#: model_terms:ir.ui.view,arch_db:ccs_base.search_cc_progress_view
#: model_terms:ir.ui.view,arch_db:ccs_base.search_cc_ship_package_view
#: model_terms:ir.ui.view,arch_db:ccs_base.tree_cc_big_package_view
#: model_terms:ir.ui.view,arch_db:ccs_base.tree_cc_bl_view
#: model_terms:ir.ui.view,arch_db:ccs_base.tree_cc_clearance_file_view
#: model_terms:ir.ui.view,arch_db:ccs_base.tree_cc_history_ship_package_view
#: model_terms:ir.ui.view,arch_db:ccs_base.tree_cc_package_good_view
......@@ -1011,6 +1042,7 @@ msgstr "清关文件"
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.view_add_exception_info_wizard
#: model_terms:ir.ui.view,arch_db:ccs_base.view_associate_pallet_wizard
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_create_and_get_pod_info_wizard_form
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_get_pod_info_wizard_form
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_input_ship_package_wizard
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_update_transfer_bl_no_wizard
......@@ -1050,6 +1082,7 @@ msgstr "配置设置"
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.view_add_exception_info_wizard
#: model_terms:ir.ui.view,arch_db:ccs_base.view_associate_pallet_wizard
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_create_and_get_pod_info_wizard_form
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_get_pod_info_wizard_form
#: model_terms:ir.ui.view,arch_db:ccs_base.view_bl_done_wizard
msgid "Confirm"
......@@ -1095,6 +1128,14 @@ msgstr "快递logo"
msgid "Courier Name"
msgstr "快递名称"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#: code:addons/ccs_base/wizard/batch_get_pod_info_wizard.py:0
#, python-format
msgid "Create TEMU Bill of Loading"
msgstr "创建TEMU提单"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_add_exception_info_wizard__create_uid
#: model:ir.model.fields,field_description:ccs_base.field_associate_pallet_wizard__create_uid
......@@ -1198,6 +1239,7 @@ msgid "Current Status"
msgstr "当前状态"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_batch_get_pod_info_wizard__partner_id
#: model:ir.model.fields,field_description:ccs_base.field_cc_bl__customer_id
#: model_terms:ir.ui.view,arch_db:ccs_base.form_cc_bl_view
#: model_terms:ir.ui.view,arch_db:ccs_base.search_cc_bl_view
......@@ -1424,6 +1466,11 @@ msgstr "目的地港口代码"
msgid "English"
msgstr "英文"
#. module: ccs_base
#: model:ir.model.fields,help:ccs_base.field_batch_get_pod_info_wizard__bl_numbers
msgid "Enter multiple BL numbers, one per line"
msgstr "输入多个BL号,每行一个"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/wizard/batch_update_transfer_bl_no_wizard.py:0
......@@ -1618,6 +1665,11 @@ msgstr "毛重"
msgid "GROSS WEIGHT (KG)"
msgstr "毛重(公斤)"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_batch_get_pod_info_wizard__get_last_mile_pod
msgid "Get Last Mile POD"
msgstr "获取尾程POD"
#. module: ccs_base
#: model:ir.model.fields.selection,name:ccs_base.selection__cc_history_package_good__item_type__gift
#: model:ir.model.fields.selection,name:ccs_base.selection__cc_package_good__item_type__gift
......@@ -2733,6 +2785,12 @@ msgstr "摆放区域"
msgid "Placement Area must be unique !"
msgstr "摆放区域必须唯一!"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_res_partner__platform_type
#: model:ir.model.fields,field_description:ccs_base.field_res_users__platform_type
msgid "Platform Type"
msgstr "平台类型"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/wizard/batch_update_transfer_bl_no_wizard.py:0
......@@ -2748,6 +2806,25 @@ msgstr "请检查导入文件和内容是否正确,请根据模板文件导入
msgid "Please configure the default customs clearance status of the bill of loading node type first."
msgstr "请先配置默认的提单节点类型的清关节点"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#, python-format
msgid "Please configure the tail-end handover POD file of the bill of loading first."
msgstr "请先配置提单的尾部交接POD文件。"
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_create_and_get_pod_info_wizard_form
msgid "Please enter the bill of lading numbers. Multiple entries are allowed, one per line"
msgstr "请输入提单号。允许多次输入,每次一行"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#, python-format
msgid "Please select at least one bill of loading."
msgstr "请选择至少一个提单。"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/wizard/batch_input_ship_package_statu_wizard.py:0
......@@ -2763,6 +2840,7 @@ msgid "Please upload the B/L data file to be imported first!"
msgstr "请先上传需要更新的提单数据文件!"
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_create_and_get_pod_info_wizard_form
#: model_terms:ir.ui.view,arch_db:ccs_base.view_batch_get_pod_info_wizard_form
msgid "Preview"
msgstr "预览"
......@@ -3439,6 +3517,21 @@ msgstr "同步时间"
msgid "SyncTo.."
msgstr "同步"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/wizard/batch_get_pod_info_wizard.py:0
#: model:ir.actions.act_window,name:ccs_base.action_temu_bl
#: model:ir.model.fields.selection,name:ccs_base.selection__cc_bl__bl_type__temu
#: model:ir.ui.menu,name:ccs_base.menu_temu_cc_bl
#, python-format
msgid "TEMU Bill of Loading"
msgstr "TEMU提单"
#. module: ccs_base
#: model:ir.model.fields.selection,name:ccs_base.selection__res_partner__platform_type__temu
msgid "TEMU Platform"
msgstr "TEMU 平台"
#. module: ccs_base
#: model:ir.actions.act_window,name:ccs_base.action_history_tt_api_log
#: model:ir.ui.menu,name:ccs_base.menu_history_flight_tt_api_log
......@@ -3448,11 +3541,23 @@ msgstr "同步"
msgid "TIKTOK推送日志"
msgstr ""
#. module: ccs_base
#: model:ir.actions.act_window,name:ccs_base.action_cc_bl
#: model:ir.model.fields.selection,name:ccs_base.selection__cc_bl__bl_type__tk
#: model:ir.ui.menu,name:ccs_base.menu_cc_bl model_terms:ir.ui.view,arch_db:ccs_base.tree_cc_bl_view
msgid "TK Bill of Loading"
msgstr "TK提单"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_cc_history_ship_package__tk_code
#: model:ir.model.fields,help:ccs_base.field_cc_history_ship_package__tk_code
msgid "TK Code"
msgstr ""
msgstr "TK代码"
#. module: ccs_base
#: model:ir.model.fields.selection,name:ccs_base.selection__res_partner__platform_type__tk
msgid "TK Platform"
msgstr "TK 平台"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_cc_history_package_sync_log__process_code
......@@ -3959,6 +4064,11 @@ msgstr "重量单位"
msgid "Whether to export in Big packages"
msgstr "是否分大包导出"
#. module: ccs_base
#: model:ir.model.fields,help:ccs_base.field_batch_get_pod_info_wizard__get_last_mile_pod
msgid "Whether to get last mile POD information"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,help:ccs_base.field_batch_get_pod_info_wizard__remove_specified_text
msgid "Whether to remove specified text from PDF files"
......@@ -3967,7 +4077,7 @@ msgstr "是否涂抹PDF中的指定文字"
#. module: ccs_base
#: model:ir.model.fields,help:ccs_base.field_batch_get_pod_info_wizard__skip_ocr_direct_ai
msgid "Whether to skip OCR processing and directly use AI processing (for testing AI)"
msgstr ""
msgstr "是否跳过OCR处理直接使用AI处理(用于测试AI)"
#. module: ccs_base
#: model:ir.model.fields,help:ccs_base.field_batch_get_pod_info_wizard__sync_match_node
......@@ -4145,6 +4255,21 @@ msgstr ""
msgid "分组"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields.selection,name:ccs_base.selection__batch_get_pod_info_wizard__action_type__创建temu提单
msgid "创建temu提单"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,help:ccs_base.field_batch_get_pod_info_wizard__sync_successful_processed
msgid "勾选后显示同步尾程POD和同步匹配节点的字段以及确定按钮"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,help:ccs_base.field_batch_get_pod_info_wizard__generate_successful_processed
msgid "勾选后显示确定按钮"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_cc_bl__is_history
msgid "历史单据"
......@@ -4238,6 +4363,11 @@ msgstr ""
msgid "是否同步"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_batch_get_pod_info_wizard__sync_successful_processed
msgid "是否同步成功涂抹的提单"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_history_tt_api_log__success_bl
#: model_terms:ir.ui.view,arch_db:ccs_base.search_history_tt_api_log_view
......@@ -4265,6 +4395,11 @@ msgstr ""
msgid "清理向导临时附件"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_batch_get_pod_info_wizard__generate_successful_processed
msgid "生成成功涂抹的提单附件信息"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_history_tt_api_log__source
#: model_terms:ir.ui.view,arch_db:ccs_base.search_history_tt_api_log_view
......@@ -4282,6 +4417,11 @@ msgstr ""
msgid "自动获取尾程POD"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields.selection,name:ccs_base.selection__batch_get_pod_info_wizard__action_type__获取尾程pod信息
msgid "获取尾程POD信息"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_history_tt_api_log__request_id
msgid "请求id"
......
# 导入odoo
# 导入日志
import base64
import io
import json
import logging
import zipfile
from datetime import timedelta
import pytz
......@@ -636,6 +639,10 @@ class CcBL(models.Model):
}
redis_conn.lpush('history_data_list', json.dumps(vals))
# 新增类型 TK提单/TEMU提单
bl_type = fields.Selection([('tk', 'TK Bill of Loading'), ('temu', 'TEMU Bill of Loading')], string='B/L Type',
default='tk')
is_history = fields.Boolean('历史单据', default=False)
# 提单号
bl_no = fields.Char(string='B/L No', index=True)
......@@ -721,7 +728,8 @@ class CcBL(models.Model):
bl_objs = self.env['cc.bl'].search(
[('state', '=', 'ccing'), ('cc_attachment_ids.file_name', '=', fix_name)])
if len(bl_objs) > 0:
line_objs = bl_objs.cc_attachment_ids.filtered(lambda attach: not attach.file and attach.file_name == fix_name)
line_objs = bl_objs.cc_attachment_ids.filtered(
lambda attach: not attach.file and attach.file_name == fix_name)
if len(line_objs) > 0:
bl_objs = line_objs.mapped('bl_id')
logging.info('cron_get_pod bl_objs:%s,%s' % (len(bl_objs), ','.join([bl.bl_no for bl in bl_objs])))
......@@ -733,6 +741,52 @@ class CcBL(models.Model):
})
wizard_obj.confirm()
def _get_pod_files(self):
fix_name = '尾程交接POD(待大包数量和箱号)'
res = []
for bl in self:
files = self.env['cc.clearance.file'].sudo().search(
[('bl_id', '=', bl.id), ('file_name', '=', fix_name), ('file', '!=', False)])
files = files.filtered(lambda f: f.file not in (False, b'', ''))
if not files:
continue
total = len(files)
idx = 0
for f in files:
idx += 1
base = bl.bl_no or str(bl.id)
ext = 'pdf'
if f.attachment_name and '.' in f.attachment_name:
ext = f.attachment_name.split('.')[-1]
name = f"{base}.{ext}" if total == 1 else f"{base}-{idx}.{ext}"
res.append((name, f.file))
return res
def action_download_pod(self):
files = self._get_pod_files()
if not files:
return {'type': 'ir.actions.act_window_close'}
if len(self) == 1 and len(files) == 1:
name, data_b64 = files[0]
att = self.env['ir.attachment'].sudo().create(
{'name': name, 'datas': data_b64, 'res_model': 'cc.bl', 'res_id': self.id,
'mimetype': 'application/pdf'})
url = f"/web/content/ir.attachment/{att.id}/datas/{att.name}?download=true"
return {'type': 'ir.actions.act_url', 'url': url, 'target': 'self'}
buf = io.BytesIO()
with zipfile.ZipFile(buf, 'w', compression=zipfile.ZIP_DEFLATED) as zf:
for name, data_b64 in files:
zf.writestr(name, base64.b64decode(data_b64))
datas = base64.b64encode(buf.getvalue())
zip_name = 'POD.zip'
if len(self) == 1:
zip_name = f"{self.bl_no or self.id}.zip"
att = self.env['ir.attachment'].sudo().create(
{'name': zip_name, 'datas': datas, 'res_model': 'cc.bl', 'res_id': (self.id if len(self) == 1 else self[0].id),
'mimetype': 'application/zip'})
url = f"/web/content/ir.attachment/{att.id}/datas/{att.name}?download=true"
return {'type': 'ir.actions.act_url', 'url': url, 'target': 'self'}
# 增加一个can_cancel的方法,用于检查提单当前是否可以取消,返回True表示可以取消, False表示不可以取消,同时返回取消的原因
def check_cancel(self):
if self.is_cancel:
......@@ -774,8 +828,25 @@ class CcBL(models.Model):
bl.bl_ship_package_qty = len(ship_package_ids)
bl.bl_total_qty = len(bl.good_ids.filtered(lambda good: not good.is_cancel))
def get_default_partner(self):
"""
获取默认的客户
:return:
"""
print(self._context)
type = self._context.get('default_bl_type', 'tk')
partner_ids = self.env['res.partner'].get_type_partner(type)
if partner_ids:
return partner_ids[0]
return False
def get_customer_domain(self):
type = self._context.get('default_bl_type', 'tk')
return [('platform_type', '=', type)]
# 所属客户
customer_id = fields.Many2one('res.partner', string='Customer')
customer_id = fields.Many2one('res.partner', string='Customer', index=True, default=get_default_partner,
domain=lambda self: self.get_customer_domain())
# 大包明细
big_package_ids = fields.One2many('cc.big.package', 'bl_id', string='Big Packages')
......@@ -1173,10 +1244,40 @@ class CcBL(models.Model):
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'batch.get.pod.info.wizard',
'context': {'active_id': self.ids},
'context': {'active_id': self.ids, 'default_action_type': '获取尾程POD信息'},
'views': [[self.env.ref('ccs_base.view_batch_get_pod_info_wizard_form').id, "form"]],
'target': 'new',
}
def action_create_temu_bl(self):
"""
创建temu提单
"""
return {
'name': _('Create TEMU Bill of Loading'),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'batch.get.pod.info.wizard',
'views': [[self.env.ref('ccs_base.view_batch_create_and_get_pod_info_wizard_form').id, "form"]],
'context': {'active_id': self.ids, 'default_action_type': '创建temu提单'},
'target': 'new'
}
def action_batch_download_pod(self):
"""
将选中的提单以提单号命名下载尾程交接POD文件,若文件有多个则以提单-1/-2进行命名下载,若选择多个提单,则将所有文件打包成zip,zip命名则以POD进行命名
"""
# 检查是否有选中的提单
if not self:
raise UserError(_('Please select at least one bill of loading.'))
# 检查是否有尾程交接POD文件
fix_name = '尾程交接POD(待大包数量和箱号)'
has_files = self.env['cc.clearance.file'].search_count(
[('bl_id', 'in', self.ids), ('file_name', '=', fix_name), ('file', '!=', False)])
if not has_files:
raise UserError(_('Please configure the tail-end handover POD file of the bill of loading first.'))
return self.action_download_pod()
# 增加一个清关进度的业务对象,继承自models.Model, 用于管理业务数据.业务数据包括提单号、清关节点(业务对象)、进度日期、进度描述、更新人
class CcProgress(models.Model):
......
from odoo import models, fields, api, _
# 导入日志
import logging
from odoo.exceptions import UserError
from odoo import models, fields
# 获取日志
_logger = logging.getLogger(__name__)
......@@ -17,3 +15,18 @@ class ResPartner(models.Model):
is_customer = fields.Boolean(string='Is Customer', default=False)
# 是否是清关公司
is_clearance_company = fields.Boolean(string='Is Clearance Company', default=False)
# 新增类型:TK平台/TEMU平台。用英文表示
platform_type = fields.Selection([
('tk', 'TK Platform'),
('temu', 'TEMU Platform'),
], string='Platform Type', default='tk')
def get_type_partner(self, type='tk'):
"""
获取默认的TEMU平台客户
:return:
"""
partner_ids = self.env['res.partner'].search([('platform_type', '=', type)])
if partner_ids:
return partner_ids[0]
return False
......@@ -67,7 +67,7 @@ access_cc_big_package_ccs_base.group_clearance_of_customs_manager,cc_big_package
access_cc_clearance_file_base.group_user,cc_clearance_file base.group_user,ccs_base.model_cc_clearance_file,base.group_user,1,0,0,0
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
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,1,1,1
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
......
/** @odoo-module */
import {useService} from '@web/core/utils/hooks';
const {useRef, useEffect, useState} = owl;
export const TemuBlCreateMixin = {
setup() {
this._super();
this.actionService = useService('action');
this.notification = useService('notification');
this.orm = useService('orm');
this.http = useService('http');
this.fileInput = useRef('fileInput');
this.root = useRef("root");
},
async onCreateTemuBlClick() {
// 点击按钮弹出创建temu提单的向导
const records = this.model.root.selection;
const recordIds = records.map((a) => a.resId);
const action = await this.orm.call('cc.bl', 'action_create_temu_bl', [recordIds]);
this.actionService.doAction(action);
},
};
......@@ -23,4 +23,12 @@ export const LinkTransferBlNo = {
this.actionService.doAction(action);
},
async onCreateTemuBlClick() {
// 点击按钮弹出创建temu提单的向导
const records = this.model.root.selection;
const recordIds = records.map((a) => a.resId);
const action = await this.orm.call('cc.bl', 'action_create_temu_bl', [recordIds]);
this.actionService.doAction(action);
},
};
......@@ -13,7 +13,7 @@ const {onWillStart} = owl;
export class BigPackageListController extends ListController {
setup() {
super.setup();
console.log('----------引用成功')
console.log('----------big_package_list_controller引用成功')
this.orm = useService('orm');
this.actionService = useService('action');
this.rpc = useService("rpc");
......@@ -26,12 +26,17 @@ export class BigPackageListController extends ListController {
});
}
displayLink() {
console.log('ccs flag:' + this.isBigPackage && this.is_link)
// 是大包的对象以及有清关清理的权限才显示按钮
return this.isBigPackage && this.is_link;
}
displayCreateTemuBl (){
return false;
}
displayTransferBlNo() {
// 大包页面永远不显示“关联转单号”按钮
return false;
......
......@@ -13,16 +13,49 @@ const {onWillStart} = owl;
export class BlListController extends ListController {
setup() {
super.setup();
console.log('----------引用成功')
console.log('----------bl_list_controller引用成功')
this.orm = useService('orm');
this.actionService = useService('action');
this.rpc = useService("rpc");
this.user = useService("user");
this.isBl = this.model.rootParams.resModel === "cc.bl";
this.isTemuBl=false;
if (this.isBl) {
const d = this.props.domain;
// #输出d类型
console.log('d类型:' + typeof d)
console.log('d:' + d)
const containsTk = (x) => {
if (x === 'temu') {
return true;
}
if (Array.isArray(x)) {
for (const el of x) {
if (containsTk(el)) {
return true;
}
}
return false;
}
if (x && typeof x === 'object') {
for (const k in x) {
if (containsTk(x[k])) {
return true;
}
}
return false;
}
return false;
};
this.isTemuBl = !!containsTk(d);
}
console.log('ccs isBl:' + this.isBl)
console.log('ccs isTemuBl:' + this.isTemuBl)
onWillStart(async () => {
this.can_link_transfer_bl_no = await this.user.hasGroup("ccs_base.group_clearance_of_customs_user");
console.log('ccs can_link_transfer_bl_no:' + this.can_link_transfer_bl_no)
this.is_user = await this.user.hasGroup("ccs_base.group_clearance_of_customs_user");
console.log('ccs is_user:' + this.is_user)
});
}
......@@ -31,6 +64,12 @@ export class BlListController extends ListController {
return false;
}
displayCreateTemuBl() {
console.log('ccs flag:' + this.isTemuBl && this.is_user)
// 是temu提单的对象以及有清关用户的权限才显示按钮
return this.isTemuBl && this.is_user;
}
displayTransferBlNo() {
console.log('ccs flag:' + this.isBl && this.can_link_transfer_bl_no)
// 是提单的对象以及有清关用户的权限才显示按钮
......
......@@ -12,5 +12,10 @@
Link Transfer B/L No
</button>
</xpath>
<xpath expr="//button[hasclass('o_list_button_add')]" position="after">
<button t-if="displayCreateTemuBl()" type="button" class="d-none d-md-inline o_button_create_temu_bl btn btn-primary mx-1" t-on-click.prevent="onCreateTemuBlClick">
Batch Create B/L
</button>
</xpath>
</t>
</templates>
/** @odoo-module */
import {TemuBlCreateMixin} from '../mixins/create_temu_bl';
import {registry} from '@web/core/registry';
import {patch} from '@web/core/utils/patch';
import {useService} from '@web/core/utils/hooks';
import {listView} from "@web/views/list/list_view";
import {ListController} from "@web/views/list/list_controller";
const {onWillStart} = owl;
export class TemuBlListController extends ListController {
setup() {
super.setup();
console.log('----------temu_bl_list_controller引用成功')
this.orm = useService('orm');
this.actionService = useService('action');
this.rpc = useService("rpc");
this.user = useService("user");
this.isTemuBl = this.model.rootParams.resModel === "cc.bl";
console.log('ccs isTemuBl:' + this.isTemuBl)
onWillStart(async () => {
this.is_user = await this.user.hasGroup("ccs_base.group_clearance_of_customs_user");
console.log('ccs is_user:' + this.is_user)
});
}
displayCreateTemuBl() {
console.log('ccs flag:' + this.isTemuBl && this.is_user)
// 是temu提单的对象以及有清关用户的权限才显示按钮
return this.isTemuBl && this.is_user;
}
displayLink() {
return false;
}
displayTransferBlNo() {
// 大包页面永远不显示“关联转单号”按钮
return false;
}
}
patch(TemuBlListController.prototype, 'temu_bl_list_controller_create', TemuBlCreateMixin);
registry.category('views').add('cc_temu_bl_tree', {
...listView,
buttonTemplate: 'ccs_base.ListButtons',
Controller: TemuBlListController
});
\ No newline at end of file
......@@ -7,13 +7,14 @@
<field name="name">tree.cc.bl</field>
<field name="model">cc.bl</field>
<field name="arch" type="xml">
<tree string="Bill of Loading" decoration-warning="is_cancel==True" js_class="cc_bl_tree">
<tree string="TK Bill of Loading" decoration-warning="is_cancel==True" js_class="cc_bl_tree">
<field optional="show" name="state" string="Status" widget="badge" decoration-info="state=='draft'"
decoration-primary="state=='ccing'" decoration-success="state=='done'"/>
<field optional="show" name="customs_clearance_status" string="Customs Clearance Status"/>
<field optional="show" name="bl_no" string="Bill of Loading No."/>
<field optional="show" name="bl_date" string="B/L Date"/>
<field optional="show" name="last_mile_provider_ids" string="Last Mile Providers" widget="many2many_tags"/>
<field optional="show" name="last_mile_provider_ids" string="Last Mile Providers"
widget="many2many_tags"/>
<field optional="hide" name="transfer_bl_no" string="Transfer Bill of Loading No."/>
<field optional="show" name="customer_id" string="Customer"/>
<field optional="show" name="customs_bl_no" string="Customs Bill of Loading No."/>
......@@ -67,7 +68,8 @@
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<!-- 追回按钮 - 仅在已完成状态显示,仅清关员和清关经理可操作 -->
<button name="action_recall" type="object" string="Recall" attrs="{'invisible': [('state', '!=', 'done')]}"
<button name="action_recall" type="object" string="Recall"
attrs="{'invisible': [('state', '!=', 'done')]}"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<field name="state" widget="statusbar"/>
......@@ -136,7 +138,7 @@
<field name="is_history" invisible="1"/>
<label for="bl_no"/>
<h1>
<field name="bl_no" readonly="True"/>
<field name="bl_no" attrs="{'readonly': [('bl_type', '=', 'tk')]}"/>
</h1>
<group>
<group>
......@@ -156,6 +158,7 @@
<field name="end_port_code" string="End Port"/>
<field name="etd" string="ETD"/>
<field name="process_time" string="Customs Clearance Status Process Time"/>
<field name="bl_type" string="B/L Type" invisible="1"/>
</group>
<group>
<field name="billing_weight" string="Billing Weight"/>
......@@ -170,23 +173,13 @@
domain="[('is_clearance_company', '=', True)]"/>
<field name="cc_country_id" string="CC Country" requied="1"/>
<field name="cc_deadline" string="CC Deadline"/>
<!-- <field name="cc_progress_date" string="Current CC Progress Date"/>-->
<!-- <field name="cc_progress" string="Current CC Progress"/>-->
</group>
</group>
<notebook>
<!-- <page string="CC Progress">-->
<!-- <field name="cc_progress_ids" string="CC Progress"/>-->
<!-- </page>-->
<!-- <page string="Ship Packages">-->
<!-- <field name="ship_package_ids" string="Ship Packages"/>-->
<!-- </page>-->
<!-- <page string="Big Packages">-->
<!-- <field name="big_package_ids" string="Big Packages"/>-->
<!-- </page>-->
<page string="Attachments">
<group>
<field name="bl_attachment_ids" string="B/L Attachments" widget="many2many_attachment_preview"
<field name="bl_attachment_ids" string="B/L Attachments"
widget="many2many_attachment_preview"
readonly="1"/>
<field name="cc_attachment_ids" string="CC Attachments"/>
</group>
......@@ -332,82 +325,32 @@
</record>
<record model="ir.actions.act_window" id="action_cc_bl">
<field name="name">Bill of Loading</field>
<field name="name">TK Bill of Loading</field>
<field name="res_model">cc.bl</field>
<field name="view_mode">tree,form,pivot,graph,calendar</field>
<field name="domain">[]</field>
<field name="context">{'search_default_filter_state_not_finished':1}</field>
<field name="domain">[('bl_type','=','tk')]</field>
<field name="context">{'search_default_filter_state_not_finished':1,'default_bl_type':'tk'}</field>
<field name="view_id" ref="tree_cc_bl_view"/>
<field name="help" type="html">
<p>
</p>
</field>
</record>
<record model="ir.actions.act_window" id="action_temu_bl">
<field name="name">TEMU Bill of Loading</field>
<field name="res_model">cc.bl</field>
<field name="view_mode">tree,form,pivot,graph,calendar</field>
<field name="domain">[('bl_type','=','temu')]</field>
<field name="view_id" ref="tree_cc_bl_view"/>
<!-- <field name="view_id" ref="tree_temu_cc_bl_view"/> -->
<field name="context">{'search_default_filter_state_not_finished':1,'default_bl_type':'temu'}</field>
<field name="help" type="html">
<p>
</p>
</field>
</record>
<!--&lt;!&ndash; <record model="ir.ui.view" id="search_cc_bl_view">&ndash;&gt;-->
<!--&lt;!&ndash; <field name="name">search.cc.bl</field>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="model">cc.bl</field>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="arch" type="xml">&ndash;&gt;-->
<!--&lt;!&ndash; <search string="Bill of Loading">&ndash;&gt;-->
<!--&lt;!&ndash; <field name="bl_no" string="Fuzzy Search"&ndash;&gt;-->
<!--&lt;!&ndash; filter_domain="['|', ('bl_no', 'ilike', self), '|', ('cc_company_id.name', 'ilike', self),('customer_id.name', 'ilike', self)]"/>&ndash;&gt;-->
<!--&lt;!&ndash; <separator/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="bl_no" string="B/L No."/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="customer_id" string="Customer"/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="cc_country_id" string="CC Country"/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="cc_company_id" string="CC Company"/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="bl_date" string="B/L Date"/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="bl_total_amount" string="B/L Total Amount"/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="bl_total_qty" string="B/L Total Qty"/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="cc_progress" string="Current CC Progress"/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="cc_progress_date" string="Current CC Progress Date"/>&ndash;&gt;-->
<!--&lt;!&ndash; <field name="state" string="Status"/>&ndash;&gt;-->
<!--&lt;!&ndash; <separator/>&ndash;&gt;-->
<!--&lt;!&ndash; <filter name="filter_bl_date" string="B/L Date" date="bl_date"/>&ndash;&gt;-->
<!--&lt;!&ndash;&lt;!&ndash; # 增加一个过滤器, 用于显示今天到期的单据&ndash;&gt;&ndash;&gt;-->
<!--&lt;!&ndash; <filter name="filter_today_deadline" string="Today Deadline" domain="[('cc_deadline', '=', time.strftime('%Y-%m-%d'))]"/>&ndash;&gt;-->
<!--&lt;!&ndash;&lt;!&ndash; # 增加一个过滤器,用于显示已经到期的单据&ndash;&gt;&ndash;&gt;-->
<!--&lt;!&ndash; <filter name="filter_deadline" string="Deadline" domain="[('cc_deadline', '&lt;', time.strftime('%Y-%m-%d'))]"/>&ndash;&gt;-->
<!--&lt;!&ndash; <separator/>&ndash;&gt;-->
<!--&lt;!&ndash; <group expand="0" string="Group By">&ndash;&gt;-->
<!--&lt;!&ndash; <filter domain="[]" name="groupby_customer_id" string="Customer"&ndash;&gt;-->
<!--&lt;!&ndash; context="{'group_by': 'customer_id'}"/>&ndash;&gt;-->
<!--&lt;!&ndash; <filter domain="[]" name="groupby_cc_country_id" string="CC Country"&ndash;&gt;-->
<!--&lt;!&ndash; context="{'group_by': 'cc_country_id'}"/>&ndash;&gt;-->
<!--&lt;!&ndash; <filter domain="[]" name="groupby_cc_company_id" string="CC Company"&ndash;&gt;-->
<!--&lt;!&ndash; context="{'group_by': 'cc_company_id'}"/>&ndash;&gt;-->
<!--&lt;!&ndash; <filter domain="[]" name="groupby_state" string="Status" context="{'group_by': 'state'}"/>&ndash;&gt;-->
<!--&lt;!&ndash; </group>&ndash;&gt;-->
<!--&lt;!&ndash; <searchpanel>&ndash;&gt;-->
<!--&lt;!&ndash; <field icon="fa-users" name="state"/>&ndash;&gt;-->
<!--&lt;!&ndash; <field icon="fa-users" select="multi" name="cc_country_id" enable_counters="1"/>&ndash;&gt;-->
<!--&lt;!&ndash; </searchpanel>&ndash;&gt;-->
<!--&lt;!&ndash; </search>&ndash;&gt;-->
<!--&lt;!&ndash; </field>&ndash;&gt;-->
<!--&lt;!&ndash; </record>&ndash;&gt;-->
<!-- <record model="ir.actions.act_window" id="action_cc_bl">-->
<!-- <field name="name">Bill of Loading</field>-->
<!-- <field name="res_model">cc.bl</field>-->
<!-- <field name="view_mode">tree,form,pivot,graph</field>-->
<!-- <field name="domain">[]</field>-->
<!-- <field name="context">{-->
<!-- 'search_default_filter_today_deadline': 1,-->
<!-- }</field>-->
<!-- <field name="help" type="html">-->
<!-- <p class="o_view_nocontent_smiling_face">-->
<!-- [Bill of Loading] Not yet! Click the Create button in the top left corner and the sofa is yours!-->
<!-- </p>-->
<!-- <p>-->
<!-- </p>-->
<!-- </field>-->
<!-- </record>-->
<!-- 导出报关数据 <menuitem sequence="10" name="Bill of Loading" id="menu_cc_bl" action="action_cc_bl" web_icon="ccs_base,static/description/icon3.png"/>-->
<record id="export_order_big_package_xls_server" model="ir.actions.server">
......@@ -483,4 +426,19 @@
</field>
</record>
<!-- 下载POD -->
<record id="bl_download_pod_server_action" model="ir.actions.server">
<field name="name">Batch Download POD</field>
<field name="model_id" ref="model_cc_bl"/>
<field name="binding_model_id" ref="model_cc_bl"/>
<field name="state">code</field>
<field name="binding_view_types">list,form</field>
<field name="groups_id" eval="[(4, ref('ccs_base.group_clearance_of_customs_user'))]"/>
<field name="code">
if records:
action = records.action_batch_download_pod()
</field>
</record>
</odoo>
\ No newline at end of file
......@@ -14,22 +14,6 @@
<field name="web_icon">ccs_base,static/description/icon5.png</field>
</record>
<!-- # 增加一个"客户"action, 仅显示为客户的partner,显示模式为树,表单-->
<record model="ir.actions.act_window" id="action_cc_partner">
<field name="name">Customers</field>
<field name="res_model">res.partner</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('is_customer', '=', True)]</field>
<field name="context">{'default_is_customer': True}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
[Customers] Not yet! Click the Create button in the top left corner and the sofa is yours!
</p>
<p>
</p>
</field>
</record>
<!-- # 增加一个"客户"菜单, 与action_cc_partner关联-->
<menuitem sequence="10" name="Customers" id="menu_cc_partner" action="action_cc_partner"
parent="menu_ccs_base_main"/>
......@@ -47,23 +31,6 @@
<menuitem parent="menu_ccs_base_main" sequence="99" name="CC Node" id="menu_cc_node" action="action_cc_node"/>
<!-- # 增加一个"供应商"action, 仅显示为供应商的partner,显示模式为树,表单-->
<record model="ir.actions.act_window" id="action_cc_is_clearance_company">
<field name="name">Clearance Company</field>
<field name="res_model">res.partner</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('is_clearance_company', '=', True)]</field>
<field name="context">{'default_is_clearance_company': True}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
[Clearance Company] Not yet! Click the Create button in the top left corner and the sofa is yours!
</p>
<p>
</p>
</field>
</record>
<!-- # 增加一个"供应商"菜单, 与action_cc_supplier关联-->
<menuitem sequence="20" name="Clearance Company" id="menu_cc_clearance_company"
action="action_cc_is_clearance_company"
......@@ -86,7 +53,11 @@
action="action_history_tt_api_log"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<menuitem parent="" sequence="10" name="Bill of Loading" id="menu_cc_bl" action="action_cc_bl"
<menuitem parent="" sequence="10" name="TK Bill of Loading" id="menu_cc_bl" action="action_cc_bl"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<!-- TEMU提单 -->
<menuitem parent="" sequence="11" name="TEMU Bill of Loading" id="menu_temu_cc_bl" action="action_temu_bl"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<menuitem parent="" sequence="13" name="Big Package" id="menu_cc_big_package" action="action_cc_big_package"
......
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<record id="view_partner_form" model="ir.ui.view">
<field name="name">view_partner_form</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="platform_type" />
</xpath>
</field>
</record>
<record id="view_partner_tree" model="ir.ui.view">
<field name="name">view_partner_tree</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='email']" position="after">
<field name="platform_type" />
</xpath>
</field>
</record>
<record id="view_res_partner_filter" model="ir.ui.view">
<field name="name">view_res_partner_filter</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='group_country']" position="after">
<filter name="group_platform_type" context="{'group_by': 'platform_type'}"/>
</xpath>
</field>
</record>
<!-- # 增加一个"客户"action, 仅显示为客户的partner,显示模式为树,表单-->
<record model="ir.actions.act_window" id="action_cc_partner">
<field name="name">Customers</field>
<field name="res_model">res.partner</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('is_customer', '=', True)]</field>
<field name="context">{'default_is_customer': True}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
[Customers] Not yet! Click the Create button in the top left corner and the sofa is yours!
</p>
<p>
</p>
</field>
</record>
<!-- # 增加一个"供应商"action, 仅显示为供应商的partner,显示模式为树,表单-->
<record model="ir.actions.act_window" id="action_cc_is_clearance_company">
<field name="name">Clearance Company</field>
<field name="res_model">res.partner</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('is_clearance_company', '=', True)]</field>
<field name="context">{'default_is_clearance_company': True}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
[Clearance Company] Not yet! Click the Create button in the top left corner and the sofa is yours!
</p>
<p>
</p>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
......@@ -31,6 +31,37 @@ class BatchGetPodInfoWizard(models.TransientModel):
order_id = [self._context.get('active_id')]
return self.env['cc.bl'].browse(order_id)
action_type = fields.Selection([
('获取尾程POD信息', '获取尾程POD信息'),
('创建temu提单', '创建temu提单'),
], string='Action Type', default='获取尾程POD信息')
# ============temu提单 批量创建操作相关字段============
# 客户:默认TEMU平台客户,任一一个,可修改
partner_id = fields.Many2one(
'res.partner',
string='Customer', # 客户
default=lambda self: self.env['res.partner'].get_type_partner('temu'),
)
# 提单号:可输入多个,一行一个
bl_numbers = fields.Text(
string='BL Number', # 提单号
help='Enter multiple BL numbers, one per line' # 输入多个BL号,每行一个
)
# 获取尾程POD信息☑️(默认勾选)
get_last_mile_pod = fields.Boolean(
string='Get Last Mile POD', # 获取尾程POD信息
default=True,
help='Whether to get last mile POD information' # 是否获取尾程POD信息
)
generate_successful_processed = fields.Boolean(
string='生成成功涂抹的提单附件信息', # 生成成功涂抹的提单附件信息
default=False,
help='勾选后显示确定按钮'
)
# ===========提单获取尾程pod操作相关字段============
sync_last_mile_pod = fields.Boolean(
string='Sync Last Mile POD', # 同步尾程POD
default=False,
......@@ -62,11 +93,6 @@ class BatchGetPodInfoWizard(models.TransientModel):
help='勾选后显示同步尾程POD和同步匹配节点的字段以及确定按钮' # 勾选后显示同步尾程POD和同步匹配节点的字段以及确定按钮
)
# debug_mode = fields.Boolean(
# string='Debug Mode', # 调试模式
# default=False,
# help='Show red markers for deleted text positions' # 显示删除文字位置的红色标记
# )
show_error_message = fields.Text(
string='Show Error Message',
help='Show error message'
......@@ -76,19 +102,12 @@ class BatchGetPodInfoWizard(models.TransientModel):
pdf_filename = fields.Char(string='PDF文件名称')
processed_files_data = fields.Text(string='已处理的文件数据', help='存储已处理的文件信息(JSON格式)')
def action_preview(self):
"""
预览操作:获取PDF、处理涂抹、合并PDF并显示
"""
try:
bl_objs = self.get_order()
def _get_bill_numbers(self, bl_objs):
_logger.info(f"开始预览操作,提单数量: {len(bl_objs)}")
# 调用接口获取提单pdf文件
pdf_file_arr = self._get_pdf_file_arr()
pdf_file_arr = self._get_pdf_file_arr(bl_objs)
# 处理PDF文件,匹配提单对象
processed_files = self._match_bl_by_file_name(pdf_file_arr)
processed_files = self._match_bl_by_file_name(pdf_file_arr, bl_objs)
# 把没有匹配到文件的进行提示
error_bl = []
matched_bl_ids = [f['bl'].id for f in processed_files if f.get('bl')]
......@@ -100,7 +119,18 @@ class BatchGetPodInfoWizard(models.TransientModel):
if not self._context.get('is_skip_raise_error'):
self.show_error_message = _('%s bill of loading cannot find release note file') % (
', '.join([bl.bl_no for bl in error_bl]))
return processed_files
def action_preview(self):
"""
预览操作:获取PDF、处理涂抹、合并PDF并显示
"""
action_type = self.action_type
self.show_error_message = False
try:
bl_objs = self.get_bl_objs() # 获取提单
# 处理PDF文件,匹配提单对象
processed_files = self._get_bill_numbers(bl_objs)
# 如果启用了涂抹文字,进行处理
if self.remove_specified_text and processed_files:
processed_files = self._remove_specified_text(processed_files, debug_mode=False)
......@@ -109,15 +139,15 @@ class BatchGetPodInfoWizard(models.TransientModel):
successful_files = []
failed_files = []
for file_info in processed_files:
if file_info.get('bl'):
bl = file_info.get('bl')
if file_info.get('bl_no'):
bl_no = file_info.get('bl_no')
file_data = file_info.get('file_data', '')
# 检查处理是否失败(通过processing_failed标记或错误消息)
processing_failed = file_info.get('processing_failed', False)
has_error = False
if self.show_error_message:
error_msg = str(self.show_error_message)
if bl and bl.bl_no in error_msg:
if bl_no in error_msg:
has_error = True
# 如果处理失败或者有错误,则认为失败
......@@ -133,17 +163,20 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 如果所有文件都成功了(没有失败的文件),自动勾选"是否同步成功涂抹的提单"
if len(successful_files) == len(processed_files) and not failed_files and not self.show_error_message:
if action_type == '获取尾程POD信息':
self.sync_successful_processed = True
_logger.info(f"所有提单都处理成功,自动勾选同步选项")
else:
self.generate_successful_processed = True
else:
# 有失败的文件,保持未勾选状态,让用户决定
# 将成功处理的提单号追加到show_error_message中
if successful_files:
successful_bl_nos = []
for file_info in successful_files:
if file_info.get('bl'):
bl = file_info['bl']
successful_bl_nos.append(bl.bl_no)
if file_info.get('bl_no'):
bl_no = file_info['bl_no']
successful_bl_nos.append(bl_no)
# 在错误消息后面追加成功处理的提单号
existing_error = self.show_error_message or ''
successful_bl_nos_str = '、'.join(successful_bl_nos) if successful_bl_nos else ''
......@@ -151,7 +184,10 @@ class BatchGetPodInfoWizard(models.TransientModel):
self.show_error_message = f"{existing_error}{success_msg}"
_logger.info(
f"部分提单处理失败(成功:{len(successful_files)},失败:{len(failed_files)}),成功处理的提单号已显示")
if action_type == '获取尾程POD信息':
self.sync_successful_processed = False
else:
self.generate_successful_processed = False
# 序列化并存储处理后的文件数据(包括成功和失败的,但只有成功的才会合并PDF)
if processed_files:
......@@ -164,35 +200,42 @@ class BatchGetPodInfoWizard(models.TransientModel):
self.processed_files_data = self._serialize_processed_files(processed_files)
successful_bl_data = []
for file_info in processed_files:
if file_info.get('bl'):
bl = file_info['bl']
if file_info.get('bl_no'):
bl_no = file_info['bl_no']
successful_bl_data.append({
'bl_id': bl.id,
'bl_no': bl.bl_no
'bl_no': bl_no
})
# 没有涂抹文字,所有文件都成功,自动勾选
if action_type == '获取尾程POD信息':
self.sync_successful_processed = True
_logger.info(f"未启用涂抹文字,所有提单都成功,自动勾选同步选项")
else:
self.generate_successful_processed = True
else:
self.processed_files_data = ''
if action_type == '获取尾程POD信息':
self.sync_successful_processed = False
else:
self.generate_successful_processed = False
# 返回表单视图
return {
'type': 'ir.actions.act_window',
'name': _('Batch Get POD Info'),
'name': _('Batch Get POD Info') if action_type == '获取尾程POD信息' else _(
'Create TEMU Bill of Loading'),
'res_model': 'batch.get.pod.info.wizard',
'view_mode': 'form',
'res_id': self.id,
'target': 'new',
'context': {'active_id': bl_objs.ids}
'context': {'active_id': bl_objs.ids if bl_objs else False}
}
except Exception as e:
_logger.error(f"预览操作失败: {str(e)}")
self.show_error_message = _('预览操作失败: %s') % str(e)
return {
'type': 'ir.actions.act_window',
'name': _('Batch Get POD Info'),
'name': _('Batch Get POD Info') if action_type == '获取尾程POD信息' else _(
'Create TEMU Bill of Loading'),
'res_model': 'batch.get.pod.info.wizard',
'view_mode': 'form',
'res_id': self.id,
......@@ -207,9 +250,9 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 计算整个过程的耗时
start_time = time.time()
self.show_error_message = False
bl_objs = self.get_order()
_logger.info(f"%s提单开始执行批量获取POD信息操作" % len(bl_objs))
action_type = self.action_type
bl_objs = self.get_bl_objs()
if action_type == '获取尾程POD信息' or (action_type == '创建temu提单' and self.get_last_mile_pod):
# 优先使用已处理的文件数据(预览时已处理)
processed_files = None
if self.processed_files_data:
......@@ -228,23 +271,9 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 如果没有已处理的数据,则执行处理流程
if not processed_files:
# 调用接口获取提单pdf文件
pdf_file_arr = self._get_pdf_file_arr()
# 处理PDF文件,匹配提单对象
processed_files = self._match_bl_by_file_name(pdf_file_arr)
# 把没有匹配到文件的进行提示
error_bl = []
matched_bl_ids = [f['bl'].id for f in processed_files if f.get('bl')]
for bl in bl_objs:
if bl.id not in matched_bl_ids:
error_bl.append(bl)
if error_bl:
logging.info('%s个提单无法找到release note文件' % len(error_bl))
# 英文提示
if not self._context.get('is_skip_raise_error'):
self.show_error_message = _('%s bill of loading cannot find release note file') % (
', '.join([bl.bl_no for bl in error_bl]))
bl_objs = self.get_bl_objs() # 获取提单
processed_files = self._get_bill_numbers(bl_objs)
# 如果启用了涂抹文字,进行处理
if self.remove_specified_text and processed_files:
processed_files = self._remove_specified_text(processed_files, debug_mode=False)
......@@ -257,7 +286,8 @@ class BatchGetPodInfoWizard(models.TransientModel):
return {
'type': 'ir.actions.act_window',
'res_model': 'batch.get.pod.info.wizard',
'name': _('Batch Get POD Info'),
'name': _('Batch Get POD Info') if action_type == '获取尾程POD信息' else _(
'Create TEMU Bill of Loading'),
'view_mode': 'form',
'res_id': self.id,
'target': 'new',
......@@ -266,16 +296,19 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 检查是否有文字清除失败的错误
if self.show_error_message and any(
'仍存在目标文字' in str(self.show_error_message) or '未完全清除文字' in str(self.show_error_message)):
'仍存在目标文字' in str(self.show_error_message) or '未完全清除文字' in str(
self.show_error_message)):
_logger.error(f"检测到文字清除失败,停止处理: {self.show_error_message}")
return {
'type': 'ir.actions.act_window',
'res_model': 'batch.get.pod.info.wizard',
'name': _('Batch Get POD Info'),
'name': _('Batch Get POD Info') if action_type == '获取尾程POD信息' else _(
'Create TEMU Bill of Loading'),
'view_mode': 'form',
'res_id': self.id,
'target': 'new',
'context': {'default_show_error_message': self.show_error_message, 'active_id': bl_objs.ids}
'context': {'default_show_error_message': self.show_error_message,
'active_id': bl_objs.ids if bl_objs else False}
}
# 只处理成功涂抹的提单
......@@ -286,7 +319,6 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 检查是否有bl对象和有文件数据
if not file_info.get('bl'):
continue
bl = file_info['bl']
file_data = file_info.get('file_data', '')
# 检查处理是否失败(通过processing_failed标记)
processing_failed = file_info.get('processing_failed', False)
......@@ -298,11 +330,13 @@ class BatchGetPodInfoWizard(models.TransientModel):
_logger.warning("没有找到已处理的文件数据")
# 回写到附件信息
if successful_processed_files and (self.sync_last_mile_pod or self.sync_match_node):
if successful_processed_files and (
(self.sync_last_mile_pod or self.sync_match_node) or self.get_last_mile_pod):
# 回写PDF文件到清关文件
self._write_pdf_file(successful_processed_files)
# 再同步和回写
if action_type == '获取尾程POD信息':
if self.sync_last_mile_pod and successful_processed_files:
self._sync_last_mile_pod(successful_processed_files)
......@@ -327,13 +361,66 @@ class BatchGetPodInfoWizard(models.TransientModel):
return {
'type': 'ir.actions.act_window',
'res_model': 'batch.get.pod.info.wizard',
'name': _('Batch Get POD Info'),
'name': _('Batch Get POD Info') if action_type == '获取尾程POD信息' else _(
'Create TEMU Bill of Loading'),
'view_mode': 'form',
'res_id': self.id,
'target': 'new',
'context': {'default_show_error_message': self.show_error_message, 'active_id': bl_objs.ids}
'context': {'default_show_error_message': self.show_error_message,
'active_id': bl_objs.ids if bl_objs else False}
}
if action_type == '创建temu提单':
return {
'type': 'ir.actions.act_window',
'res_model': 'cc.bl',
'name': _('TEMU Bill of Loading'),
'view_mode': 'list,form',
'domain': [('bl_type', '=', 'temu')],
'context': {'default_bl_type': 'temu'},
'target': 'current',
}
def get_bl_objs(self):
if self.action_type == '获取尾程POD信息':
bl_objs = self.get_order()
else:
raw_lines = [i.strip() for i in self.bl_numbers.splitlines() if i.strip()]
normalized_list = [self.env['common.common'].sudo().process_match_str(i) for i in raw_lines]
norm_to_raw = {}
for raw, norm in zip(raw_lines, normalized_list):
if norm not in norm_to_raw:
norm_to_raw[norm] = raw
normalized = sorted(set(normalized_list))
exist_set = set()
if normalized:
self._cr.execute(
"select UPPER(REPLACE(REPLACE(REPLACE(bl_no,' ', ''), '-', ''), '/', '')) from cc_bl where UPPER(REPLACE(REPLACE(REPLACE(bl_no,' ', ''), '-', ''), '/', '')) in %s",
(tuple(normalized),))
exist_set.update([r[0] for r in self._cr.fetchall()])
self._cr.execute(
"select UPPER(REPLACE(REPLACE(REPLACE(transfer_bl_no,' ', ''), '-', ''), '/', '')) from cc_bl where transfer_bl_no is not null and UPPER(REPLACE(REPLACE(REPLACE(transfer_bl_no,' ', ''), '-', ''), '/', '')) in %s",
(tuple(normalized),))
exist_set.update([r[0] for r in self._cr.fetchall()])
non_exist_norm = [n for n in normalized if n not in exist_set]
create_vals = [{
'customer_id': self.partner_id.id,
'bl_type': 'temu',
'bl_no': norm_to_raw[n]
} for n in non_exist_norm]
new_bl = self.env['cc.bl'].create(create_vals) if create_vals else self.env['cc.bl']
ids = []
if normalized:
self._cr.execute(
"select id from cc_bl where UPPER(REPLACE(REPLACE(REPLACE(bl_no,' ', ''), '-', ''), '/', '')) in %s",
(tuple(normalized),))
ids += [r[0] for r in self._cr.fetchall()]
self._cr.execute(
"select id from cc_bl where transfer_bl_no is not null and UPPER(REPLACE(REPLACE(REPLACE(transfer_bl_no,' ', ''), '-', ''), '/', '')) in %s",
(tuple(normalized),))
ids += [r[0] for r in self._cr.fetchall()]
bl_objs = self.env['cc.bl'].browse(list(set(ids))) | new_bl
return bl_objs
def _validate_node_push_conditions(self, processed_files):
"""
验证节点推送条件
......@@ -343,14 +430,11 @@ class BatchGetPodInfoWizard(models.TransientModel):
return processed_files
# 写一个方法调接口获取提单pdf文件
def _get_pdf_file_arr(self):
def _get_pdf_file_arr(self, bl_objs):
"""
从API获取PDF文件
"""
# 获取当前选中的提单对象
bl_objs = self.get_order()
bill_numbers = [self.env['common.common'].sudo().process_match_str(bl.bl_no) for bl in bl_objs]
# 调用API获取PDF文件
api_url = self.env['ir.config_parameter'].sudo().get_param('last_mile_pod_api_url',
'http://172.104.52.150:7002')
......@@ -472,7 +556,7 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 过滤有效的PDF文件
valid_files = []
for file_info in processed_files:
if file_info.get('bl') and file_info.get('file_data'):
if file_info.get('bl_no') and file_info.get('file_data'):
valid_files.append(file_info)
if not valid_files:
......@@ -483,12 +567,13 @@ class BatchGetPodInfoWizard(models.TransientModel):
if len(valid_files) == 1:
file_info = valid_files[0]
bl = file_info['bl']
bl_no = bl.bl_no
file_data = file_info['file_data']
file_name = file_info.get('file_name', f"{bl.bl_no}.pdf")
file_name = file_info.get('file_name', f"{bl_no}.pdf")
# 生成文件名(包含提单号和日期)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
pdf_filename = f"POD文件_{bl.bl_no}_{timestamp}.pdf"
pdf_filename = f"POD文件_{bl_no}_{timestamp}.pdf"
# 直接保存到字段
self.write({
......@@ -515,11 +600,10 @@ class BatchGetPodInfoWizard(models.TransientModel):
for file_info in batch_files:
bl = file_info['bl']
bl_no = bl.bl_no
file_data = file_info['file_data']
bl_numbers.append(bl.bl_no)
bl_numbers.append(bl_no)
source_pdf = None
pdf_binary = None
try:
# 将base64数据转换为二进制
pdf_binary = base64.b64decode(file_data)
......@@ -530,17 +614,15 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 将源PDF的所有页面插入到合并的PDF中
merged_pdf.insert_pdf(source_pdf)
_logger.info(f"已添加提单 {bl.bl_no} 的PDF到合并文档({len(source_pdf)} 页)")
_logger.info(f"已添加提单 {bl_no} 的PDF到合并文档({len(source_pdf)} 页)")
except Exception as e:
_logger.error(f"合并提单 {bl.bl_no} 的PDF失败: {str(e)}")
_logger.error(f"合并提单 {bl_no} 的PDF失败: {str(e)}")
continue
finally:
# 立即释放资源
if source_pdf:
source_pdf.close()
source_pdf = None
pdf_binary = None
gc.collect() # 强制垃圾回收
# 每批处理完后,保存到临时文件并释放内存
......@@ -603,13 +685,12 @@ class BatchGetPodInfoWizard(models.TransientModel):
except Exception as e:
_logger.warning(f"删除临时文件失败: {str(e)}")
def _match_bl_by_file_name(self, pdf_file_arr):
def _match_bl_by_file_name(self, pdf_file_arr, bl_obj):
"""
Match BL by file name and return processed array # 根据文件名匹配提单并返回处理后的数组
:param pdf_file_arr: PDF文件数组 [{'bill_number':'', 'filename':'', 'file_data':''}]
:return: 处理后的数组 [{'bl': bl_obj, 'file_name': 'xxx.pdf', 'file_data': 'xxx', 'matched': True/False}]
"""
bl_obj = self.get_order() # 获取当前选中的提单对象
processed_files = []
for bl in bl_obj:
select_bl_no = self.env['common.common'].sudo().process_match_str(bl.bl_no)
......@@ -796,10 +877,10 @@ class BatchGetPodInfoWizard(models.TransientModel):
skip_ocr = self.skip_ocr_direct_ai # 是否跳过OCR直接使用AI
for file_info in processed_files:
if not file_info['bl']:
if not file_info['bl_no']:
updated_files.append(file_info)
continue
bl = file_info['bl']
bl_no = file_info['bl_no']
file_data = file_info['file_data']
processed_file_data = file_data # 默认使用原始数据
processing_failed = False # 标记处理是否失败
......@@ -810,15 +891,15 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 先提取文本用于后续同步节点功能(如果需要的话)
if 'ocr_texts' not in file_info:
file_info['ocr_texts'] = self._extract_text_from_pdf_with_ocr(pdf_binary, bl.bl_no)
file_info['ocr_texts'] = self._extract_text_from_pdf_with_ocr(pdf_binary, bl_no)
# 如果跳过OCR,直接使用AI处理
if skip_ocr:
_logger.info(f"提单 {bl.bl_no} 跳过OCR,直接使用AI处理")
_logger.info(f"提单 {bl_no} 跳过OCR,直接使用AI处理")
try:
ai_processed_pdf = self._process_pdf_with_ai_image_edit(
pdf_data=pdf_binary,
bl_no=bl.bl_no
bl_no=bl_no
)
if ai_processed_pdf:
processed_file_data = base64.b64encode(ai_processed_pdf).decode('utf-8')
......@@ -826,50 +907,50 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 检查是否还存在目标文字
final_check_pdf = base64.b64decode(processed_file_data)
text_still_exists, final_found_texts = self._check_target_texts_exist(final_check_pdf,
bl.bl_no)
bl_no)
if text_still_exists:
error_msg = f"提单 {bl.bl_no} 经过AI处理后仍存在目标文字: {', '.join(final_found_texts)},请取消该提单操作,手动处理"
error_msg = f"提单 {bl_no} 经过AI处理后仍存在目标文字: {', '.join(final_found_texts)},请取消该提单操作,手动处理"
_logger.error(error_msg)
error_messages.append(error_msg)
# 不更新文件数据,保持原始状态
processed_file_data = file_data
processing_failed = True
else:
_logger.info(f"提单 {bl.bl_no} AI处理成功,目标文字已清除")
_logger.info(f"提单 {bl_no} AI处理成功,目标文字已清除")
else:
error_msg = f"提单 {bl.bl_no} AI处理失败"
error_msg = f"提单 {bl_no} AI处理失败"
_logger.error(error_msg)
error_messages.append(error_msg)
processing_failed = True
except Exception as e:
_logger.error(f"提单 {bl.bl_no} AI处理异常: {str(e)}")
error_msg = f"提单 {bl.bl_no} AI处理异常: {str(e)}"
_logger.error(f"提单 {bl_no} AI处理异常: {str(e)}")
error_msg = f"提单 {bl_no} AI处理异常: {str(e)}"
error_messages.append(error_msg)
processing_failed = True
else:
# 原有逻辑:先用OCR处理,如果还存在则用AI处理
# 第一步:使用OCR方法处理PDF
_logger.info(f"提单 {bl.bl_no} 开始OCR处理")
_logger.info(f"提单 {bl_no} 开始OCR处理")
try:
processed_pdf = self._process_pdf_with_ocr(
pdf_data=pdf_binary,
bl_no=bl.bl_no,
bl_no=bl_no,
debug_mode=debug_mode
)
if processed_pdf:
processed_file_data = base64.b64encode(processed_pdf).decode('utf-8')
# 第二步:检查是否还存在目标文字
pdf_for_check = base64.b64decode(processed_file_data)
text_exists, found_texts = self._check_target_texts_exist(pdf_for_check, bl.bl_no)
text_exists, found_texts = self._check_target_texts_exist(pdf_for_check, bl_no)
logging.info(f"ocr处理之后的text_exists: {text_exists}")
if text_exists:
# 第三步:如果还存在,使用AI图片编辑处理
_logger.info(f"提单 {bl.bl_no} OCR处理后仍存在目标文字,使用AI图片编辑处理")
_logger.info(f"提单 {bl_no} OCR处理后仍存在目标文字,使用AI图片编辑处理")
try:
ai_processed_pdf = self._process_pdf_with_ai_image_edit(
pdf_data=pdf_for_check,
bl_no=bl.bl_no
bl_no=bl_no
)
if ai_processed_pdf:
processed_file_data = base64.b64encode(ai_processed_pdf).decode('utf-8')
......@@ -877,51 +958,51 @@ class BatchGetPodInfoWizard(models.TransientModel):
# 第四步:再次检查是否还存在目标文字
final_check_pdf = base64.b64decode(processed_file_data)
text_still_exists, final_found_texts = self._check_target_texts_exist(
final_check_pdf, bl.bl_no)
final_check_pdf, bl_no)
if text_still_exists:
# 第五步:如果仍然存在,记录错误信息并停止处理
error_msg = f"提单 {bl.bl_no} 经过系统处理后仍存在目标文字: {', '.join(final_found_texts)},请取消该提单操作,手动处理"
error_msg = f"提单 {bl_no} 经过系统处理后仍存在目标文字: {', '.join(final_found_texts)},请取消该提单操作,手动处理"
_logger.error(error_msg)
error_messages.append(error_msg)
# 不更新文件数据,保持原始状态
processed_file_data = file_data
processing_failed = True
else:
_logger.warning(f"提单 {bl.bl_no} AI处理失败,检查OCR处理结果")
_logger.warning(f"提单 {bl_no} AI处理失败,检查OCR处理结果")
# AI处理失败,检查OCR结果是否真的清除了目标文字
ocr_check_pdf = base64.b64decode(processed_file_data)
text_still_exists, ocr_found_texts = self._check_target_texts_exist(
ocr_check_pdf, bl.bl_no)
ocr_check_pdf, bl_no)
if text_still_exists:
error_msg = f"提单 {bl.bl_no} 经过系统处理后仍存在目标文字: {', '.join(ocr_found_texts)},请取消该提单操作,手动处理"
error_msg = f"提单 {bl_no} 经过系统处理后仍存在目标文字: {', '.join(ocr_found_texts)},请取消该提单操作,手动处理"
error_messages.append(error_msg)
# 不更新文件数据,保持原始状态
processed_file_data = file_data
processing_failed = True
else:
_logger.info(f"提单 {bl.bl_no} OCR处理成功,目标文字已清除")
_logger.info(f"提单 {bl_no} OCR处理成功,目标文字已清除")
except Exception as e:
_logger.error(f"提单 {bl.bl_no} AI处理异常: {str(e)}")
_logger.error(f"提单 {bl_no} AI处理异常: {str(e)}")
# AI处理失败,使用OCR结果,但需要检查
final_check_pdf = base64.b64decode(processed_file_data)
text_still_exists, final_found_texts = self._check_target_texts_exist(
final_check_pdf, bl.bl_no)
final_check_pdf, bl_no)
if text_still_exists:
error_msg = f"提单 {bl.bl_no} 经过系统处理后仍存在目标文字: {', '.join(final_found_texts)},请取消该提单操作,手动处理"
error_msg = f"提单 {bl_no} 经过系统处理后仍存在目标文字: {', '.join(final_found_texts)},请取消该提单操作,手动处理"
error_messages.append(error_msg)
# 不更新文件数据,保持原始状态
processed_file_data = file_data
processing_failed = True
else:
_logger.info(f"提单 {bl.bl_no} OCR处理成功,目标文字已清除")
_logger.info(f"提单 {bl_no} OCR处理成功,目标文字已清除")
else:
_logger.warning(f"提单 {bl.bl_no} OCR处理失败")
error_messages.append(f"提单 {bl.bl_no} OCR处理失败")
_logger.warning(f"提单 {bl_no} OCR处理失败")
error_messages.append(f"提单 {bl_no} OCR处理失败")
processing_failed = True
except Exception as e:
_logger.error(f"提单 {bl.bl_no} OCR处理异常: {str(e)}")
error_messages.append(f"提单 {bl.bl_no} OCR处理异常: {str(e)}")
_logger.error(f"提单 {bl_no} OCR处理异常: {str(e)}")
error_messages.append(f"提单 {bl_no} OCR处理异常: {str(e)}")
processing_failed = True
# 更新文件信息,使用处理后的PDF数据
......@@ -2468,8 +2549,6 @@ class BatchGetPodInfoWizard(models.TransientModel):
temp_attachments = self.env['ir.attachment'].sudo().browse(attachment_ids)
attachment_count = len(temp_attachments)
attachment_names = [att.name for att in temp_attachments]
_logger.info(f"找到 {attachment_count} 个{one_day_ago.strftime('%Y-%m-%d')}之前创建的临时附件,开始清理")
# 删除物理文件
......
......@@ -13,8 +13,8 @@
<group>
<!-- attrs="{'invisible': [('pdf_file', '!=', False)]}" -->
<field name="remove_specified_text" readonly="1" widget="boolean_toggle"/>
<field name="skip_ocr_direct_ai" readonly="0" widget="boolean_toggle"
attrs="{'invisible': [('pdf_file', '!=', False)]}"/>
<field name="skip_ocr_direct_ai" invisible="1" widget="boolean_toggle"/>
<field name="action_type" invisible="1"/>
</group>
<group attrs="{'invisible': ['|', ('pdf_file', '=', False), ('show_error_message', '=', False)]}">
<field name="sync_successful_processed" widget="boolean_toggle"/>
......@@ -71,6 +71,77 @@
</field>
</record>
<!-- Batch Create and Get POD Info Wizard Form View 批量创建并获取POD信息向导表单视图 -->
<record id="view_batch_create_and_get_pod_info_wizard_form" model="ir.ui.view">
<field name="name">batch.create.and.get.pod.info.wizard.form</field>
<field name="model">batch.get.pod.info.wizard</field>
<field name="arch" type="xml">
<form string="Batch Create and Get POD Info"> <!-- 批量创建并获取POD信息 -->
<sheet>
<group>
<group>
<field name="partner_id" options="{'no_create':True}"
domain="[('is_customer', '=', True), ('platform_type', '=', 'temu')]"
attrs="{'invisible': [('action_type', '!=', '创建temu提单')]}"/>
<!-- 请输入提单号,可输入多个,一行一个 -->
<field name="bl_numbers"
placeholder="Please enter the bill of lading numbers. Multiple entries are allowed, one per line"
attrs="{'required': [('action_type', '=', '创建temu提单')],'invisible': [('action_type', '!=', '创建temu提单')]}"/>
</group>
<group>
<field name="get_last_mile_pod"
attrs="{'invisible': [('action_type', '!=', '创建temu提单')]}"/>
<field name="remove_specified_text" readonly="1"
attrs="{'invisible': [('get_last_mile_pod', '=', False)]}"
widget="boolean_toggle"/>
<field name="skip_ocr_direct_ai" invisible="1" widget="boolean_toggle"/>
<field name="action_type" invisible="1"/>
</group>
</group>
<group attrs="{'invisible': ['|', ('pdf_file', '=', False), ('show_error_message', '=', False)]}">
<field name="generate_successful_processed" widget="boolean_toggle"/>
</group>
<div class="alert alert-info" role="alert">
<strong>Description:</strong> <!-- 说明: -->
<ul>
<li>
<strong>Get Last Mile POD:</strong>
Generate a last mile POD (Proof of Delivery) attachment information, including
big package quantities and container numbers
</li> <!-- 获取尾程POD:生成一条尾程交接POD(待大包数量和箱号)的附件信息 -->
<li attrs="{'invisible': [('get_last_mile_pod', '=', False)]}">
<strong>Remove Specified Text:</strong>
Remove specified text (AGN, UCLINK LOGISITICS LTD) from PDF files
</li> <!-- 涂抹指定文字:对PDF文件中的指定文字进行涂抹处理 -->
</ul>
</div>
<div class="alert alert-danger" role="alert"
attrs="{'invisible': [('show_error_message', '=', False)]}">
<field name="show_error_message"/>
</div>
<div>
<field name="pdf_file" filename="pdf_filename" widget="pdf_viewer" readonly="1"
attrs="{'invisible': [('pdf_file', '=', False)]}"/>
</div>
<footer>
<!-- 预览按钮:处理PDF并显示合并后的文件 -->
<button string="Preview" type="object" name="action_preview" class="btn-primary"
attrs="{'invisible': ['|',('pdf_file', '!=', False),('get_last_mile_pod','=',False)]}"/>
<!-- 确认按钮:使用已处理的文件数据进行回写 -->
<!-- 如果有失败的文件(show_error_message不为空),需要勾选generate_successful_processed才显示;如果全部成功,直接显示 -->
<button string="Confirm" type="object" name="confirm" class="btn-primary"
attrs="{'invisible': [('get_last_mile_pod','=',True)]}"/>
<button string="Confirm" type="object" name="confirm" class="btn-primary"
attrs="{'invisible': ['|', ('pdf_file', '=', False), '&amp;', ('show_error_message', '!=', False), ('generate_successful_processed', '=', False)]}"/>
<button string="Close" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
<!-- Batch Get POD Info Wizard Action 批量获取POD信息向导动作 -->
<record id="action_batch_get_pod_info_wizard" model="ir.actions.act_window">
<field name="name">Batch Get POD Info</field> <!-- 批量获取POD信息 -->
......
......@@ -30,8 +30,8 @@
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': "http://www.cybrosys.com",
'depends': ['base', 'sale_management'],
'data': ['views/sale_order_views.xml'],
'depends': ['base'],
'data': [],
'assets': {
'web.assets_backend': [
'many2many_attachment_preview/static/src/js/attachment_preview.js',
......
......@@ -19,4 +19,4 @@
# If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import sale_order
# from . import sale_order
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论