提交 71cce641 authored 作者: 伍姿英's avatar 伍姿英

Merge branch 'release/3.2.0'

......@@ -41,12 +41,12 @@ class CCLastMileProvider(models.Model):
matching_value = fields.Text(string='Matching Value') # 尾程服务商匹配值
placement_area = fields.Char('Placement Area') # 摆放区域,英文
def match_provider(self, provider_name):
def match_provider(self, provider_name,record_obj=None):
"""Check if the provider name exists in matching values and return the record."""
# 将输入的 provider_name 转换为小写
provider_name_lower = provider_name.lower()
# 查询所有匹配的记录
matching_records = self.sudo().search([])
matching_records = self.sudo().search([]) if not record_obj else record_obj
# 检查是否有记录的 matching_value 包含 provider_name(不区分大小写)
for record in matching_records:
if record.matching_value:
......
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
batch_input_ship_package_status_wizard_group_user,batch_input_ship_package_status_wizard_group_user,ccs_base.model_batch_input_ship_package_status_wizard,base.group_user,1,1,1,1
export_bl_big_package_xlsx_wizard_group_user,export_bl_big_package_xlsx_wizard_group_user,ccs_base.model_export_bl_big_package_xlsx_wizard,base.group_user,1,1,1,1
associate_pallet_wizard_group_user,associate_pallet_wizard_group_user,ccs_base.model_associate_pallet_wizard,base.group_user,1,1,1,1
associate_pallet_wizard_group_user,associate_pallet_wizard_group_user,model_associate_pallet_wizard,base.group_user,1,1,1,1
add_exception_info_wizard_group_user,add_exception_info_wizard_group_user,ccs_base.model_add_exception_info_wizard,base.group_user,1,1,1,1
update_bl_status_wizard_group_user,update_bl_status_wizard_group_user,ccs_base.model_update_bl_status_wizard,base.group_user,1,1,1,1
batch_update_transfer_bl_no_wizard_group_user,batch_update_transfer_bl_no_wizard_group_user,ccs_base.model_batch_update_transfer_bl_no_wizard,base.group_user,1,1,1,1
......
......@@ -12,6 +12,7 @@
<field name="ship_package_qty" string="Packages Qty"/>
<field name="goods_qty" string="Goods Qty"/>
<field name="is_cancel" string="Cancelled"/>
<field name="next_provider_name"/>
<field name="pallet_number"/>
<field name="pallet_usage_date"/>
<field name="tally_state" optional="show"/>
......@@ -164,9 +165,6 @@
</field>
</record>
<menuitem parent="" sequence="13" name="Big Package" id="menu_cc_big_package" action="action_cc_big_package"/>
<record id="big_package_add_exception_info_server_action" model="ir.actions.server">
<field name="name">Batch Add Package Exception Information</field>
<field name="model_id" ref="model_cc_big_package"/>
......@@ -179,16 +177,4 @@
action = records.action_package_exception_info()
</field>
</record>
<!-- <record id="action_cc_big_package_server" model="ir.actions.server">-->
<!-- <field name="name">全部航班</field>-->
<!-- <field name="model_id" ref="model_cc_big_package"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">-->
<!-- action = model.action_cc_big_package()-->
<!-- </field>-->
<!-- </record>-->
<!-- <menuitem id="menu_cc_big_package" name="Big Package" action="action_cc_big_package_server" sequence="13"/>-->
</odoo>
\ No newline at end of file
......@@ -320,8 +320,6 @@
</field>
</record>
<menuitem parent="" sequence="10" name="Bill of Loading" id="menu_cc_bl" action="action_cc_bl"/>
<!--&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;-->
......
......@@ -84,8 +84,4 @@
</p>
</field>
</record>
<!-- <menuitem parent="" sequence="99" name="Clearance File" id="menu_cc_clearance_file" action="action_cc_clearance_file"/>-->
</odoo>
\ No newline at end of file
......@@ -146,13 +146,15 @@
<field name="context">{}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
[Customers Declaration Order] Not yet! Click the Create button in the top left corner and the sofa is yours!
[Customers Declaration Order] Not yet! Click the Create button in the top left corner and the sofa is
yours!
</p>
<p>
</p>
</field>
</record>
<!--没用到-->
<menuitem sequence="20" name="CC Order" id="menu_cc_customers_declaration_order"
action="action_cc_customers_declaration_order" web_icon="ccs_base,static/description/icon1.png"/>
......
......@@ -45,7 +45,4 @@
<field name="res_model">cc.exception.info</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_exception_info" name="Package Exception Information" parent="menu_ccs_base_main" sequence="98"
action="action_exception_info"/>
</odoo>
\ No newline at end of file
......@@ -157,32 +157,4 @@
</p>
</field>
</record>
<!-- <record id="big_package_add_exception_info_server_action" model="ir.actions.server">-->
<!-- <field name="name">Batch Add Package Exception Information</field>-->
<!-- <field name="model_id" ref="model_cc_big_package"/>-->
<!-- <field name="binding_model_id" ref="model_cc_big_package"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="binding_view_types">list</field>-->
<!-- <field name="groups_id" eval="[(4, ref('ccs_base.group_clearance_of_customs_manager'))]"/>-->
<!-- <field name="code">-->
<!-- if records:-->
<!-- action = records.action_package_exception_info()-->
<!-- </field>-->
<!-- </record>-->
<!-- <record id="action_cc_big_package_server" model="ir.actions.server">-->
<!-- <field name="name">全部航班</field>-->
<!-- <field name="model_id" ref="model_cc_big_package"/>-->
<!-- <field name="state">code</field>-->
<!-- <field name="code">-->
<!-- action = model.action_cc_big_package()-->
<!-- </field>-->
<!-- </record>-->
<!-- <menuitem id="menu_cc_big_package" name="Big Package" action="action_cc_big_package_server" sequence="13"/>-->
</odoo>
\ No newline at end of file
......@@ -57,7 +57,4 @@
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_last_mile_provider" name="Last Mile Providers" parent="menu_ccs_base_main" sequence="95"
action="action_last_mile_provider"/>
</odoo>
\ No newline at end of file
......@@ -41,9 +41,4 @@
<field name="domain">[]</field>
<field name="context">{}</field>
</record>
<menuitem parent="menu_ccs_base_main" sequence="100" name="CC Node Exception Reason"
id="menu_cc_node_exception_reason"
action="action_cc_node_exception_reason"/>
</odoo>
\ No newline at end of file
......@@ -54,7 +54,4 @@
</p>
</field>
</record>
<menuitem parent="menu_ccs_base_main" sequence="99" name="CC Node" id="menu_cc_node" action="action_cc_node"/>
</odoo>
\ No newline at end of file
......@@ -184,6 +184,4 @@
</field>
</record>
<menuitem parent="" sequence="16" name="Package Goods" id="menu_cc_package_good" action="action_cc_package_good"/>
</odoo>
\ No newline at end of file
......@@ -335,8 +335,6 @@
</field>
</record>
<menuitem parent="" sequence="15" name="Ship Package" id="menu_cc_ship_package" action="action_cc_ship_package"/>
<record id="ship_package_add_exception_info_server_action" model="ir.actions.server">
<field name="name">Batch Add Package Exception Information</field>
......
......@@ -8,6 +8,7 @@
<record id="menu_ccs_base_main" model="ir.ui.menu">
<field name="name">Master Data</field>
<field name="sequence" eval="20"/>
<field name="groups_id" eval="[(4, ref('ccs_base.group_clearance_of_customs_manager'))]"/>
<field name="web_icon">ccs_base,static/description/icon5.png</field>
</record>
......@@ -31,6 +32,20 @@
<menuitem sequence="10" name="Customers" id="menu_cc_partner" action="action_cc_partner"
parent="menu_ccs_base_main"/>
<menuitem id="menu_exception_info" name="Package Exception Information" parent="menu_ccs_base_main"
sequence="98"
action="action_exception_info"/>
<menuitem id="menu_last_mile_provider" name="Last Mile Providers" parent="menu_ccs_base_main" sequence="95"
action="action_last_mile_provider"/>
<menuitem parent="menu_ccs_base_main" sequence="100" name="CC Node Exception Reason"
id="menu_cc_node_exception_reason"
action="action_cc_node_exception_reason"/>
<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>
......@@ -53,15 +68,34 @@
parent="menu_ccs_base_main"/>
<menuitem sequence="25" name="History Data" id="menu_cc_history_data"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"
/>
<menuitem parent="menu_cc_history_data" sequence="1" name="History Big Package" id="menu_cc_history_big_package" action="action_cc_history_big_package"/>
<menuitem parent="menu_cc_history_data" sequence="1" name="History Big Package" id="menu_cc_history_big_package"
action="action_cc_history_big_package"/>
<menuitem parent="menu_cc_history_data" sequence="5" name="History Package Goods"
id="menu_cc_history_package_good" action="action_cc_history_package_good"/>
<menuitem parent="menu_cc_history_data" sequence="3" name="History Ship Package"
id="menu_cc_history_ship_package" action="action_cc_history_ship_package"/>
<menuitem parent="menu_cc_history_data" id="menu_history_flight_tt_api_log" name="TIKTOK推送日志" sequence="7"
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"
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"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<menuitem parent="menu_cc_history_data" sequence="5" name="History Package Goods" id="menu_cc_history_package_good" action="action_cc_history_package_good"/>
<menuitem parent="" sequence="16" name="Package Goods" id="menu_cc_package_good" action="action_cc_package_good"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<menuitem parent="menu_cc_history_data" sequence="3" name="History Ship Package" id="menu_cc_history_ship_package" action="action_cc_history_ship_package"/>
<menuitem parent="" sequence="15" name="Ship Package" id="menu_cc_ship_package" action="action_cc_ship_package"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<menuitem parent="menu_cc_history_data" id="menu_history_flight_tt_api_log" name="TIKTOK推送日志" sequence="7" action="action_history_tt_api_log"/>
</data>
</odoo>
\ No newline at end of file
......@@ -64,14 +64,14 @@ class AssociatePalletWizard(models.TransientModel):
new_pallet_number = record.pallet_number # 修改的托盘号
old_usage_date = package.pallet_usage_date
# 同一提单,同一托盘号,使用日期必须一致
related_packages = package.bl_id.big_package_ids.filtered(
lambda p: p.pallet_number == new_pallet_number) # 查找对应提单下相同托盘号的所有大包
warning_package_arr = [related_package.big_package_no for related_package in related_packages if
related_package.pallet_usage_date != record.usage_date]
if warning_package_arr:
raise ValidationError(
_('Big Package No :%s ,The same bill of lading, same pallet number, and usage date must be consistent!') % (
'\n'.join(warning_package_arr))) # 大包号关联的同一提单,同一托盘号,使用日期必须一致
# related_packages = package.bl_id.big_package_ids.filtered(
# lambda p: p.pallet_number == new_pallet_number) # 查找对应提单下相同托盘号的所有大包
# warning_package_arr = [related_package.big_package_no for related_package in related_packages if
# related_package.pallet_usage_date != record.usage_date]
# if warning_package_arr:
# raise ValidationError(
# _('Big Package No :%s ,The same bill of lading, same pallet number, and usage date must be consistent!') % (
# '\n'.join(warning_package_arr))) # 大包号关联的同一提单,同一托盘号,使用日期必须一致
package.update_pallet_info(new_pallet_number, record.usage_date)
if old_pallet_number:
# %s %s更改了托盘号,由%s变更为%s,托盘使用日期%s变更为%s
......
......@@ -10,7 +10,7 @@
""",
'category': 'Clearance of customs',
'website': 'https://www.yizuo.ltd',
'depends': ['base_setup', 'ccs_base'],
'depends': ['base_setup', 'ccs_base', 'ccs_pallet'],
'data': [
'security/security.xml',
'security/ir.model.access.csv',
......@@ -33,6 +33,7 @@
'views/cc_bl_view.xml',
'views/pda_scan_record_views.xml',
'views/bl_patrol_views.xml',
'views/menu_view.xml',
],
'demo': [
......
......@@ -10,6 +10,7 @@ from . import ir_attachment
from . import http
from . import pda_scan_record
from . import bl_patrol
from . import cc_pallet
# -*- coding: utf-8 -*-
# 导入日志
import logging
from odoo import models
# 获取日志
_logger = logging.getLogger(__name__)
class CcPallet(models.Model):
# 模型名称
_inherit = 'cc.pallet'
# 模型描述
_description = 'Pallet'
def search_pallet_info(self):
"""搜索托盘信息"""
return {
'id': self.id, # 托盘id
'name': self.name, # 托盘号
'express_company_id': self.express_company_id.id, # 快递公司id
'express_company_name': self.express_company_id.name, # 快递公司名称
'usage_state': self.usage_state, # 使用状态 unused未使用 used已使用
'usage_date': str(self.usage_date) if self.usage_date else '', # 使用日期
'print_state': self.print_state, # 打印状态 unprinted未打印 printed已打印
'sorting_time': str(self.sorting_time) if self.sorting_time else '', # 托盘理货时间
'delivery_time': str(self.delivery_time) if self.delivery_time else '', # 托盘交货时间
'package_count': self.package_count, # 大包数量
'partner_id': self.partner_id.id, # 使用客户id
'partner_name': self.partner_id.name, # 使用客户名称
'delivery_plate_number': self.delivery_plate_number or '', # 托盘交付车牌号
}
......@@ -24,8 +24,10 @@ class PDAScanRecord(models.Model):
operation = fields.Selection([
('bill_tally', _('Bill Tally')), # 按提单理货
('tail_tally', _('Tail Tally')), # 按尾程理货
('pallet_tally', _('Pallet Tally')), # 按托盘理货
('bill_handover', _('Bill Handover')), # 按提单交货
('tail_handover', _('Tail Handover')) # 按尾程交货
('tail_handover', _('Tail Handover')), # 按尾程交货
('pallet_handover', _('Pallet Handover')) # 按托盘交货
], string=_('Operation'), required=True) # 操作
record_type = fields.Selection([
('tally', _('Tally')), # 理货
......
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_group_user_ao_tt_api,access_group_user_ao_tt_api,ccs_connect_tiktok.model_ao_tt_api,base.group_user,1,0,0,0
access_ao_tt_api_log,ao_tt_api_log,model_ao_tt_api_log,base.group_system,1,1,1,1
access_cc_ship_package_sync_log_base.group_user,cc_ship_package_sync_log base.group_user,ccs_connect_tiktok.model_cc_ship_package_sync_log,base.group_user,1,0,0,0
access_cc_ship_package_sync_log_base.group_erp_manager,cc_ship_package_sync_log base.group_erp_manager,ccs_connect_tiktok.model_cc_ship_package_sync_log,base.group_erp_manager,1,1,1,1
......@@ -10,7 +9,12 @@ access_cc_ship_package_sync_log_ccs_base.group_clearance_of_customs_user,cc_ship
access_cc_bl_sync_log_base.group_user,cc_bl_sync_log base.group_user,ccs_connect_tiktok.model_cc_bl_sync_log,base.group_user,1,0,0,0
access_cc_bl_sync_log_base.group_erp_manager,cc_bl_sync_log base.group_erp_manager,ccs_connect_tiktok.model_cc_bl_sync_log,base.group_erp_manager,1,1,1,1
access_cc_bl_sync_log_ccs_base.group_clearance_of_customs_manager,cc_bl_sync_log ccs_base.group_clearance_of_customs_manager,ccs_connect_tiktok.model_cc_bl_sync_log,ccs_base.group_clearance_of_customs_manager,1,0,0,0
access_cc_bl_sync_log_ccs_base.group_clearance_of_customs_user,cc_bl_sync_log ccs_base.group_clearance_of_customs_user,ccs_connect_tiktok.model_cc_bl_sync_log,ccs_base.group_clearance_of_customs_user,1,0,0,0
access_cc_bl_sync_log_ccs_base.group_clearance_of_customs_user,cc_bl_sync_log ccs_base.group_clearance_of_customs_user,model_cc_bl_sync_log,ccs_base.group_clearance_of_customs_user,1,0,0,0
access_ao_tt_api_log_user,access_ao_tt_api_log_user,model_ao_tt_api_log,base.group_user,1,0,0,0
access_ao_tt_api_log,ao_tt_api_log,model_ao_tt_api_log,base.group_system,1,1,1,1
access_pda_scan_record_user,pda.scan.record.user,model_pda_scan_record,base.group_user,1,1,1,0
access_pda_scan_record_manager,pda.scan.record.manager,model_pda_scan_record,base.group_system,1,1,1,1
......
......@@ -97,11 +97,5 @@
<field name="domain">[]</field>
<field name="context">{'search_default_last_30d':1}</field>
</record>
<menuitem
id="menu_ao_flight_tt_api_log"
name="TIKTOK推送日志"
sequence="21" action="action_ao_tt_api_log"/>
</data>
</odoo>
\ No newline at end of file
......@@ -97,10 +97,5 @@
</field>
</record>
<!-- 菜单项 -->
<menuitem id="menu_bl_patrol"
name="提单巡查"
action="action_bl_patrol"
sequence="22"/>
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<menuitem
id="menu_tt_api_log"
name="TIKTOK推送日志" parent=""
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"
sequence="21" action="action_ao_tt_api_log"/>
<!-- 菜单项 -->
<menuitem id="menu_bl_patrol"
name="提单巡查"
action="action_bl_patrol"
sequence="22"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<!-- 菜单项 -->
<menuitem id="menu_pda_scan_record"
name="PDA Scan Record"
action="action_pda_scan_record"
sequence="21"
groups="ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
</data>
</odoo>
\ No newline at end of file
......@@ -80,10 +80,4 @@
</p>
</field>
</record>
<!-- 菜单项 -->
<menuitem id="menu_pda_scan_record"
name="PDA Scan Record"
action="action_pda_scan_record"
sequence="21"/>
</odoo>
\ No newline at end of file
from . import models
from . import wizard
from . import reports
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': '清关托盘模块',
'version': '1.2',
'summary': '清关托盘模块',
'sequence': 10,
'description': """
清关托盘模块
1) 创建托盘和打印
""",
'category': 'Pallet Management',
'website': 'https://www.yizuo.ltd',
'depends': ['base', 'mail', 'web', 'ccs_base'],
'data': [
'security/pallet_security.xml',
'security/ir.model.access.csv',
'wizard/pallet_batch_wizard_view.xml',
'wizard/pallet_print_wizard_view.xml',
'wizard/associate_pallet_wizard_views.xml',
"reports/report_pallet_labe.xml",
'reports/pallet_label_report_templates.xml',
'views/cc_pallet_view.xml',
'views/menu_view.xml',
],
'installable': True,
'application': True,
'assets': {
'web.assets_backend': [
'ccs_pallet/static/src/mixins/batch_create_pallet.js',
'ccs_pallet/static/src/views/bl_list_pallet_controller.js',
'ccs_pallet/static/src/views/list.xml',
],
},
'license': 'AGPL-3',
}
差异被折叠。
from . import cc_pallet
from . import cc_big_package
# -*- coding: utf-8 -*-
# 导入日志
import logging
from odoo import models, fields, api, _
# 获取日志
_logger = logging.getLogger(__name__)
class CCBigPackage(models.Model):
# 模型名称
_inherit = 'cc.big.package'
# 模型描述
_description = 'Big Package'
pallet_id = fields.Many2one('cc.pallet', string='Pallet',index=True)
def action_link_pallet(self):
return {
'name': _('Link Pallet'),
'type': 'ir.actions.act_window',
'views': [[False, "form"]],
'res_model': 'associate.pallet.wizard',
'target': 'new',
'context': {},
}
def update_pallet_info(self, pallet_number, pallet_usage_date, pallet_id):
"""
修改托盘信息
:param pallet_number:
:param pallet_usage_date:
:param pallet_id:
:return:
"""
self.pallet_usage_date = pallet_usage_date
self.pallet_number = pallet_number
self.pallet_id = pallet_id
\ No newline at end of file
# -*- coding: utf-8 -*-
# 导入日志
import logging
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
# 获取日志
_logger = logging.getLogger(__name__)
class CcPallet(models.Model):
# 模型名称
_name = 'cc.pallet'
_inherit = ['mail.thread', 'mail.activity.mixin']
# 模型描述
_description = 'Pallet'
_order = 'create_date desc'
@api.model
def create(self, vals):
# 托盘号(年月+4位数,不能重复生成)
if not vals.get('name'):
vals['name'] = self.get_start_number()
return super(CcPallet, self).create(vals)
def get_start_number(self):
"""
获取当前年月+4位数,不能重复生成
"""
now = fields.Datetime.now()
year_month = now.strftime('%Y%m')
last_pallet = self.search([('name', 'like', year_month + '%')], order='name desc', limit=1)
if last_pallet and last_pallet.name:
last_number = int(last_pallet.name[-4:])
new_number = last_number + 1
else:
new_number = 1
return f"{year_month}{new_number:04d}"
@api.model
def get_partner_id(self):
"""
默认给值,随机选一个未存档的客户
"""
return self.env['res.partner'].search([('is_customer', '=', True), ('active', '=', True)], limit=1).id
# 计算字段:大包数量
@api.depends('package_ids')
def _compute_package_count(self):
for record in self:
record.package_count = len(record.package_ids)
# 计算字段:托盘理货时间和交货时间
@api.depends('package_ids', 'package_ids.tally_time', 'package_ids.delivery_time')
def _compute_pallet_times(self):
for pallet in self:
if pallet.package_ids:
# 获取所有关联大包的理货时间,取最晚的时间
sorting_times = pallet.package_ids.filtered('tally_time').mapped('tally_time')
if sorting_times:
pallet.sorting_time = max(sorting_times)
else:
pallet.sorting_time = False
# 获取所有关联大包的尾程交货时间,取最晚的时间
delivery_times = pallet.package_ids.filtered('delivery_time').mapped('delivery_time')
if delivery_times:
pallet.delivery_time = max(delivery_times)
else:
pallet.delivery_time = False
else:
pallet.sorting_time = False
pallet.delivery_time = False
# 托盘号(年月+4位数,不能重复生成)
name = fields.Char(string=_('Pallet Number'), copy=False, help=_('Pallet number format: YYYYMM + 4 digits'))
# 托盘归属快递
express_company_id = fields.Many2one('cc.last.mile.provider', string=_('Express Company'), index=True)
# 使用状态
usage_state = fields.Selection([('unused', _('Unused')), ('used', _('Used'))], string=_('Usage State'),
default='unused', index=True, tracking=True)
usage_date = fields.Date(string='Usage Date', index=True)
# 打印状态
print_state = fields.Selection([('unprinted', _('Unprinted')), ('printed', _('Printed'))], string=_('Print State'),
default='unprinted', index=True, tracking=True)
# 托盘理货时间(计算字段)
sorting_time = fields.Datetime(string=_('Sorting Time'), compute='_compute_pallet_times', store=True)
# 托盘交货时间(计算字段)
delivery_time = fields.Datetime(string=_('Delivery Time'), compute='_compute_pallet_times', store=True)
# 托盘装载大包
package_ids = fields.Many2many('cc.big.package', 'pallet_package_rel', string=_('Packages'))
# 大包数量
package_count = fields.Integer(string=_('Package Count'), compute='_compute_package_count', store=True)
# 使用客户
partner_id = fields.Many2one('res.partner', string=_('Customer'), default=get_partner_id,
domain=[('is_customer', '=', True)])
# 托盘交付车牌号
delivery_plate_number = fields.Char(string=_('Delivery Plate Number'))
def update_pallet_info(self, **kwargs):
"""更新托盘信息"""
if kwargs.get('delivery_plate_number', ''):
self.delivery_plate_number = kwargs['delivery_plate_number']
# 当大包关联到托盘时,自动更新使用状态
def update_usage_state(self, success_package, usage_date):
"""更新托盘使用状态"""
for pallet in self:
pallet.usage_state = 'used'
pallet.usage_date = usage_date
# 要把这个大包关联的托盘取消关联
for package in success_package:
package.pallet_id.package_ids = [(3, package.id, 0)] # 移除这个大包
# 关联大包到托盘
pallet.package_ids = [(4, package_id.id, 0) for package_id in success_package]
# 更新大包的托盘信息
for package in success_package:
old_pallet_number = package.pallet_number
new_pallet_number = pallet.name # 使用托盘的编号
old_usage_date = package.pallet_usage_date
# 同一提单,同一托盘号,使用日期必须一致
# related_packages = package.bl_id.big_package_ids.filtered(
# lambda p: p.pallet_number == new_pallet_number) # 查找对应提单下相同托盘号的所有大包
# warning_package_arr = [related_package.big_package_no for related_package in related_packages if
# str(related_package.pallet_usage_date) != usage_date]
# if warning_package_arr:
# raise ValidationError(
# _('Big Package No :%s ,The same bill of lading, same pallet number, and usage date must be consistent!') % (
# '\n'.join(warning_package_arr))) # 大包号关联的同一提单,同一托盘号,使用日期必须一致
# 更新大包的托盘信息
package.update_pallet_info(new_pallet_number, usage_date, pallet.id)
if old_pallet_number:
# %s %s更改了托盘号,由%s变更为%s,托盘使用日期%s变更为%s
body = _(
'%s at %s changed the pallet number from %s to %s, and the pallet usage date from %s to %s') % (
self.env.user.name, fields.Datetime.now(), old_pallet_number, new_pallet_number,
old_usage_date,
usage_date)
else:
# 某人某时关联了托盘xxx,托盘使用日期xxxx
body = _('%s at %s associated tray %s, with a tray usage date of %s') % (
self.env.user.name, fields.Datetime.now(), new_pallet_number, usage_date)
package.message_post(body=body)
# 记录托盘关联日志
body = _('%s at %s associated %d packages to pallet %s') % (
self.env.user.name, fields.Datetime.now(), len(success_package), pallet.name)
pallet.message_post(body=body)
def action_print_labels(self):
"""打印标签动作"""
return {
'type': 'ir.actions.act_window',
'name': _('Print Pallet Labels'),
'res_model': 'pallet.print.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_pallet_ids': [(6, 0, self.ids)],
'active_ids': self.ids,
},
}
def action_view_packages(self):
"""查看大包动作"""
return {
'type': 'ir.actions.act_window',
'name': _('Pallet Packages'),
'res_model': 'cc.big.package',
'view_mode': 'list,form',
'domain': [('pallet_id', '=', self.id)],
'context': {'default_pallet_id': self.id},
}
def action_batch_create(self):
"""批量创建托盘动作"""
return {
'name': _('Batch Create Pallets'),
'type': 'ir.actions.act_window',
'views': [[False, "form"]],
'res_model': 'pallet.batch.wizard',
'target': 'new',
'context': {},
}
def print_labels_success(self):
for pallet in self:
pallet.print_state = 'printed'
def unlink(self):
"""
已使用的托盘需要控制不能删除
"""
for pallet in self:
if pallet.usage_state == 'used':
raise ValidationError(_('Pallet %s has been used, cannot be deleted!') % pallet.name)
return super(CcPallet, self).unlink()
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import report_pallet
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_palletlabel">
<t t-call="web.html_container">
<t t-set="barcode_size" t-value="'width:80mm;height:30mm'"/>
<!-- 纵向的 -->
<!-- <t t-set="table_style" t-value="'width:100mm;height:150mm;'"/> -->
<!-- 横向的 -->
<t t-set="table_style" t-value="'width:150mm;height:70mm;'"/>
<t t-set="padding_page" t-value="'padding: 5mm'"/>
<t t-set="pallets" t-value="pallets"/>
<t t-foreach="pallets" t-as="pallet">
<t t-call="ccs_pallet.report_simple_pallet_barcode"/>
</t>
</t>
</template>
<!-- 托盘标签模板 -->
<template id="report_simple_pallet_barcode">
<div class="o_label_sheet o_label_dymo" t-att-style="padding_page">
<div class="o_label_full" t-att-style="table_style" style="display: flex; flex-direction: column; justify-content: space-between; align-items: center; text-align: center;">
<!-- 顶部标题 -->
<div style="flex: 0 0 auto; margin-bottom: 10mm; text-align: center;">
<div style="font-size: 24px; font-weight: bold; line-height: 1.2; font-family: Arial, sans-serif;">
<t t-esc="pallet.partner_id.name or 'TIKTOK'"/> / <t t-esc="pallet.express_company_id.abbreviation"/>
</div>
</div>
<!-- 中间条形码区域 -->
<div style="flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center;">
<t t-if="pallet.name">
<div t-out="pallet.name" style="padding:0; margin: 0 auto;" t-options="{'widget': 'barcode', 'quiet': 0, 'symbology': 'auto', 'img_style': barcode_size}"/>
</t>
</div>
<!-- 底部托盘号 -->
<div style="flex: 0 0 auto; margin-top: 10mm; text-align: center;">
<div style="font-size: 32px; font-weight: bold; line-height: 1.2; font-family: Arial, sans-serif;">
<span t-field="pallet.name"/>
</div>
</div>
</div>
</div>
<!-- <div class="o_label_sheet o_label_dymo" t-att-style="padding_page">
<div class="o_label_full" t-att-style="table_style" style="position: relative; box-sizing: border-box;">
<table style="width: 100%; height: 100%; border-collapse: collapse;">
<tr>
<td style="height: 20mm; text-align: center; vertical-align: middle; padding: 0; margin: 0;">
<div style="font-size: 24px; font-weight: bold; line-height: 1.2; font-family: Arial, sans-serif;">
<t t-esc="pallet.partner_id.name or 'TIKTOK'"/> / <t t-esc="pallet.express_company_id.abbreviation"/>
</div>
</td>
</tr>
<tr>
<td style="height: 60mm; text-align: center; vertical-align: middle; padding: 5mm; background-color: #f0f0f0; border: 1px solid #ddd;">
<t t-if="pallet.name">
<div style="text-align: center; font-size: 12px; color: #666;">
<div t-out="pallet.name"
t-options="{'widget': 'barcode', 'symbology': 'auto', 'img_style': barcode_size}"
style="margin: 10px 0;"/>
</div>
</t>
</td>
</tr>
<tr>
<td style="height: 30mm; text-align: center; vertical-align: middle; padding: 0; margin: 0;">
<div style="font-size: 32px; font-weight: bold; line-height: 1.2; font-family: Arial, sans-serif;">
<span t-field="pallet.name"/>
</div>
</td>
</tr>
</table>
</div>
</div> -->
</template>
</odoo>
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models, _
from odoo.exceptions import UserError
class ReportPallet(models.AbstractModel):
_name = 'report.ccs_pallet.report_palletlabel'
_description = 'Pallet report'
@api.model
def _get_report_values(self, docids, data=None):
# Overriding data values here since used also in _get_routes.
pallets = self.env['cc.pallet'].browse(docids)
return {
'pallets': pallets,
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- 托盘标签纸张格式 纵向的 10x15cm-->
<record id="paperformat_pallet_label" model="report.paperformat">
<field name="name">托盘标签 (10x15cm)</field>
<field name="default" eval="True"/>
<field name="format">custom</field>
<field name="orientation">Portrait</field>
<field name="margin_top">5</field>
<field name="margin_bottom">0</field>
<field name="margin_left">5</field>
<field name="margin_right">0</field>
<field name="header_line" eval="False"/>
<field name="header_spacing">0</field>
<field name="dpi">90</field>
<field name="page_width">100</field>
<field name="page_height">140</field>
</record>
<!-- 托盘标签纸张格式 横向的 10x15cm-->
<record id="paperformat_pallet_label_landscape" model="report.paperformat">
<field name="name">托盘标签 (10x15cm) 横向</field>
<field name="default" eval="True"/>
<field name="format">custom</field>
<field name="orientation">Landscape</field>
<field name="margin_top">10</field>
<field name="margin_bottom">0</field>
<field name="margin_left">7</field>
<field name="margin_right">8</field>
<field name="header_line" eval="False"/>
<field name="header_spacing">0</field>
<field name="dpi">90</field>
<field name="page_width">80</field>
<field name="page_height">140</field>
</record>
<!-- 托盘标签打印报告 -->
<record id="action_pallet_label_report" model="ir.actions.report">
<field name="name">托盘标签</field>
<field name="model">cc.pallet</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">ccs_pallet.report_palletlabel</field>
<field name="report_file">ccs_pallet.report_palletlabel</field>
<field name="paperformat_id" ref="paperformat_pallet_label_landscape"/>
<!-- <field name="binding_model_id" ref="model_cc_pallet"/> -->
<field name="binding_model_id" eval="False"/>
<field name="binding_type">report</field>
</record>
</odoo>
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
pallet_batch_wizard_group_user,pallet_batch_wizard_group_user,model_pallet_batch_wizard,base.group_user,1,1,1,1
pallet_print_wizard_group_user,pallet_print_wizard_group_user,model_pallet_print_wizard,base.group_user,1,1,1,1
cc_pallet_group_user,cc_pallet_group_user,model_cc_pallet,base.group_user,1,1,1,0
cc_pallet_group_system,cc_pallet_group_system,model_cc_pallet,base.group_system,1,1,1,1
cc_pallet_group_pallet_manager,cc_pallet_group_pallet_manager,model_cc_pallet,ccs_pallet.group_pallet_manager,1,1,1,1
cc_big_package_group_pallet_manager,cc_big_package_group_pallet_manager,model_cc_big_package,ccs_pallet.group_pallet_manager,1,1,0,0
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="0">
<record model="ir.module.category" id="ccs_pallet.module_category_pallet">
<field name="name">Pallet Information</field>
<field name="description">Pallet Information</field>
<field name="sequence">7</field>
</record>
<record id="group_pallet_manager" model="res.groups">
<field name="name">Pallet Manager</field>
<field name="category_id" ref="ccs_pallet.module_category_pallet"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
</data>
</odoo>
/** @odoo-module */
import {useService} from '@web/core/utils/hooks';
const {useRef, useEffect, useState} = owl;
export const BatchCreatePallet = {
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 onBatchCreatePalletClick() {
// 点击按钮弹出批量创建托盘的向导
const records = this.model.root.selection;
const recordIds = records.map((a) => a.resId);
const action = await this.orm.call('cc.pallet', 'action_batch_create', [recordIds]);
this.actionService.doAction(action);
},
};
/** @odoo-module */
import {BatchCreatePallet} from '../mixins/batch_create_pallet';
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 BlListPalletController extends ListController {
setup() {
super.setup();
console.log('----------引用成功')
this.orm = useService('orm');
this.actionService = useService('action');
this.rpc = useService("rpc");
this.user = useService("user");
this.isPallet = this.model.rootParams.resModel === "cc.pallet";
console.log('ccs isPallet:' + this.isPallet)
onWillStart(async () => {
this.can_batch_create_pallet = await this.user.hasGroup("ccs_pallet.group_pallet_manager");
console.log('ccs can_batch_create_pallet:' + this.can_batch_create_pallet)
});
}
displayLink() {
// 提单页面永远不显示“关联托盘”按钮
return false;
}
displayBatchCreatePallet() {
console.log('ccs flag:' + this.isPallet && this.can_batch_create_pallet)
// 是提单的对象以及有清关用户的权限才显示按钮
return this.isPallet && this.can_batch_create_pallet;
}
}
patch(BlListPalletController.prototype, 'batch_create_pallet', BatchCreatePallet);
registry.category('views').add('cc_pallet_tree', {
...listView,
buttonTemplate: 'ccs_pallet.ListButtons',
Controller: BlListPalletController
});
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="ccs_pallet.ListButtons" t-inherit="web.ListView.Buttons" t-inherit-mode="primary" owl="1">
<xpath expr="//button[hasclass('o_list_button_add')]" position="after">
<button t-if="displayBatchCreatePallet()" type="button" class="d-none d-md-inline o_button_batch_create_pallet btn btn-primary mx-1" t-on-click.prevent="onBatchCreatePalletClick">
Batch Create Pallet
</button>
</xpath>
</t>
</templates>
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record model="ir.ui.view" id="tree_cc_big_package_view">
<field name="name">tree.cc.big.package</field>
<field name="model">cc.big.package</field>
<field name="inherit_id" ref="ccs_base.tree_cc_big_package_view"/>
<field name="arch" type="xml">
<tree position="attributes">
<attribute name="js_class">cc_big_package_tree</attribute>
</tree>
</field>
</record>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- 托盘管理表单视图 -->
<record id="view_cc_pallet_form" model="ir.ui.view">
<field name="name">cc.pallet.form</field>
<field name="model">cc.pallet</field>
<field name="arch" type="xml">
<form string="Pallet Management">
<header>
<button name="action_print_labels" string="Print Labels" type="object" class="btn-primary"
icon="fa-print"/>
<field name="usage_state" widget="statusbar"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button name="action_view_packages" type="object" class="oe_stat_button" icon="fa-cubes">
<field name="package_count" widget="statinfo" string="Packages"/>
</button>
</div>
<div class="oe_title">
<h1>
<field name="name" readonly="1"/>
</h1>
</div>
<group>
<group string="Basic Information">
<field name="express_company_id" required="1" options="{'no_create': True, 'no_quick_create': True}"/>
<field name="partner_id" options="{'no_create': True, 'no_quick_create': True}"/>
<field name="delivery_plate_number"/>
<field name="create_uid" readonly="1" string="Create By"/>
<field name="create_date" readonly="1" string="Create Date"/>
</group>
<group string="Status Information">
<field name="print_state" readonly="1"/>
<field name="usage_date" readonly="1"/>
<field name="sorting_time" readonly="1"/>
<field name="delivery_time" readonly="1"/>
</group>
</group>
<notebook>
<page string="Package Information" name="packages">
<field name="package_ids" readonly="1"/>
</page>
</notebook>
</sheet>
<chatter/>
</form>
</field>
</record>
<!-- 托盘管理列表视图 -->
<record id="view_cc_pallet_list" model="ir.ui.view">
<field name="name">cc.pallet.list</field>
<field name="model">cc.pallet</field>
<field name="arch" type="xml">
<tree string="Pallet Management" js_class="cc_pallet_tree">
<field name="name"/>
<field name="express_company_id"/>
<field name="usage_state" decoration-success="usage_state == 'unused'"
decoration-warning="usage_state == 'used'"/>
<field name="print_state" decoration-info="print_state == 'unprinted'"
decoration-success="print_state == 'printed'"/>
<field name="sorting_time"/>
<field name="delivery_time"/>
<field name="package_count"/>
<field name="usage_date"/>
<field name="delivery_plate_number"/>
<field name="create_uid" string="Create By"/>
<field name="create_date" string="Create Date"/>
</tree>
</field>
</record>
<!-- 托盘管理搜索视图 -->
<record id="view_cc_pallet_search" model="ir.ui.view">
<field name="name">cc.pallet.search</field>
<field name="model">cc.pallet</field>
<field name="arch" type="xml">
<search string="Pallet Search">
<field name="name" filter_domain="[('name', 'ilike', self)]"/>
<field name="express_company_id"/>
<field name="partner_id"/>
<field name="delivery_plate_number"/>
<separator/>
<filter name="filter_unused" string="Unused" domain="[('usage_state', '=', 'unused')]"/>
<filter name="filter_used" string="Used" domain="[('usage_state', '=', 'used')]"/>
<filter name="filter_unprinted" string="Unprinted" domain="[('print_state', '=', 'unprinted')]"/>
<filter name="filter_printed" string="Printed" domain="[('print_state', '=', 'printed')]"/>
<separator/>
<group expand="0" string="Group By">
<filter name="group_by_express" string="Express Company"
context="{'group_by': 'express_company_id'}"/>
<filter name="group_by_print_state" string="Print State" context="{'group_by': 'print_state'}"/>
<filter name="group_by_usage_state" string="Usage State" context="{'group_by': 'usage_state'}"/>
</group>
</search>
</field>
</record>
<!-- 托盘管理动作 -->
<record id="action_cc_pallet" model="ir.actions.act_window">
<field name="name">Pallet Management</field>
<field name="res_model">cc.pallet</field>
<field name="view_mode">tree,form</field>
<field name="context">{}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create Pallet
</p>
<p>
Pallet management system for managing pallets in the warehouse, including pallet number generation,
status tracking and label printing.
</p>
</field>
</record>
<!-- 增加server action,批量打印标签 -->
<record id="action_print_labels_pallet_server" model="ir.actions.server">
<field name="name">Print Labels</field>
<field name="groups_id" eval="[(4, ref('ccs_pallet.group_pallet_manager'))]"/>
<field name="model_id" ref="model_cc_pallet"/>
<field name="binding_model_id" ref="model_cc_pallet"/>
<field name="binding_view_types">list</field>
<field name="state">code</field>
<field name="code">
if records:
action = records.action_print_labels()
</field>
</record>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<!-- 菜单项 -->
<menuitem id="menu_cc_pallet_root" name="Pallet Management" sequence="18"
groups="ccs_pallet.group_pallet_manager,ccs_base.group_clearance_of_customs_user,ccs_base.group_clearance_of_customs_manager"/>
<menuitem id="menu_cc_pallet"
name="Pallet"
parent="menu_cc_pallet_root"
action="action_cc_pallet"
sequence="10"/>
</data>
</odoo>
\ No newline at end of file
# -*- coding: utf-8 -*-
from . import pallet_batch_wizard
from . import pallet_print_wizard
from . import associate_pallet_wizard
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, _
from odoo.exceptions import ValidationError
class AssociatePalletWizard(models.TransientModel):
_inherit = 'associate.pallet.wizard'
_description = 'Associate Pallet Wizard'
# 字段定义
pallet_id = fields.Many2one('cc.pallet', string='Pallet', index=True)
def confirm(self):
for record in self:
if not record.pallet_id:
raise ValidationError(_('Please select a pallet!')) # 请选择托盘!
if record.usage_date > fields.Date.today():
raise ValidationError(_('The usage date cannot be later than the current date!')) # 使用日期不能大于当前日期!
# 处理大包号
big_package_ids = record.big_package_numbers.splitlines()
success_package = []
fail_package = []
for package_number in big_package_ids:
package = self.env['cc.big.package'].search([('big_package_no', '=', package_number)], limit=1)
if package:
success_package.append(package)
else:
fail_package.append(package_number)
if fail_package:
raise ValidationError(_('%s The package does not exist, please check the input information!') % (
'\n'.join(fail_package))) # 不存在该大包,请检查输入信息
if success_package:
#所有的大包的下一级服务商必须和托盘的下一级服务商一致
error_package = []
for package in success_package:
provider = self.env['cc.last.mile.provider'].sudo().with_context({'lang': self.env.user.lang}).match_provider(
package.next_provider_name,record_obj=record.pallet_id.express_company_id)
if not provider:
error_package.append(package.big_package_no)
if error_package:
raise ValidationError(_('The last mile carrier of package 【%s】 does not match the last mile carrier of the pallet. Please check and retry!') % (
'、'.join(error_package)))#大包号XXXXXX的尾程快递与托盘归属的尾程快递不一致
# 更新托盘的使用状态(理货时间和交货时间会自动通过计算字段更新)
record.pallet_id.update_usage_state(success_package, record.usage_date)
<odoo>
<record id="view_associate_pallet_wizard" model="ir.ui.view">
<field name="name">associate.pallet.wizard.form</field>
<field name="model">associate.pallet.wizard</field>
<field name="inherit_id" ref="ccs_base.view_associate_pallet_wizard"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='pallet_number']" position="after">
<field name="pallet_id" required="1" options="{'no_create': True, 'no_quick_create': True}"/>
</xpath>
<field name="pallet_number" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
</odoo>
\ No newline at end of file
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
class PalletBatchWizard(models.TransientModel):
_name = 'pallet.batch.wizard'
_description = 'Batch Create Pallet Wizard'
# 创建数量必须大于0,且不能超过1000
@api.constrains('quantity')
def _check_quantity(self):
"""Validate create quantity"""
if self.quantity <= 0:
raise ValidationError(_('Create quantity must be greater than 0'))
if self.quantity > 1000:
raise ValidationError(_('Cannot create more than 1000 pallets at once'))
# 托盘归属快递
express_company_id = fields.Many2one('cc.last.mile.provider', string=_('Express Company'), index=True)
# 创建数量
quantity = fields.Integer(string=_('Create Quantity'), default=1)
# 起始托盘号
start_number = fields.Char(string=_('Pallet Start Number'),
default=lambda self: self.env['cc.pallet'].get_start_number())
# 使用客户
partner_id = fields.Many2one('res.partner', string=_('Customer'), domain=[('is_customer', '=', True)],
default=lambda self: self.env['cc.pallet'].get_partner_id())
# 确认创建托盘
def action_confirm(self):
"""确认创建托盘"""
# 检查起始托盘号是否被占用
if self.start_number:
existing_pallet = self.env['cc.pallet'].search([('name', '=', self.start_number)])
if existing_pallet:
raise UserError(_('Start number has been occupied, please close the window and recreate'))
# 创建托盘记录
pallets = []
now = fields.Datetime.now()
year_month = now.strftime('%Y%m')
# 获取起始托盘号
if self.start_number:
start_num = int(self.start_number[-4:])
else:
start_num = 1
for i in range(self.quantity):
pallet_name = f"{year_month}{start_num + i:04d}"
# 检查每个托盘号是否已存在
existing_pallet = self.env['cc.pallet'].search([('name', '=', pallet_name)])
if existing_pallet:
raise UserError(_('Pallet number %s already exists, please check system data') % pallet_name)
pallet_vals = {
'name': pallet_name,
'express_company_id': self.express_company_id.id,
'partner_id': self.partner_id.id if self.partner_id else False,
}
pallet = self.env['cc.pallet'].create(pallet_vals)
pallets.append(pallet)
# 返回创建结果
return {
'type': 'ir.actions.act_window',
'name': _('Batch Create Pallet Result'),
'res_model': 'cc.pallet',
'view_mode': 'list,form',
'domain': [('id', 'in', [p.id for p in pallets])],
'context': {'create': False},
}
# 确认创建托盘并打印
def action_confirm_and_print(self):
"""Confirm create pallets and print"""
# 先创建托盘
result = self.action_confirm()
# 获取创建的托盘
pallets = self.env['cc.pallet'].search([
('id', 'in', result['domain'][0][2])
])
# 修改为已打印
pallets.print_labels_success()
return self._generate_print_report(pallets) # 直接返回打印 不关闭向导
# 获取系统参数中的本地域名
web_base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url', 'http://localhost:8069')
# 生成打印URL
report_url = f"{web_base_url}/report/pdf/ccs_pallet.action_pallet_label_report/{','.join(map(str, pallets.ids))}"
# 使用客户端动作处理打印和关闭向导 关闭后托盘列表空白
# return {
# 'type': 'ir.actions.client',
# 'tag': 'print_and_close',
# 'params': {
# 'report_url': report_url
# }
# }
# 在新窗口中打开打印 服务器不支持
import webbrowser
webbrowser.open_new_tab(report_url)
return {'type': 'ir.actions.act_window_close'}
# 生成打印报告
def _generate_print_report(self, pallets):
"""Generate print report"""
return self.env.ref('ccs_pallet.action_pallet_label_report').report_action(pallets)
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- 批量创建托盘向导表单视图 -->
<record id="view_pallet_batch_wizard_form" model="ir.ui.view">
<field name="name">pallet.batch.wizard.form</field>
<field name="model">pallet.batch.wizard</field>
<field name="arch" type="xml">
<form string="Batch Create Pallets">
<sheet>
<group>
<group>
<field name="express_company_id" required="1"/>
<field name="start_number" readonly="1"/>
<field name="quantity" required="1"/>
<field name="partner_id"/>
</group>
<group></group>
</group>
</sheet>
<footer>
<button name="action_confirm" string="Confirm" type="object" class="btn-primary"/>
<button name="action_confirm_and_print" string="Confirm and Print" type="object" class="btn-success"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- 批量创建托盘动作 -->
<record id="action_cc_pallet_batch_create" model="ir.actions.act_window">
<field name="name">Batch Create Pallets</field>
<field name="res_model">pallet.batch.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{}</field>
</record>
</odoo>
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class PalletPrintWizard(models.TransientModel):
_name = 'pallet.print.wizard'
_description = 'Pallet Print Wizard'
@api.depends('pallet_ids')
def _compute_pallet_count(self):
"""计算托盘数量"""
for record in self:
record.pallet_count = len(record.pallet_ids)
pallet_ids = fields.Many2many('cc.pallet',string=_('Pallets'))
pallet_count = fields.Integer(string=_('Pallet Count'),compute='_compute_pallet_count',store=True)
def action_print(self):
"""执行打印"""
if not self.pallet_ids:
raise UserError(_('Please select pallets to print'))
# 更新打印状态为已打印
self.pallet_ids.print_labels_success()
# 生成打印报告
return self._generate_print_report()
def _generate_print_report(self):
"""生成打印报告"""
return self.env.ref('ccs_pallet.action_pallet_label_report').report_action(self.pallet_ids)
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- 托盘打印向导表单视图 -->
<record id="view_pallet_print_wizard_form" model="ir.ui.view">
<field name="name">pallet.print.wizard.form</field>
<field name="model">pallet.print.wizard</field>
<field name="arch" type="xml">
<form string="Pallet Print">
<sheet>
<div class="oe_title">
<h1>Pallet Label Print</h1>
</div>
<group>
<field name="pallet_count" readonly="1"/>
</group>
<field name="pallet_ids" widget="many2many_tags" readonly="1"/>
</sheet>
<footer>
<button name="action_print" string="Confirm Print" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- 托盘打印向导动作 -->
<record id="action_pallet_print_wizard" model="ir.actions.act_window">
<field name="name">Pallet Print</field>
<field name="res_model">pallet.print.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{}</field>
</record>
</odoo>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论