diff --git a/.gitignore b/.gitignore index 03aa910d..17fecbcf 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /app_odoo_customize/_resource /app_web_studio /web_studio +.conf diff --git a/app_stock_barcode/__init__.py b/app_stock_barcode/__init__.py new file mode 100644 index 00000000..16d7e280 --- /dev/null +++ b/app_stock_barcode/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +from hooks import pre_init_hook +from . import models +from . import ir +from . import res \ No newline at end of file diff --git a/app_stock_barcode/__manifest__.py b/app_stock_barcode/__manifest__.py new file mode 100644 index 00000000..2ddd062f --- /dev/null +++ b/app_stock_barcode/__manifest__.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +# Created on 2017-11-05 +# author: 广州尚鹏,http://www.sunpop.cn +# email: 75695762@qq.com +# resource of Sunpop +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +# Odoo在线中文用户手册(长期更新) +# http://www.sunpop.cn/documentation/user/10.0/zh_CN/index.html + +# Odoo10离线中文用户手册下载 +# http://www.sunpop.cn/odoo10_user_manual_document_offline/ +# Odoo10离线开发手册下载-含python教程,jquery参考,Jinja2模板,PostgresSQL参考(odoo开发必备) +# http://www.sunpop.cn/odoo10_developer_document_offline/ +# description: + + +{ + 'name': "App Warehouse Management Barcode Enhance", + 'version': '10.0.1', + 'summary': """条码,仓库模块操作增强""", + 'description': """ + 扫码面板 + """, + 'author': 'Sunpop.cn', + 'website': 'http://www.sunpop.cn', + 'license': 'LGPL-3', + 'category': 'Felive', + 'sequence': 0, + 'pre_init_hook': 'pre_init_hook', + 'depends': ['stock_barcode'], + 'data': [ + 'views/stock_pack_current_views.xml', + 'views/stock_picking_views.xml', + 'views/stock_quant_package_views.xml', + ], + 'demo': [ + ], + 'test': [ + ], + 'css': [ + ], + 'qweb': [ + ], + 'js': [ + ], + 'images': [ + ], + 'installable': True, + 'auto_install': False, + 'application': True, +} diff --git a/app_stock_barcode/hooks.py b/app_stock_barcode/hooks.py new file mode 100644 index 00000000..d28aa216 --- /dev/null +++ b/app_stock_barcode/hooks.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +# Created on 2017-11-22 +# author: 广州尚鹏,http://www.sunpop.cn +# email: 300883@qq.com +# resource of Sunpop +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +# Odoo在线中文用户手册(长期更新) +# http://www.sunpop.cn/documentation/user/10.0/zh_CN/index.html + +# Odoo10离线中文用户手册下载 +# http://www.sunpop.cn/odoo10_user_manual_document_offline/ +# Odoo10离线开发手册下载-含python教程,jquery参考,Jinja2模板,PostgresSQL参考(odoo开发必备) +# http://www.sunpop.cn/odoo10_developer_document_offline/ +# description: + +def pre_init_hook(cr): + """ + 数据初始化,只在安装时执行,更新时不执行 + """ + pass; \ No newline at end of file diff --git a/app_stock_barcode/i18n/zh_CN.po b/app_stock_barcode/i18n/zh_CN.po new file mode 100644 index 00000000..f45db9f9 --- /dev/null +++ b/app_stock_barcode/i18n/zh_CN.po @@ -0,0 +1,16 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * felive_home +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-08 14:28+0000\n" +"PO-Revision-Date: 2018-01-08 14:28+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" diff --git a/app_stock_barcode/ir/__init__.py b/app_stock_barcode/ir/__init__.py new file mode 100644 index 00000000..40a96afc --- /dev/null +++ b/app_stock_barcode/ir/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/app_stock_barcode/models/__init__.py b/app_stock_barcode/models/__init__.py new file mode 100644 index 00000000..44a231bf --- /dev/null +++ b/app_stock_barcode/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +import stock_picking +import stock_pack_operation +import stock_pack_current +import stock_quant_package \ No newline at end of file diff --git a/app_stock_barcode/models/stock_pack_current.py b/app_stock_barcode/models/stock_pack_current.py new file mode 100644 index 00000000..8105512c --- /dev/null +++ b/app_stock_barcode/models/stock_pack_current.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +from odoo import fields, models, api, _ +import odoo.addons.decimal_precision as dp + +import logging +logger = logging.getLogger(__name__) + +class StockPackCurrent(models.Model): + _name = "stock.pack.current" + _description = "Current Packing Operation" + _order = "id desc" + + picking_id = fields.Many2one( + 'stock.picking', 'Stock Picking', + required=True, ondelete="cascade", + help='The stock operation where the packing has been made') + product_id = fields.Many2one('product.product', 'Product', ondelete="cascade") + product_uom_id = fields.Many2one('product.uom', 'Unit of Measure') + product_qty = fields.Float('To Do', default=0.0, digits=dp.get_precision('Product Unit of Measure'), required=True) + qty_done = fields.Float('Done', default=0.0, digits=dp.get_precision('Product Unit of Measure')) + package_id = fields.Many2one('stock.quant.package', 'Source Package') + result_package_id = fields.Many2one( + 'stock.quant.package', 'Destination Package', + ondelete='cascade', required=False, + help="If set, the operations are packed into this package") + + weight = fields.Float( + 'Weight', digits=dp.get_precision('Stock Weight'), related='product_id.weight', readonly=True, store=True, + help="The weight of the contents in Kg, not including any packaging, etc.") + + weight_done_subtotal = fields.Float( + 'Weight Done Subtotal', digits=dp.get_precision('Stock Weight'), compute='_compute_weight_done_subtotal', readonly=True, store=True, + help="The weight of the contents in Kg, not including any packaging, etc.") + + @api.depends('weight', 'qty_done') + def _compute_weight_done_subtotal(self): + for rec in self: + rec.weight_done_subtotal = rec.weight * rec.qty_done + diff --git a/app_stock_barcode/models/stock_pack_operation.py b/app_stock_barcode/models/stock_pack_operation.py new file mode 100644 index 00000000..041d49e5 --- /dev/null +++ b/app_stock_barcode/models/stock_pack_operation.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +from odoo import fields, models, api, _ +import odoo.addons.decimal_precision as dp +from odoo.exceptions import UserError +from odoo.exceptions import Warning + +import logging + +logger = logging.getLogger(__name__) + + +class PackOperation(models.Model): + _inherit = "stock.pack.operation" + + weight = fields.Float( + 'Weight', digits=dp.get_precision('Stock Weight'), related='product_id.weight', readonly=True, store=True, + help="The weight of the contents in Kg, not including any packaging, etc.") + + weight_done_subtotal = fields.Float( + 'Weight Done Subtotal', digits=dp.get_precision('Stock Weight'), compute='_compute_weight_done_subtotal', readonly=True, store=True, + help="The weight of the contents in Kg, not including any packaging, etc.") + + @api.depends('weight', 'qty_done') + def _compute_weight_done_subtotal(self): + for rec in self: + rec.weight_done_subtotal = rec.weight * rec.qty_done diff --git a/app_stock_barcode/models/stock_picking.py b/app_stock_barcode/models/stock_picking.py new file mode 100644 index 00000000..6ad54fcf --- /dev/null +++ b/app_stock_barcode/models/stock_picking.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- + +from odoo import fields, models, api, _ +from odoo.exceptions import UserError +import odoo.addons.decimal_precision as dp + +import logging + +logger = logging.getLogger(__name__) + + +class Picking(models.Model): + _name = 'stock.picking' + _inherit = ['stock.picking', 'barcodes.barcode_events_mixin'] + + # 作业,已扫码未装入包操作的记录行 + pack_operation_product_current_ids = fields.One2many( + 'stock.pack.current', 'picking_id', string='Product packing', readonly=True, copy=False) + # 作业,已装入包操作的散件 + pack_operation_product_packed_ids = fields.One2many( + 'stock.pack.operation', 'picking_id', 'Product packed', + domain=[('product_id', '>=', 1), ('qty_done', '>=', 1), ('result_package_id', '!=', False)], readonly=True, copy=False) + # 散件涉及到的包裹列表 + result_package_ids = fields.Many2many('stock.quant.package', string='Relate Packages', readonly=True, copy=False) + + # 统计,散件与包裹一起处理的数量 + product_qty_total = fields.Float('To Do Total', compute="_compute_product_qty_total", + digits=dp.get_precision('Product Unit of Measure'), readonly=True, store=True) # 总待办数量 + qty_done_total = fields.Float('Done Total', compute="_compute_done_total", + digits=dp.get_precision('Product Unit of Measure'), readonly=True, store=True) # 总完成数量 + weight_done_total = fields.Float('Weight Done Total(kg)', digits=dp.get_precision('Stock Weight'), + compute="_compute_done_total", readonly=True, store=True) # 总完成重量 + package_count = fields.Integer('Package Total', compute="_compute_package_count", readonly=True) # 待处理的包裹数量 + package_done_count = fields.Integer('Package Done Total', compute="_compute_package_done_count", readonly=True, store=True) # 已处理的包裹数量 + + @api.depends('pack_operation_product_ids.product_qty', 'pack_operation_pack_ids.product_qty') + def _compute_product_qty_total(self): + for rec in self: + try: + rec.product_qty_total = sum(rec.pack_operation_product_ids.mapped('product_qty')) + rec.product_qty_total += sum(rec.pack_operation_pack_ids.filtered(lambda pack: not pack.is_done).mapped('package_id.qty_done_total')) + except: + rec.product_qty_total = 0 + + @api.depends('pack_operation_product_ids.qty_done', 'pack_operation_pack_ids.qty_done') + def _compute_done_total(self): + for rec in self: + # 此处用一次遍历减少计算量 + qty_done_total = 0 + weight_done_total = 0 + for op in rec.pack_operation_product_ids: + qty_done_total += op.qty_done + try: + weight_op = op.product_id.weight * op.qty_done + except: + weight_op = 0 + weight_done_total += weight_op + # qty_done_total += sum(rec.pack_operation_pack_ids.mapped('package_id.qty_done_total')) + weight_done_total += sum(rec.pack_operation_pack_ids.filtered(lambda pack: pack.qty_done).mapped('package_id.weight_done_total')) + rec.qty_done_total = qty_done_total + rec.weight_done_total = weight_done_total + + @api.depends('pack_operation_product_ids.result_package_id', 'pack_operation_pack_ids') + @api.one + def _compute_package_count(self): + for rec in self: + # 散件打包数量 + rec.package_count = len(rec.pack_operation_product_packed_ids.mapped('result_package_id').ids) + # 包裹再打包数量 + rec.package_count += len(rec.pack_operation_pack_ids) + + @api.depends('state', 'pack_operation_product_ids.result_package_id', 'pack_operation_pack_ids.result_package_id') + @api.one + def _compute_package_done_count(self): + for rec in self: + if rec.state == 'done': + rec.package_done_count = len(rec.pack_operation_product_packed_ids.mapped('result_package_id').ids) + pack_packs = rec.pack_operation_pack_ids.filtered(lambda pack: not pack.product_id and pack.qty_done and pack.result_package_id) + rec.package_done_count += len(pack_packs.mapped('result_package_id').ids) + + + # 不用于字段compute,在每次放入包裹操作执行,重新计算 + def set_package(self): + for rec in self: + if rec.pack_operation_product_packed_ids: + rec.result_package_ids = rec.pack_operation_product_ids.mapped('result_package_id').ids + rec.package_count = len(rec.result_package_ids) + len(rec.pack_operation_pack_ids) + pass + + @api.multi + def put_in_pack2(self): + self.put_in_pack() + + @api.multi + def put_in_pack(self): + pack = super(Picking, self).put_in_pack() + self.set_package() + self.set_current() + return pack + + # 每次重新算,todo: 只更新相关行 + @api.onchange('pack_operation_product_ids') + def set_current(self): + self.pack_operation_product_current_ids = [(5, 0, 0)] + current_ids = [] + if self.pack_operation_product_ids and self.state != 'done': + current_ids = self.pack_operation_product_ids \ + .filtered(lambda pack: pack.product_id and pack.qty_done > 0 and not pack.result_package_id) + if current_ids: + ops = [] + for op in current_ids: + ops.insert(0, [0, 0, { + 'picking_id': self.id, + 'product_id': op.product_id.id, + 'product_uom_id': op.product_uom_id.id, + 'product_qty': op.product_qty, + 'qty_done': op.qty_done, + 'weight': op.weight, + }]) + self.update({'pack_operation_product_current_ids': ops}) \ No newline at end of file diff --git a/app_stock_barcode/models/stock_quant_package.py b/app_stock_barcode/models/stock_quant_package.py new file mode 100644 index 00000000..d7e6c2f6 --- /dev/null +++ b/app_stock_barcode/models/stock_quant_package.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +from odoo import api, models, fields, _ +from odoo.addons import decimal_precision as dp +from odoo.exceptions import UserError, ValidationError + +class QuantPackage(models.Model): + _inherit = 'stock.quant.package' + qty_done_total = fields.Float('Done Total', default=0.0, store=True, + compute="_compute_done_total", + digits=dp.get_precision('Product Unit of Measure')) # 总完成数量 + weight_done_total = fields.Float('Weight Done Total(kg)', default=0, store=True, + digits=dp.get_precision('Stock Weight'), + compute="_compute_done_total", readonly=True) # 总完成重量 + + @api.depends('quant_ids.qty') + def _compute_done_total(self): + for rec in self: + try: + rec.qty_done_total = sum(rec.quant_ids.mapped('qty')) + except: + rec.qty_done_total = 0 + try: + rec.weight_done_total = sum(rec.quant_ids.mapped('weight_done_subtotal')) + except: + rec.weight_done_total = 0 + + def _compute_complete_name(self): + """ Forms complete name of location from parent location to child location. """ + res = {} + for package in self: + current = package + name = current.name + while current.parent_id: + name = '%s / %s' % (current.parent_id.name, name) + current = current.parent_id + + if package.qty_done_total>0: + name += '-[%spcs]' % (str(package.qty_done_total)) + if package.weight_done_total>0: + name += '-[%skg]' % (str(package.weight_done_total)) + + res[package.id] = name + return res \ No newline at end of file diff --git a/app_stock_barcode/report/__init__.py b/app_stock_barcode/report/__init__.py new file mode 100644 index 00000000..633f8661 --- /dev/null +++ b/app_stock_barcode/report/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- + diff --git a/app_stock_barcode/res/__init__.py b/app_stock_barcode/res/__init__.py new file mode 100644 index 00000000..40a96afc --- /dev/null +++ b/app_stock_barcode/res/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/app_stock_barcode/static/description/icon.png b/app_stock_barcode/static/description/icon.png new file mode 100644 index 00000000..4c57f611 Binary files /dev/null and b/app_stock_barcode/static/description/icon.png differ diff --git a/app_stock_barcode/views/stock_pack_current_views.xml b/app_stock_barcode/views/stock_pack_current_views.xml new file mode 100644 index 00000000..7d473bf9 --- /dev/null +++ b/app_stock_barcode/views/stock_pack_current_views.xml @@ -0,0 +1,90 @@ + + + + app.stock.pack.current.tree + stock.pack.current + + + + + + + + + + + + + + app.stock.pack.current.kanban + stock.pack.current + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + / + + + + + + + + / + + + + + + + + / + + + + + + + + + + + + + + + + Packing Package + ir.actions.act_window + stock.pack.current + form + kanban,tree,form + [('picking_id', '=', active_id), ('qty_done, '>', 1)] + {"search_default_groupby_result_package_id":True,} + + \ No newline at end of file diff --git a/app_stock_barcode/views/stock_picking_views.xml b/app_stock_barcode/views/stock_picking_views.xml new file mode 100644 index 00000000..2bb3be5f --- /dev/null +++ b/app_stock_barcode/views/stock_picking_views.xml @@ -0,0 +1,65 @@ + + + + app.stock.picking.tree + stock.picking + + + + + + + + + + + + + + app.stock.picking.form + stock.picking + + + + + + + + + + + + + + + + + + + + + + Product:/ + + + + Package:/ + + + + + + + + Total + + + Total + + + + \ No newline at end of file diff --git a/app_stock_barcode/views/stock_quant_package_views.xml b/app_stock_barcode/views/stock_quant_package_views.xml new file mode 100644 index 00000000..c6198d31 --- /dev/null +++ b/app_stock_barcode/views/stock_quant_package_views.xml @@ -0,0 +1,25 @@ + + + + app.stock.quant.package.tree + stock.quant.package + + + + + + + + + + app.stock.quant.package.form + stock.quant.package + + + + + + + + + \ No newline at end of file diff --git a/odoo.conf b/odoo.conf new file mode 100644 index 00000000..af1dc7b3 --- /dev/null +++ b/odoo.conf @@ -0,0 +1,18 @@ +[options] +addons_path = d:\odoo10\app-odoo,d:\odoo10\source\odoo\addons,D:\odoo10ent\source\odoo\addons +data_dir = file +db_host = 127.0.0.1 +db_maxconn = 64 +db_name = False +db_user = odoo +db_password = odoo +db_port = 5432 +db_template = template1 +loglevel = debug +bin_path = runtime\win32\wkhtmltopdf +pg_path = runtime\pgsql\bin +db_template = template0 + +longpolling_port = 8072 +xmlrpc_port = 8010 +