diff --git a/app_sale_for_subcontract_service/README.rst b/app_sale_for_subcontract_service/README.rst new file mode 100644 index 00000000..300fbd14 --- /dev/null +++ b/app_sale_for_subcontract_service/README.rst @@ -0,0 +1,83 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +====================== +Subcontracted services +====================== + +This module allows a user to indicate that a service is subcontracted. +It provides the ability to create purchases from procurement processes. + +This is a base module, upon specific modules for sale / manufacuturing, modules +will need to rely on. By itself it does not provide any function to the end user. + +Possible uses of this module can be: + +* Add subcontracted services to BOMs. When a manufacturing order is created a + PO is triggered for the service to be subcontracted. See + +* Add subcontracted services to sales order. When the SO is confirmed, it + creates a PO for the service. + + +Configuration +============= + +To configure this module, you need to: + +#. Configure your service product with the flag + ``property_subcontracted_service`` in product form if this product should + trigger a procurement. +#. Add supplier in your product form. +#. Additionally and despite a predefined rule is created in each warehouse, + you can configure the 'Subcontracting_service procurement rule' for each + warehouse through 'Inventory / Configuration / Warehouse Management / + Warehouse'. + +Usage +===== + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/142/11.0 + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smash it by providing detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Damien Crier +* Jordi Ballester Alomar +* Lois Rilo + + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/app_sale_for_subcontract_service/__init__.py b/app_sale_for_subcontract_service/__init__.py new file mode 100644 index 00000000..a9e33722 --- /dev/null +++ b/app_sale_for_subcontract_service/__init__.py @@ -0,0 +1,2 @@ + +from . import models diff --git a/app_sale_for_subcontract_service/__manifest__.py b/app_sale_for_subcontract_service/__manifest__.py new file mode 100644 index 00000000..6861f50b --- /dev/null +++ b/app_sale_for_subcontract_service/__manifest__.py @@ -0,0 +1,28 @@ +# Author: Damien Crier +# Copyright 2017 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +# base on Camptocamp, Odoo Community Association (OCA) + +{ + "name": 'App Sale for Subcontracted service', + "version": "11.0.1.0.0", + "category": "Sale", + "website": "http://www.sunpop.cn/", + "author": "Sunpop.cn", + "license": "AGPL-3", + 'sequence': 3, + "summary": 'Sale for Subcontracted service(委外采购的销售整合)', + 'description': """ + """, + 'price': 68.00, + 'currency': 'EUR', + 'installable': True, + 'application': True, + 'auto_install': False, + "depends": [ + "app_procurement_for_subcontract_service", + "sale_stock", + ], + "data": [ + ], +} diff --git a/app_sale_for_subcontract_service/i18n/zh_CN.po b/app_sale_for_subcontract_service/i18n/zh_CN.po new file mode 100644 index 00000000..ed7aa491 --- /dev/null +++ b/app_sale_for_subcontract_service/i18n/zh_CN.po @@ -0,0 +1,54 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * app_procurement_for_subcontract_service +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0+e-20180617\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-07-20 11:07+0000\n" +"PO-Revision-Date: 2018-07-20 11:07+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" + +#. module: app_procurement_for_subcontract_service +#: code:addons/app_procurement_for_subcontract_service/models/warehouse.py:29 +#, python-format +msgid "%s: Subcontracting service rule" +msgstr "%s: 委外服务路线" + +#. module: app_procurement_for_subcontract_service +#: model:ir.model,name:app_procurement_for_subcontract_service.model_procurement_group +msgid "Procurement Requisition" +msgstr "补货申请" + +#. module: app_procurement_for_subcontract_service +#: model:ir.model,name:app_procurement_for_subcontract_service.model_product_template +msgid "Product Template" +msgstr "产品模板" + +#. module: app_procurement_for_subcontract_service +#: model:ir.model.fields,field_description:app_procurement_for_subcontract_service.field_product_product_property_subcontracted_service +#: model:ir.model.fields,field_description:app_procurement_for_subcontract_service.field_product_template_property_subcontracted_service +msgid "Subcontracted Service" +msgstr "Subcontracted Service" + +#. module: app_procurement_for_subcontract_service +#: model:ir.ui.view,arch_db:app_procurement_for_subcontract_service.view_warehouse +msgid "Subcontracting" +msgstr "委外服务" + +#. module: app_procurement_for_subcontract_service +#: model:ir.model.fields,field_description:app_procurement_for_subcontract_service.field_stock_warehouse_subcontracting_service_proc_rule_id +msgid "Subcontracting Service Procurement Rule" +msgstr "委外服务补货规则" + +#. module: app_procurement_for_subcontract_service +#: model:ir.model,name:app_procurement_for_subcontract_service.model_stock_warehouse +msgid "Warehouse" +msgstr "仓库" + diff --git a/app_sale_for_subcontract_service/models/__init__.py b/app_sale_for_subcontract_service/models/__init__.py new file mode 100644 index 00000000..17f41c2f --- /dev/null +++ b/app_sale_for_subcontract_service/models/__init__.py @@ -0,0 +1,2 @@ + +from . import sale_order_line diff --git a/app_sale_for_subcontract_service/models/sale_order_line.py b/app_sale_for_subcontract_service/models/sale_order_line.py new file mode 100644 index 00000000..a75cdf06 --- /dev/null +++ b/app_sale_for_subcontract_service/models/sale_order_line.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from datetime import datetime, timedelta + +from odoo import api, fields, models, _ +from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_compare +from odoo.exceptions import UserError + + +class SaleOrderLine(models.Model): + _inherit = 'sale.order.line' + + route_id = fields.Many2one('stock.location.route', string='Route', domain=[('sale_selectable', '=', True)], ondelete='restrict') + + @api.multi + def _prepare_procurement_values(self, group_id=False): + """ Prepare specific key for moves or other components that will be created from a procurement rule + comming from a sale order line. This method could be override in order to add other custom key that could + be used in move/po creation. + """ + values = super(SaleOrderLine, self)._prepare_procurement_values(group_id) + self.ensure_one() + date_planned = datetime.strptime(self.order_id.confirmation_date, DEFAULT_SERVER_DATETIME_FORMAT) \ + + timedelta(days=self.customer_lead or 0.0) - timedelta(days=self.order_id.company_id.security_lead) + values.update({ + 'company_id': self.order_id.company_id, + 'group_id': group_id, + 'sale_line_id': self.id, + 'date_planned': date_planned.strftime(DEFAULT_SERVER_DATETIME_FORMAT), + 'route_ids': self.route_id, + 'warehouse_id': self.order_id.warehouse_id or False, + 'partner_dest_id': self.order_id.partner_shipping_id + }) + return values + + @api.multi + def _action_launch_procurement_rule(self): + res = super(SaleOrderLine, self)._action_launch_procurement_rule + """ + Launch procurement group run method with required/custom fields genrated by a + sale order line. procurement group will launch '_run_move', '_run_buy' or '_run_manufacture' + depending on the sale order line product rule. + """ + precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') + errors = [] + for line in self: + if line.state != 'sale' or line.product_id.type in ('consu', 'product'): + continue + qty = 0.0 + for move in line.move_ids.filtered(lambda r: r.state != 'cancel'): + qty += move.product_uom._compute_quantity(move.product_uom_qty, line.product_uom, rounding_method='HALF-UP') + if float_compare(qty, line.product_uom_qty, precision_digits=precision) >= 0: + continue + + group_id = line.order_id.procurement_group_id + if not group_id: + group_id = self.env['procurement.group'].create({ + 'name': line.order_id.name, 'move_type': line.order_id.picking_policy, + 'sale_id': line.order_id.id, + 'partner_id': line.order_id.partner_shipping_id.id, + }) + line.order_id.procurement_group_id = group_id + else: + # In case the procurement group is already created and the order was + # cancelled, we need to update certain values of the group. + updated_vals = {} + if group_id.partner_id != line.order_id.partner_shipping_id: + updated_vals.update({'partner_id': line.order_id.partner_shipping_id.id}) + if group_id.move_type != line.order_id.picking_policy: + updated_vals.update({'move_type': line.order_id.picking_policy}) + if updated_vals: + group_id.write(updated_vals) + + values = line._prepare_procurement_values(group_id=group_id) + product_qty = line.product_uom_qty - qty + + procurement_uom = line.product_uom + quant_uom = line.product_id.uom_id + get_param = self.env['ir.config_parameter'].sudo().get_param + if procurement_uom.id != quant_uom.id and get_param('stock.propagate_uom') != '1': + product_qty = line.product_uom._compute_quantity(product_qty, quant_uom, rounding_method='HALF-UP') + procurement_uom = quant_uom + + try: + self.env['procurement.group'].run(line.product_id, product_qty, procurement_uom, line.order_id.partner_shipping_id.property_stock_customer, + line.name, line.order_id.name, values) + except UserError as error: + errors.append(error.name) + if errors: + raise UserError('\n'.join(errors)) + return True diff --git a/app_sale_for_subcontract_service/static/description/icon.png b/app_sale_for_subcontract_service/static/description/icon.png new file mode 100644 index 00000000..4c57f611 Binary files /dev/null and b/app_sale_for_subcontract_service/static/description/icon.png differ