From 0a9992ab66a7e3f74e9d9fc7c57cf8ecde559a48 Mon Sep 17 00:00:00 2001 From: Mayank Patel Date: Wed, 11 Sep 2024 05:49:14 +0000 Subject: [PATCH] [REM] product_cores: available in professional H14528 --- product_cores/__init__.py | 3 - product_cores/__manifest__.py | 25 --- product_cores/models/__init__.py | 6 - product_cores/models/account.py | 41 ---- product_cores/models/product.py | 61 ------ product_cores/models/purchase.py | 71 ------- product_cores/models/sale.py | 69 ------ product_cores/tests/__init__.py | 3 - product_cores/tests/test_product_cores.py | 242 ---------------------- product_cores/views/product_views.xml | 69 ------ product_cores/views/purchase_views.xml | 18 -- product_cores/views/sale_views.xml | 21 -- 12 files changed, 629 deletions(-) delete mode 100644 product_cores/__init__.py delete mode 100755 product_cores/__manifest__.py delete mode 100644 product_cores/models/__init__.py delete mode 100644 product_cores/models/account.py delete mode 100644 product_cores/models/product.py delete mode 100644 product_cores/models/purchase.py delete mode 100644 product_cores/models/sale.py delete mode 100644 product_cores/tests/__init__.py delete mode 100644 product_cores/tests/test_product_cores.py delete mode 100644 product_cores/views/product_views.xml delete mode 100644 product_cores/views/purchase_views.xml delete mode 100644 product_cores/views/sale_views.xml diff --git a/product_cores/__init__.py b/product_cores/__init__.py deleted file mode 100644 index 09434554..00000000 --- a/product_cores/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from . import models diff --git a/product_cores/__manifest__.py b/product_cores/__manifest__.py deleted file mode 100755 index 83abf041..00000000 --- a/product_cores/__manifest__.py +++ /dev/null @@ -1,25 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -{ - 'name': 'Product Cores', - 'author': 'Hibou Corp. ', - 'version': '15.0.1.0.0', - 'category': 'Tools', - 'license': 'OPL-1', - 'summary': 'Charge customers core deposits.', - 'description': """ -Charge customers core deposits. - """, - 'website': 'https://hibou.io/', - 'depends': [ - 'sale_stock', - 'purchase_stock', - ], - 'data': [ - 'views/product_views.xml', - 'views/purchase_views.xml', - 'views/sale_views.xml', - ], - 'installable': True, - 'application': False, -} diff --git a/product_cores/models/__init__.py b/product_cores/models/__init__.py deleted file mode 100644 index db72a159..00000000 --- a/product_cores/models/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from . import account -from . import product -from . import purchase -from . import sale diff --git a/product_cores/models/account.py b/product_cores/models/account.py deleted file mode 100644 index 7ebf1401..00000000 --- a/product_cores/models/account.py +++ /dev/null @@ -1,41 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from datetime import timedelta -from odoo import models - - -class AccountMove(models.Model): - _inherit = 'account.move' - - def _post(self, soft=True): - if self._context.get('move_reverse_cancel'): - return super(AccountMove, self)._post(soft) - self._product_core_set_date_maturity() - return super(AccountMove, self)._post(soft) - - def _product_core_set_date_maturity(self): - for move in self: - for line in move.invoice_line_ids.filtered(lambda l: l.product_id.core_ok and l.product_id.type == 'service'): - regular_date_maturity = line.date + timedelta(days=(line.product_id.product_core_validity or 0)) - if move.move_type in ('in_invoice', 'in_refund', 'in_receipt'): - # derive from purchase - if move.move_type == 'in_refund' and line.purchase_line_id: - # try to date from original - po_move_lines = self.search([('purchase_line_id', '=', line.purchase_line_id.id)]) - po_move_lines = po_move_lines.filtered(lambda l: l.move_id.move_type == 'in_invoice') - if po_move_lines: - line.date_maturity = po_move_lines[0].date_maturity or regular_date_maturity - else: - line.date_maturity = regular_date_maturity - else: - line.date_maturity = regular_date_maturity - elif move.move_type in ('out_invoice', 'out_refund', 'out_receipt'): - # derive from sale - if move.move_type == 'out_refund' and line.sale_line_ids: - other_move_lines = line.sale_line_ids.mapped('invoice_lines').filtered(lambda l: l.move_id.move_type == 'out_invoice') - if other_move_lines: - line.date_maturity = other_move_lines[0].date_maturity or regular_date_maturity - else: - line.date_maturity = regular_date_maturity - else: - line.date_maturity = regular_date_maturity diff --git a/product_cores/models/product.py b/product_cores/models/product.py deleted file mode 100644 index b88df8d9..00000000 --- a/product_cores/models/product.py +++ /dev/null @@ -1,61 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from odoo import api, fields, models - - -class ProductTemplate(models.Model): - _inherit = 'product.template' - - core_ok = fields.Boolean(string='Core') - product_core_service_id = fields.Many2one('product.product', string='Product Core Deposit', - compute='_compute_product_core_service', - inverse='_set_product_core_service') - product_core_id = fields.Many2one('product.product', string='Product Core', - compute='_compute_product_core', - inverse='_set_product_core') - product_core_validity = fields.Integer(string='Product Core Return Validity', - help='How long after a sale the core is eligible for return. (in days)') - - @api.depends('product_variant_ids', 'product_variant_ids.product_core_service_id') - def _compute_product_core_service(self): - unique_variants = self.filtered(lambda template: len(template.product_variant_ids) == 1) - for template in unique_variants: - template.product_core_service_id = template.product_variant_ids.product_core_service_id - for template in (self - unique_variants): - template.product_core_service_id = False - - @api.depends('product_variant_ids', 'product_variant_ids.product_core_id') - def _compute_product_core(self): - unique_variants = self.filtered(lambda template: len(template.product_variant_ids) == 1) - for template in unique_variants: - template.product_core_id = template.product_variant_ids.product_core_id - for template in (self - unique_variants): - template.product_core_id = False - - def _set_product_core_service(self): - if len(self.product_variant_ids) == 1: - self.product_variant_ids.product_core_service_id = self.product_core_service_id - - def _set_product_core(self): - if len(self.product_variant_ids) == 1: - self.product_variant_ids.product_core_id = self.product_core_id - - -class ProductProduct(models.Model): - _inherit = 'product.product' - - product_core_service_id = fields.Many2one('product.product', string='Product Core Deposit') - product_core_id = fields.Many2one('product.product', string='Product Core') - - def get_purchase_core_service(self, vendor): - seller_line = self.seller_ids.filtered(lambda l: l.name == vendor and l.product_core_service_id) - # only want to return the first one - for l in seller_line: - return l.product_core_service_id - return seller_line - - -class ProductSupplierinfo(models.Model): - _inherit = 'product.supplierinfo' - - product_core_service_id = fields.Many2one('product.product', string='Product Core Deposit') diff --git a/product_cores/models/purchase.py b/product_cores/models/purchase.py deleted file mode 100644 index 95ba7087..00000000 --- a/product_cores/models/purchase.py +++ /dev/null @@ -1,71 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from odoo import api, fields, models, _ -from odoo.exceptions import UserError - - -class PurchaseOrder(models.Model): - _inherit = 'purchase.order' - - def copy(self, default=None): - new_po = super(PurchaseOrder, self).copy(default=default) - for line in new_po.order_line.filtered(lambda l: l.product_id.core_ok and not l.core_line_id): - line.unlink() - return new_po - - -class PurchaseOrderLine(models.Model): - _inherit = 'purchase.order.line' - - qty_received = fields.Float(recursive=True) - core_line_id = fields.Many2one('purchase.order.line', string='Core Purchase Line', copy=False) - - @api.model - def create(self, values): - res = super(PurchaseOrderLine, self).create(values) - other_product = res.product_id.get_purchase_core_service(res.order_id.partner_id) - if other_product: - values['product_id'] = other_product.id - values['name'] = other_product.name - values['price_unit'] = other_product.list_price - values['core_line_id'] = res.id - other_line = self.create(values) - other_line._compute_tax_id() - return res - - def write(self, values): - res = super(PurchaseOrderLine, self).write(values) - if any(f in values for f in ('product_id', 'product_qty', 'product_uom')): - self.filtered(lambda l: not l.core_line_id)\ - .mapped('order_id.order_line')\ - .filtered('core_line_id')\ - ._update_core_line() - return res - - def unlink(self): - for line in self: - if line.core_line_id and line.core_line_id and not self.env.user.has_group('purchase.group_purchase_user'): - raise UserError(_('You cannot delete a core line while the original still exists.')) - # Unlink any linked core lines. - other_line = line.order_id.order_line.filtered(lambda l: l.core_line_id == line) - if other_line and other_line not in self: - other_line.write({'core_line_id': False}) - other_line.unlink() - return super(PurchaseOrderLine, self).unlink() - - def _update_core_line(self): - for line in self: - if line.core_line_id and line.core_line_id.product_id.get_purchase_core_service(line.order_id.partner_id): - line.update({ - 'product_id': line.core_line_id.product_id.get_purchase_core_service(line.order_id.partner_id).id, - 'product_qty': line.core_line_id.product_qty, - 'product_uom': line.core_line_id.product_uom.id, - }) - elif line.core_line_id: - line.unlink() - - @api.depends('qty_received_method', 'qty_received_manual', 'core_line_id.qty_received') - def _compute_qty_received(self): - super(PurchaseOrderLine, self)._compute_qty_received() - for line in self.filtered(lambda l: l.qty_received_method == 'manual' and l.core_line_id): - line.qty_received = line.core_line_id.qty_received diff --git a/product_cores/models/sale.py b/product_cores/models/sale.py deleted file mode 100644 index c1cfb7d9..00000000 --- a/product_cores/models/sale.py +++ /dev/null @@ -1,69 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from odoo import api, fields, models, _ -from odoo.exceptions import UserError - - -class SaleOrder(models.Model): - _inherit = 'sale.order' - - def copy(self, default=None): - new_so = super(SaleOrder, self).copy(default=default) - for line in new_so.order_line.filtered(lambda l: l.product_id.core_ok and not l.core_line_id): - line.unlink() - return new_so - - -class SaleOrderLine(models.Model): - _inherit = 'sale.order.line' - - qty_delivered = fields.Float(recursive=True) - core_line_id = fields.Many2one('sale.order.line', string='Core Sale Line', copy=False) - - @api.model - def create(self, values): - res = super(SaleOrderLine, self).create(values) - if res.product_id.product_core_service_id: - other_product = res.product_id.product_core_service_id - values['product_id'] = other_product.id - values['name'] = other_product.name - values['price_unit'] = other_product.list_price - values['core_line_id'] = res.id - other_line = self.create(values) - other_line._compute_tax_id() - return res - - def write(self, values): - res = super(SaleOrderLine, self).write(values) - if 'product_id' in values or 'product_uom_qty' in values or 'product_uom' in values: - for line in self.filtered(lambda l: not l.core_line_id): - line.mapped('order_id.order_line').filtered(lambda l: l.core_line_id == line)._update_core_line() - return res - - def unlink(self): - for line in self: - if line.core_line_id and line.core_line_id and not self.env.user.has_group('sales_team.group_sale_manager'): - raise UserError(_('You cannot delete a core line while the original still exists.')) - # Unlink any linked core lines. - other_line = line.order_id.order_line.filtered(lambda l: l.core_line_id == line) - if other_line and other_line not in self: - other_line.write({'core_line_id': False}) - other_line.unlink() - return super(SaleOrderLine, self).unlink() - - def _update_core_line(self): - for line in self: - if line.core_line_id and line.core_line_id.product_id.product_core_service_id: - line.write({ - 'product_id': line.core_line_id.product_id.product_core_service_id.id, - 'product_uom_qty': line.core_line_id.product_uom_qty, - 'product_uom': line.core_line_id.product_uom.id, - }) - elif line.core_line_id: - line.unlink() - - @api.depends('core_line_id.qty_delivered') - def _compute_qty_delivered(self): - super(SaleOrderLine, self)._compute_qty_delivered() - for line in self.filtered(lambda l: l.core_line_id): - line.qty_delivered = line.core_line_id.qty_delivered diff --git a/product_cores/tests/__init__.py b/product_cores/tests/__init__.py deleted file mode 100644 index c6970af4..00000000 --- a/product_cores/tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from . import test_product_cores diff --git a/product_cores/tests/test_product_cores.py b/product_cores/tests/test_product_cores.py deleted file mode 100644 index 2bbe195c..00000000 --- a/product_cores/tests/test_product_cores.py +++ /dev/null @@ -1,242 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from odoo.tests import common, Form -from odoo import fields - - -class TestProductCores(common.TransactionCase): - def setUp(self): - super(TestProductCores, self).setUp() - self.customer = self.env.ref('base.res_partner_2') - self.vendor = self.env.ref('base.res_partner_12') - self.purchase_tax_physical = self.env['account.tax'].create({ - 'name': 'Purchase Tax Physical', - 'type_tax_use': 'purchase', - 'amount': 5.0, - }) - self.purchase_tax_service = self.env['account.tax'].create({ - 'name': 'Purchase Tax Service', - 'type_tax_use': 'purchase', - 'amount': 1.0, - }) - self.sale_tax_physical = self.env['account.tax'].create({ - 'name': 'Sale Tax Physical', - 'type_tax_use': 'sale', - 'amount': 5.0, - }) - self.sale_tax_service = self.env['account.tax'].create({ - 'name': 'Sale Tax Service', - 'type_tax_use': 'sale', - 'amount': 1.0, - }) - self.product = self.env['product.product'].create({ - 'name': 'Turbo', - 'type': 'product', - 'categ_id': self.env.ref('product.product_category_all').id, - 'supplier_taxes_id': [(6, 0, [self.purchase_tax_physical.id])], - 'taxes_id': [(6, 0, [self.sale_tax_physical.id])] - }) - self.product_core_service = self.env['product.product'].create({ - 'name': 'Turbo Core Deposit', - 'type': 'service', - 'categ_id': self.env.ref('product.product_category_all').id, - 'core_ok': True, - 'service_type': 'manual', - 'supplier_taxes_id': [(6, 0, [self.purchase_tax_service.id])], - 'taxes_id': [(6, 0, [self.sale_tax_service.id])], - 'product_core_validity': 30, - }) - self.product_core = self.env['product.product'].create({ - 'name': 'Turbo Core', - 'type': 'product', - 'categ_id': self.env.ref('product.product_category_all').id, - 'core_ok': True, - }) - self.product.product_core_id = self.product_core - self.product.product_core_service_id = self.product_core_service - - def test_01_purchase(self): - purchase = self.env['purchase.order'].create({ - 'partner_id': self.vendor.id, - }) - test_qty = 2.0 - po_line = self.env['purchase.order.line'].create({ - 'order_id': purchase.id, - 'product_id': self.product.id, - 'name': 'Test', - 'date_planned': purchase.date_order, - 'product_qty': test_qty, - 'product_uom': self.product.uom_id.id, - 'price_unit': 10.0, - }) - # Compute taxes since it didn't come from being created - po_line._compute_tax_id() - # No service line should have been created. - self.assertEqual(len(purchase.order_line), 1) - po_line.unlink() - - # Create a supplierinfo for this vendor with a core service product - self.env['product.supplierinfo'].create({ - 'name': self.vendor.id, - 'price': 10.0, - 'product_core_service_id': self.product_core_service.id, - 'product_tmpl_id': self.product.product_tmpl_id.id, - }) - po_line = self.env['purchase.order.line'].create({ - 'order_id': purchase.id, - 'product_id': self.product.id, - 'name': 'Test', - 'date_planned': purchase.date_order, - 'product_qty': test_qty, - 'product_uom': self.product.uom_id.id, - 'price_unit': 10.0, - }) - po_line._compute_tax_id() - # Ensure second line was created - self.assertEqual(len(purchase.order_line), 2) - # Ensure second line has the same quantity - self.assertTrue(all(l.product_qty == test_qty for l in purchase.order_line)) - po_line_service = purchase.order_line.filtered(lambda l: l.product_id == self.product_core_service) - self.assertTrue(po_line_service) - # Ensure correct taxes - self.assertEqual(po_line.taxes_id, self.purchase_tax_physical) - self.assertEqual(po_line_service.taxes_id, self.purchase_tax_service) - - test_qty = 10.0 - po_line.product_qty = test_qty - # Ensure second line has the same quantity - self.assertTrue(all(l.product_qty == test_qty for l in purchase.order_line)) - - purchase.button_confirm() - self.assertEqual(purchase.state, 'purchase') - self.assertEqual(len(purchase.picking_ids), 1) - self.assertEqual(len(purchase.picking_ids.move_line_ids), 1) # shouldn't have the service - purchase.picking_ids.move_line_ids.qty_done = purchase.picking_ids.move_line_ids.product_uom_qty - purchase.picking_ids.button_validate() - purchase.flush() - - # All lines should be received on the PO - for line in purchase.order_line: - self.assertEqual(line.product_qty, line.qty_received) - - # From purchase.tests.test_purchase_order_report in 13 - f = Form(self.env['account.move'].with_context(default_type='in_invoice')) - f.partner_id = purchase.partner_id - f.purchase_id = purchase - vendor_bill = f.save() - self.assertEqual(len(vendor_bill.invoice_line_ids), 2) - vendor_bill.action_post() - for line in vendor_bill.invoice_line_ids: - pol = purchase.order_line.filtered(lambda l: l.product_id == line.product_id) - self.assertTrue(pol) - self.assertEqual(line.quantity, pol.product_qty) - if line.product_id.type == 'service': - self.assertNotEqual(line.date, line.date_maturity) - purchase.flush() - - # Duplicate PO - # Should not 'duplicate' the original service line - purchase2 = purchase.copy() - self.assertEqual(len(purchase2.order_line), 2) - po_line2 = purchase2.order_line.filtered(lambda l: l.product_id == self.product) - po_line_service2 = purchase2.order_line.filtered(lambda l: l.product_id == self.product_core_service) - self.assertTrue(po_line2) - self.assertTrue(po_line_service2) - # Should not be allowed to remove the service line. - # Managers can remove the service line. - # with self.assertRaises(UserError): - # po_line_service2.unlink() - po_line2.unlink() - # Deleting the main product line should delete the service line - self.assertFalse(po_line2.exists()) - self.assertFalse(po_line_service2.exists()) - - def test_02_sale(self): - # Need Inventory. - adjust_quant = self.env['stock.quant'].with_context(inventory_mode=True).create({ - 'product_id': self.product.id, - 'inventory_quantity': 20.0, - 'location_id': self.env.ref('stock.warehouse0').lot_stock_id.id, - }) - adjust_quant.action_apply_inventory() - self.assertEqual(self.product.virtual_available, 20.0) - - sale = self.env['sale.order'].create({ - 'partner_id': self.customer.id, - 'date_order': fields.Datetime.now(), - 'picking_policy': 'direct', - }) - test_qty = 2.0 - so_line = self.env['sale.order.line'].create({ - 'order_id': sale.id, - 'product_id': self.product.id, - 'name': 'Test', - 'product_uom_qty': test_qty, - 'product_uom': self.product.uom_id.id, - 'price_unit': 10.0, - }) - # Compute taxes since it didn't come from being created - so_line._compute_tax_id() - # Ensure second line was created - self.assertEqual(len(sale.order_line), 2) - # Ensure second line has the same quantity - self.assertTrue(all(l.product_uom_qty == test_qty for l in sale.order_line)) - so_line_service = sale.order_line.filtered(lambda l: l.product_id == self.product_core_service) - self.assertTrue(so_line_service) - # Ensure correct taxes - self.assertEqual(so_line.tax_id, self.sale_tax_physical) - self.assertEqual(so_line_service.tax_id, self.sale_tax_service) - - test_qty = 1.0 - so_line.product_uom_qty = test_qty - # Ensure second line has the same quantity - self.assertTrue(all(l.product_qty == test_qty for l in sale.order_line)) - - sale.action_confirm() - self.assertTrue(sale.state in ('sale', 'done')) - self.assertEqual(len(sale.picking_ids), 1) - self.assertEqual(len(sale.picking_ids.move_lines), 1) - self.assertEqual(sale.picking_ids.move_lines.product_id, self.product) - sale.picking_ids.action_assign() - - self.assertEqual(so_line.product_uom_qty, sale.picking_ids.move_lines.reserved_availability) - for move_line in sale.picking_ids.mapped('move_lines.move_line_ids'): - move_line.qty_done = move_line.product_uom_qty - sale.picking_ids.button_validate() - self.assertEqual(sale.picking_ids.state, 'done') - self.assertEqual(so_line.qty_delivered, so_line.product_uom_qty) - - # Ensure all products are delivered. - self.assertTrue(all(l.product_qty == l.qty_delivered for l in sale.order_line)) - - # Duplicate SO - # Should not 'duplicate' the original service line - sale2 = sale.copy() - self.assertEqual(len(sale2.order_line), 2) - so_line2 = sale2.order_line.filtered(lambda l: l.product_id == self.product) - so_line_service2 = sale2.order_line.filtered(lambda l: l.product_id == self.product_core_service) - self.assertTrue(so_line2) - self.assertTrue(so_line_service2) - # Should not be allowed to remove the service line. - # Managers can remove the service line - # with self.assertRaises(UserError): - # so_line_service2.unlink() - so_line2.unlink() - # Deleting the main product line should delete the service line - self.assertFalse(so_line2.exists()) - self.assertFalse(so_line_service2.exists()) - - # Return the SO - self.assertEqual(len(sale.picking_ids), 1) - wiz = self.env['stock.return.picking'].with_context(active_model='stock.picking', active_id=sale.picking_ids.id).create({}) - wiz._onchange_picking_id() - wiz.create_returns() - self.assertEqual(len(sale.picking_ids), 2) - - return_picking = sale.picking_ids.filtered(lambda p: p.state != 'done') - self.assertTrue(return_picking) - for move_line in return_picking.mapped('move_lines.move_line_ids'): - move_line.qty_done = move_line.product_uom_qty - return_picking.button_validate() - - self.assertTrue(all(l.qty_delivered == 0.0 for l in sale.order_line)) diff --git a/product_cores/views/product_views.xml b/product_cores/views/product_views.xml deleted file mode 100644 index da7157d9..00000000 --- a/product_cores/views/product_views.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - product.template.product.form.inherit - product.template - - - -
- -
-
- - - - - - - -
-
- - - product.product.form.inherit - product.product - - - -
- -
-
- - - - - - - -
-
- - - - product.supplierinfo.tree.view.inherit - product.supplierinfo - - - - - - - - - - product.supplierinfo.form.view.inherit - product.supplierinfo - - - - - - - - -
diff --git a/product_cores/views/purchase_views.xml b/product_cores/views/purchase_views.xml deleted file mode 100644 index 63b8aec4..00000000 --- a/product_cores/views/purchase_views.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - purchase.order.form.inherit - purchase.order - - - - - - - - - - - - diff --git a/product_cores/views/sale_views.xml b/product_cores/views/sale_views.xml deleted file mode 100644 index 6b2b88f7..00000000 --- a/product_cores/views/sale_views.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - sale.order.form.inherit - sale.order - - - - - - - - - - - - - - -