提交 1b8d84e6 authored 作者: 贺阳's avatar 贺阳

托盘功能开发和关联托盘的修改

上级 727366d3
......@@ -21,7 +21,6 @@
'wizard/update_bl_status_wizard.xml',
'wizard/export_bl_big_package_xlsx_wizard.xml',
'wizard/batch_update_transfer_bl_no_wizard_view.xml',
'wizard/associate_pallet_wizard_views.xml',
'wizard/add_exception_info_wizard_views.xml',
'wizard/email_template.xml',
'data/data.xml',
......@@ -58,9 +57,7 @@
'ccs_base/static/css/base.scss',
],
'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/views/big_package_list_controller.js',
'ccs_base/static/src/views/bl_list_controller.js',
'ccs_base/static/src/views/list.xml',
],
......
......@@ -67,16 +67,6 @@ class CcBigPackage(models.Model):
exception_info_ids = fields.Many2many('cc.exception.info', 'bigpackage_exception_info_rel',
string='Exception Information')
def update_pallet_info(self, pallet_number, pallet_usage_date):
"""
修改托盘信息
:param pallet_number:
:param pallet_usage_date:
:return:
"""
self.pallet_usage_date = pallet_usage_date
self.pallet_number = pallet_number
def update_exception_info(self, exception_info_ids, is_send=False, email_language='zh_CN'):
"""
大包回写异常原因,发送邮件
......@@ -110,16 +100,6 @@ class CcBigPackage(models.Model):
'domain': [('bl_line_id', 'in', self.ship_package_ids.ids), ('is_cancel', '=', False)],
}
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 action_cc_big_package(self):
"""
菜单 大包
......
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
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
......
......@@ -26,10 +26,10 @@ export class BlListController extends ListController {
});
}
displayLink() {
// 提单页面永远不显示“关联托盘”按钮
return false;
}
// displayLink() {
// // 提单页面永远不显示“关联托盘”按钮
// return false;
// }
displayTransferBlNo() {
console.log('ccs flag:' + this.isBl && this.can_link_transfer_bl_no)
......
......@@ -2,11 +2,6 @@
<templates xml:space="preserve">
<t t-name="ccs_base.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="displayLink()" type="button" class="d-none d-md-inline o_button_link_pallet btn btn-primary mx-1" t-on-click.prevent="onLinkPalletClick">
Link Pallet
</button>
</xpath>
<xpath expr="//button[hasclass('o_list_button_add')]" position="after">
<button t-if="displayTransferBlNo()" type="button" class="d-none d-md-inline o_button_transfer_bl_no btn btn-primary mx-1" t-on-click.prevent="onTransferBlNoClick">
Link Transfer B/L No
......
......@@ -6,7 +6,7 @@
<field name="name">tree.cc.big.package</field>
<field name="model">cc.big.package</field>
<field name="arch" type="xml">
<tree string="Big Package" js_class="cc_big_package_tree" decoration-warning="is_cancel==True">
<tree string="Big Package" decoration-warning="is_cancel==True">
<field optional="show" name="big_package_no" string="Big Package No."/>
<field optional="show" name="bl_id" string="Bill of Loading"/>
<field name="ship_package_qty" string="Packages Qty"/>
......@@ -30,9 +30,6 @@
<field name="arch" type="xml">
<form string="Big Package">
<header>
<!-- <button name="action_link_pallet" type="object"-->
<!-- string="Link Pallet"-->
<!-- groups="ccs_base.group_clearance_of_customs_manager"/>&lt;!&ndash; 关联托盘 &ndash;&gt;-->
<button name="action_package_exception_info" type="object"
string="Add Package Exception Information"
groups="ccs_base.group_clearance_of_customs_manager"/><!-- 添加包裹异常信息 -->
......
......@@ -2,7 +2,6 @@
from . import batch_input_ship_package_statu_wizard
from . import export_bl_big_package_xlsx_wizard
from . import associate_pallet_wizard
from . import add_exception_info_wizard
from . import update_bl_status_wizard
from . import batch_update_transfer_bl_no_wizard
......
from . import wizard
from . import models
from . import controllers
from . import wizard
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': '清关托盘管理模块',
'name': '清关托盘模块',
'version': '1.2',
'summary': '托盘管理模块',
'summary': '清关托盘模块',
'sequence': 10,
'description': """
托盘管理模块
1) 定义托盘对象,并完成托盘的导入功能
2) 定义托盘生成报关单的功能
3) 定义清关节点,并在托盘上更新清关节点.
清关托盘模块
1) 创建托盘和打印
""",
'category': 'Pallet Management',
'website': 'https://www.yizuo.ltd',
......@@ -17,15 +15,24 @@
'data': [
'security/pallet_security.xml',
'security/ir.model.access.csv',
'views/cc_pallet_view.xml',
'views/menu_view.xml',
'wizard/pallet_batch_wizard_view.xml',
'wizard/pallet_print_wizard_view.xml',
'wizard/associate_pallet_wizard_views.xml',
'reports/pallet_label_report.xml',
'views/cc_pallet_view.xml',
'views/cc_big_package_view.xml',
'views/menu_view.xml',
],
'installable': True,
'application': True,
'assets': {
'web.assets_backend': [
'ccs_pallet/static/src/mixins/link_pallet.js',
'ccs_pallet/static/src/mixins/batch_create_pallet.js',
'ccs_pallet/static/src/views/bl_list_pallet_controller.js',
'ccs_pallet/static/src/views/big_package_list_controller.js',
'ccs_pallet/static/src/views/list.xml',
],
},
'license': 'AGPL-3',
}
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
</data>
</odoo>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- <record id="sequence_cc_pallet" model="ir.sequence">
<field name="name">托盘编码规则</field>
<field name="code">cc.pallet</field>
<field name="padding">2</field>
<field name="number_next_actual">1</field>
<field name="company_id" eval="False"/>
</record> -->
</data>
</odoo>
\ No newline at end of file
<odoo>
<data>
</data>
</odoo>
\ No newline at end of file
差异被折叠。
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 json
import logging
from datetime import timedelta
import pytz
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
# 获取日志
_logger = logging.getLogger(__name__)
......@@ -19,125 +15,95 @@ class CcPallet(models.Model):
_inherit = ['mail.thread', 'mail.activity.mixin']
# 模型描述
_description = 'Pallet'
@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='托盘号',
required=True,
readonly=True,
copy=False,
default=lambda self: _('New'),
help='托盘号格式:年月+4位数'
)
name = fields.Char(string=_('Pallet Number'), required=True, readonly=True, copy=False,
help=_('Pallet number format: YYYYMM + 4 digits'))
# 托盘归属快递
express_company_id = fields.Many2one(
'res.partner',
string='托盘归属快递',
required=True,
domain=[('is_express_company', '=', True)],
help='选择尾程快递公司'
)
# 创建时间
create_date = fields.Datetime(
string='创建时间',
readonly=True,
default=fields.Datetime.now
)
# 创建人
create_uid = fields.Many2one(
'res.users',
string='创建人',
readonly=True,
default=lambda self: self.env.user
)
express_company_id = fields.Many2one('cc.last.mile.provider', string=_('Express Company'), index=True)
# 使用状态
usage_state = fields.Selection([
('unused', '未使用'),
('used', '已使用')
], string='使用状态', default='unused', required=True, tracking=True)
usage_state = fields.Selection([('unused', _('Unused')), ('used', _('Used'))], string=_('Usage State'),
default='unused', index=True, tracking=True)
# 打印状态
print_state = fields.Selection([
('unprinted', '未打印'),
('printed', '已打印')
], string='打印状态', default='unprinted', required=True, tracking=True)
# 托盘理货时间
sorting_time = fields.Datetime(
string='托盘理货时间',
help='托盘理货完成的时间'
)
# 托盘交货时间
delivery_time = fields.Datetime(
string='托盘交货时间',
help='托盘交付给客户的时间'
)
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.One2many(
'stock.picking',
'pallet_id',
string='托盘装载大包',
help='装载在此托盘上的大包'
)
package_ids = fields.Many2many('cc.big.package', 'pallet_package_rel', string=_('Packages'))
# 大包数量
package_count = fields.Integer(
string='托盘装载大包数',
compute='_compute_package_count',
store=True
)
package_count = fields.Integer(string=_('Package Count'), compute='_compute_package_count', store=True)
# 使用客户
customer_id = fields.Many2one(
'res.partner',
string='使用客户',
domain=[('is_company', '=', True)],
help='使用此托盘的客户'
)
partner_id = fields.Many2one('res.partner', string=_('Customer'), default=get_partner_id,
domain=[('is_customer', '=', True)])
# 托盘交付车牌号
delivery_plate_number = fields.Char(
string='托盘交付车牌号',
help='交付托盘时的车牌号'
)
# 计算字段:大包数量
@api.depends('package_ids')
def _compute_package_count(self):
for record in self:
record.package_count = len(record.package_ids)
# 重写create方法,自动生成托盘号
@api.model
def create(self, vals):
if vals.get('name', _('New')) == _('New'):
# 生成托盘号:年月+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:
# 提取最后4位数字
last_number = int(last_pallet.name[-4:])
new_number = last_number + 1
else:
new_number = 1
# 生成新的托盘号
vals['name'] = f"{year_month}{new_number:04d}"
return super(CcPallet, self).create(vals)
delivery_plate_number = fields.Char(string=_('Delivery Plate Number'))
# 当大包关联到托盘时,自动更新使用状态
@api.model
def update_usage_state(self):
......@@ -147,12 +113,13 @@ class CcPallet(models.Model):
pallet.usage_state = 'used'
else:
pallet.usage_state = 'unused'
def action_print_labels(self):
"""打印标签动作"""
return {
'type': 'ir.actions.act_window',
'name': _('打印托盘标签'),
'name': _('Print Pallet Labels'),
'res_model': 'pallet.print.wizard',
'view_mode': 'form',
'target': 'new',
......@@ -160,24 +127,25 @@ class CcPallet(models.Model):
'default_pallet_ids': [(6, 0, self.ids)],
},
}
def action_view_packages(self):
"""查看大包动作"""
return {
'type': 'ir.actions.act_window',
'name': _('托盘大包'),
'name': _('Pallet Packages'),
'res_model': 'stock.picking',
'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',
'name': _('批量创建托盘'),
'views': [[False, "form"]],
'res_model': 'pallet.batch.wizard',
'view_mode': 'form',
'target': 'new',
}
\ No newline at end of file
'context': {},
}
......@@ -26,11 +26,14 @@
<!-- 条形码区域 -->
<div style="text-align: center; margin: 2cm 0; padding: 1cm; border: 2px dashed #999; background-color: #f9f9f9;">
<div style="font-size: 18px; color: #666; margin-bottom: 0.5cm;">
条形二维码
</div>
<!-- 这里可以集成条形码生成库 -->
<div style="font-size: 14px; color: #999;">
<t t-esc="pallet.name"/>
<!-- 托盘号作为二维码 -->
<t t-if="pallet.name">
<!-- `quiet=0` to remove the left and right margins on the barcode -->
<div t-out="pallet.name" style="padding:0" t-options="{'widget': 'barcode', 'quiet': 0, 'symbology': 'auto', 'img_style': barcode_size}"/>
<div class="o_label_name" style="height:1.7em;background-color: transparent;">
<span t-out="pallet.name"/>
</div>
</t>
</div>
</div>
......
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_cc_pallet_user,cc.pallet.user,model_cc_pallet,base.group_user,1,1,1,0
access_cc_pallet_manager,cc.pallet.manager,model_cc_pallet,base.group_system,1,1,1,1
access_pallet_batch_wizard_user,pallet.batch.wizard.user,model_pallet_batch_wizard,base.group_user,1,1,1,0
access_pallet_print_wizard_user,pallet.print.wizard.user,model_pallet_print_wizard,base.group_user,1,1,1,0
\ No newline at end of file
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
associate_pallet_wizard_group_user,associate_pallet_wizard_group_user,model_associate_pallet_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
......@@ -2,7 +2,7 @@
<odoo>
<data noupdate="0">
<record model="ir.module.category" id="ccs_base.module_category_pallet">
<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>
......@@ -10,7 +10,7 @@
<record id="group_pallet_manager" model="res.groups">
<field name="name">Pallet Manager</field>
<field name="category_id" ref="ccs_base.module_category_pallet"/>
<field name="category_id" ref="ccs_pallet.module_category_pallet"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
</data>
......
/** @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);
},
};
......@@ -21,7 +21,7 @@ export class BigPackageListController extends ListController {
this.isBigPackage = this.model.rootParams.resModel === "cc.big.package";
console.log('ccs isBigPackage:' + this.isBigPackage)
onWillStart(async () => {
this.is_link = await this.user.hasGroup("ccs_base.group_clearance_of_customs_manager");
this.is_link = await this.user.hasGroup("ccs_base.group_clearance_of_customs_manager") || await this.user.hasGroup("ccs_pallet.group_pallet_manager");
console.log('ccs is_link:' + this.is_link)
});
}
......@@ -32,8 +32,8 @@ export class BigPackageListController extends ListController {
return this.isBigPackage && this.is_link;
}
displayTransferBlNo() {
// 大包页面永远不显示“关联转单号”按钮
displayBatchCreatePallet() {
// 大包页面永远不显示“批量创建托盘”按钮
return false;
}
......@@ -43,6 +43,6 @@ patch(BigPackageListController.prototype, 'big_package_list_controller_link_pall
registry.category('views').add('cc_big_package_tree', {
...listView,
buttonTemplate: 'ccs_base.ListButtons',
buttonTemplate: 'ccs_pallet.ListButtons',
Controller: BigPackageListController
});
\ No newline at end of file
/** @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="displayLink()" type="button" class="d-none d-md-inline o_button_link_pallet btn btn-primary mx-1" t-on-click.prevent="onLinkPalletClick">
Link Pallet
</button>
</xpath>
<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_list" model="ir.ui.view">
<field name="name">cc.pallet.list</field>
<field name="model">cc.pallet</field>
<field name="arch" type="xml">
<list string="托盘管理" multi_edit="1">
<field name="name" string="托盘号"/>
<field name="express_company_id" string="托盘归属快递"/>
<field name="usage_state" string="使用状态" decoration-success="usage_state == 'unused'" decoration-warning="usage_state == 'used'"/>
<field name="print_state" string="打印状态" decoration-info="print_state == 'unprinted'" decoration-success="print_state == 'printed'"/>
<field name="sorting_time" string="托盘理货时间"/>
<field name="delivery_time" string="托盘交货时间"/>
<field name="package_count" string="托盘装载大包数"/>
<field name="delivery_plate_number" string="托盘交付车牌号"/>
</list>
</field>
</record>
<!-- 托盘管理表单视图 -->
<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="托盘管理">
<form string="Pallet Management">
<header>
<button name="action_print_labels" string="打印标签" type="object" class="btn-primary" icon="fa-print"/>
<field name="usage_state" widget="statusbar" statusbar_visible="unused,used"/>
<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="大包"/>
<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="基本信息">
<group string="Basic Information">
<field name="express_company_id" required="1"/>
<field name="customer_id"/>
<field name="partner_id"/>
<field name="delivery_plate_number"/>
</group>
<group string="状态信息">
<group string="Status Information">
<field name="print_state"/>
<field name="sorting_time"/>
<field name="delivery_time"/>
</group>
</group>
<notebook>
<page string="大包信息" name="packages">
<field name="package_ids">
<list>
<field name="name"/>
<field name="partner_id"/>
<field name="state"/>
</list>
</field>
<page string="Package Information" name="packages">
<field name="package_ids"/>
</page>
</notebook>
</sheet>
......@@ -71,28 +45,49 @@
</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" string="Pallet Number"/>
<field name="express_company_id" string="Express Company"/>
<field name="usage_state" string="Usage State" decoration-success="usage_state == 'unused'"
decoration-warning="usage_state == 'used'"/>
<field name="print_state" string="Print State" decoration-info="print_state == 'unprinted'"
decoration-success="print_state == 'printed'"/>
<field name="sorting_time" string="Sorting Time"/>
<field name="delivery_time" string="Delivery Time"/>
<field name="package_count" string="Package Count"/>
<field name="delivery_plate_number" string="Delivery Plate Number"/>
</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="托盘搜索">
<field name="name" string="托盘号" filter_domain="[('name', 'ilike', self)]"/>
<field name="express_company_id" string="快递公司"/>
<field name="customer_id" string="使用客户"/>
<field name="delivery_plate_number" string="车牌号"/>
<search string="Pallet Search">
<field name="name" string="Pallet Number" filter_domain="[('name', 'ilike', self)]"/>
<field name="express_company_id" string="Express Company"/>
<field name="partner_id" string="Customer"/>
<field name="delivery_plate_number" string="Plate Number"/>
<separator/>
<filter name="filter_unused" string="未使用" domain="[('usage_state', '=', 'unused')]"/>
<filter name="filter_used" string="已使用" domain="[('usage_state', '=', 'used')]"/>
<filter name="filter_unprinted" string="未打印" domain="[('print_state', '=', 'unprinted')]"/>
<filter name="filter_printed" string="已打印" domain="[('print_state', '=', 'printed')]"/>
<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="分组">
<filter name="group_by_express" string="尾程快递" context="{'group_by': 'express_company_id'}"/>
<filter name="group_by_print_state" string="打印状态" context="{'group_by': 'print_state'}"/>
<filter name="group_by_usage_state" string="使用状态" context="{'group_by': 'usage_state'}"/>
<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>
......@@ -100,44 +95,18 @@
<!-- 托盘管理动作 -->
<record id="action_cc_pallet" model="ir.actions.act_window">
<field name="name">托盘管理</field>
<field name="name">Pallet Management</field>
<field name="res_model">cc.pallet</field>
<field name="view_mode">list,form</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>
<!-- 批量创建托盘动作 -->
<record id="action_cc_pallet_batch_create" model="ir.actions.act_window">
<field name="name">批量创建托盘</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>
<!-- 菜单项 -->
<menuitem id="menu_cc_pallet_root"
name="托盘管理"
sequence="10"/>
<menuitem id="menu_cc_pallet"
name="托盘管理"
parent="menu_cc_pallet_root"
action="action_cc_pallet"
sequence="10"/>
<menuitem id="menu_cc_pallet_batch_create"
name="批量创建托盘"
parent="menu_cc_pallet_root"
action="action_cc_pallet_batch_create"
sequence="20"/>
</odoo>
\ No newline at end of file
......@@ -2,6 +2,15 @@
<odoo>
<data>
<!-- 菜单项 -->
<menuitem id="menu_cc_pallet_root" name="Pallet Management" sequence="18"
groups="ccs_pallet.group_pallet_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
......@@ -2,3 +2,4 @@
from . import pallet_batch_wizard
from . import pallet_print_wizard
from . import associate_pallet_wizard
......@@ -10,40 +10,17 @@ class AssociatePalletWizard(models.TransientModel):
_name = 'associate.pallet.wizard'
_description = 'Associate Pallet Wizard'
@api.onchange('usage_date')
def change_usage_date(self):
for item in self:
if item.usage_date:
item.pallet_number = item.get_pallet_number(item.usage_date)
def get_pallet_number(self, usage_date):
"""
生成托盘号 从001开始,如果
:return: 新的托盘号
"""
try:
# 查找大包中最新的托盘号
latest_pallet = self.env['cc.big.package'].search([('pallet_usage_date', '=', str(usage_date))],
order='pallet_number desc', limit=1)
# 生成新的托盘号
if latest_pallet:
new_pallet_number = int(latest_pallet.pallet_number) + 1
else:
new_pallet_number = 1 # 如果没有找到,默认从1开始
return str(new_pallet_number).zfill(3) # 返回格式化的托盘号
except Exception as e:
raise ValidationError(str(e))
usage_date = fields.Date(string='Usage Date', default=fields.Date.today) # 使用日期
pallet_number = fields.Char(string='Pallet Number', required=True) # 托盘号
pallet_id = fields.Many2one('cc.pallet', string='Pallet') # 托盘选择
big_package_numbers = fields.Text(string='Big Package Numbers') # 大包号(可输入多个)
def confirm(self):
for record in self:
if not record.pallet_number.isdigit():
raise ValidationError(_('The pallet number can only be entered as a number!')) # 托盘号只能输入数字
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 = []
......@@ -54,15 +31,21 @@ class AssociatePalletWizard(models.TransientModel):
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:
# 关联大包到托盘
record.pallet_id.package_ids = [(6, 0, [p.id for p in success_package])]
# 更新大包的托盘信息
for package in success_package:
# 回写大包的托盘号和使用日期
old_pallet_number = package.pallet_number
new_pallet_number = record.pallet_number # 修改的托盘
new_pallet_number = record.pallet_id.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) # 查找对应提单下相同托盘号的所有大包
......@@ -72,7 +55,9 @@ class AssociatePalletWizard(models.TransientModel):
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)
package.update_pallet_info(new_pallet_number, record.usage_date,record.pallet_id.id)
if old_pallet_number:
# %s %s更改了托盘号,由%s变更为%s,托盘使用日期%s变更为%s
body = _(
......@@ -85,3 +70,11 @@ class AssociatePalletWizard(models.TransientModel):
body = _('%s at %s associated tray %s, with a tray usage date of %s') % (
self.env.user.name, fields.Datetime.now(), new_pallet_number, record.usage_date)
package.message_post(body=body)
# 更新托盘的使用状态(理货时间和交货时间会自动通过计算字段更新)
record.pallet_id.update_usage_state()
# 记录托盘关联日志
body = _('%s at %s associated %d packages to pallet %s') % (
self.env.user.name, fields.Datetime.now(), len(success_package), record.pallet_id.name)
record.pallet_id.message_post(body=body)
......@@ -7,7 +7,7 @@
<sheet>
<group>
<field name="usage_date" required="1"/> <!-- 使用日期 -->
<field name="pallet_number" required="1"/> <!-- 托盘号 -->
<field name="pallet_id" required="1" options="{'no_create': True, 'no_quick_create': True}"/> <!-- 托盘选择 -->
<field name="big_package_numbers" required="1"
placeholder="Multiple can be entered, one large package number per line"/> <!-- 大包号 可输入多个,一行一个大包号 -->
</group>
......
......@@ -6,130 +6,87 @@ from odoo.exceptions import UserError, ValidationError
class PalletBatchWizard(models.TransientModel):
_name = 'pallet.batch.wizard'
_description = '批量创建托盘向导'
_description = 'Batch Create Pallet Wizard'
express_company_id = fields.Many2one(
'res.partner',
string='托盘归属快递',
required=True,
domain=[('is_express_company', '=', True)],
help='选择尾程快递公司'
)
quantity = fields.Integer(
string='创建数量',
required=True,
default=1,
help='要创建的托盘数量'
)
start_number = fields.Char(
string='托盘创建开始编号',
readonly=True,
help='本次创建托盘的起始编号'
)
customer_id = fields.Many2one(
'res.partner',
string='使用客户',
domain=[('is_company', '=', True)],
help='使用此托盘的客户(可选)'
)
@api.onchange('express_company_id', 'quantity')
def _onchange_express_company(self):
"""当选择快递公司或数量时,计算开始编号"""
if self.express_company_id and self.quantity:
# 获取当前年月
now = fields.Datetime.now()
year_month = now.strftime('%Y%m')
# 查找当月最大的编号
last_pallet = self.env['cc.pallet'].search([
('name', 'like', year_month + '%')
], order='name desc', limit=1)
if last_pallet and last_pallet.name:
# 提取最后4位数字
last_number = int(last_pallet.name[-4:])
start_number = last_number + 1
else:
start_number = 1
self.start_number = f"{year_month}{start_number:04d}"
# 创建数量必须大于0,且不能超过1000
@api.constrains('quantity')
def _check_quantity(self):
"""验证创建数量"""
"""Validate create quantity"""
if self.quantity <= 0:
raise ValidationError(_('创建数量必须大于0'))
raise ValidationError(_('Create quantity must be greater than 0'))
if self.quantity > 1000:
raise ValidationError(_('单次创建数量不能超过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):
"""确认创建托盘"""
self.ensure_one()
# 检查起始托盘号是否被占用
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)
])
# 检查每个托盘号是否已存在
existing_pallet = self.env['cc.pallet'].search([('name', '=', pallet_name)])
if existing_pallet:
raise UserError(_('托盘号 %s 已存在,请检查系统数据') % pallet_name)
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,
'customer_id': self.customer_id.id if self.customer_id else False,
'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': _('批量创建托盘结果'),
'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):
"""确认创建托盘并打印"""
self.ensure_one()
"""Confirm create pallets and print"""
# 先创建托盘
result = self.action_confirm()
# 获取创建的托盘
pallets = self.env['cc.pallet'].search([
('id', 'in', result['domain'][0][2])
])
# 生成打印文件
return self._generate_print_report(pallets)
# 生成打印报告
def _generate_print_report(self, pallets):
"""生成打印报告"""
# 这里需要实现PDF生成逻辑
# 暂时返回一个简单的动作
"""Generate print report"""
# PDF生成逻辑需要在这里实现
# 现在返回一个简单的动作
return {
'type': 'ir.actions.report',
'report_name': 'ccs_pallet.pallet_label_report',
......
......@@ -5,45 +5,32 @@
<field name="name">pallet.batch.wizard.form</field>
<field name="model">pallet.batch.wizard</field>
<field name="arch" type="xml">
<form string="批量创建托盘">
<form string="Batch Create Pallets">
<sheet>
<div class="oe_title">
<h1>批量创建托盘</h1>
</div>
<group>
<group string="创建信息">
<group string="Create Information">
<field name="express_company_id" required="1"/>
<field name="quantity" required="1"/>
<field name="customer_id"/>
<field name="partner_id"/>
</group>
<group string="编号信息">
<group string="Number Information">
<field name="start_number" readonly="1"/>
</group>
</group>
<div class="alert alert-info" role="alert">
<strong>提示:</strong>
<ul>
<li>托盘号将按升序自动生成</li>
<li>格式:年月+4位数(如:2025010001)</li>
<li>单次最多可创建1000个托盘</li>
</ul>
</div>
</sheet>
<footer>
<button name="action_confirm" string="确认" type="object" class="btn-primary"/>
<button name="action_confirm_and_print" string="确认并打印" type="object" class="btn-success"/>
<button string="取消" class="btn-secondary" special="cancel"/>
<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_pallet_batch_wizard" model="ir.actions.act_window">
<field name="name">批量创建托盘</field>
<!-- 批量创建托盘动作 -->
<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>
......
......@@ -6,32 +6,22 @@ from odoo.exceptions import UserError
class PalletPrintWizard(models.TransientModel):
_name = 'pallet.print.wizard'
_description = '托盘打印向导'
_description = 'Pallet Print Wizard'
pallet_ids = fields.Many2many(
'cc.pallet',
string='托盘',
required=True,
help='选择要打印的托盘'
)
pallet_count = fields.Integer(
string='托盘数量',
compute='_compute_pallet_count',
store=True
)
@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):
"""执行打印"""
self.ensure_one()
if not self.pallet_ids:
raise UserError(_('请选择要打印的托盘'))
raise UserError(_('Please select pallets to print'))
# 更新打印状态为已打印
self.pallet_ids.write({'print_state': 'printed'})
......
......@@ -5,10 +5,10 @@
<field name="name">pallet.print.wizard.form</field>
<field name="model">pallet.print.wizard</field>
<field name="arch" type="xml">
<form string="托盘打印">
<form string="Pallet Print">
<sheet>
<div class="oe_title">
<h1>托盘标签打印</h1>
<h1>Pallet Label Print</h1>
</div>
<group>
......@@ -16,20 +16,11 @@
</group>
<field name="pallet_ids" widget="many2many_tags" readonly="1"/>
<div class="alert alert-info" role="alert">
<strong>打印说明:</strong>
<ul>
<li>标签尺寸:10cm × 15cm</li>
<li>标签内容:客户名称、尾程快递简称、托盘号条形码</li>
<li>打印后托盘状态将自动更新为"已打印"</li>
</ul>
</div>
</sheet>
<footer>
<button name="action_print" string="确定打印" type="object" class="btn-primary"/>
<button string="取消" class="btn-secondary" special="cancel"/>
<button name="action_print" string="Confirm Print" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
......@@ -37,7 +28,7 @@
<!-- 托盘打印向导动作 -->
<record id="action_pallet_print_wizard" model="ir.actions.act_window">
<field name="name">托盘打印</field>
<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>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论