diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2024-12-04 11:24:24 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2024-12-04 11:24:24 +0700 |
| commit | 1094670e6fc35e5150b612b32e1f497b36c022b3 (patch) | |
| tree | 4482491680db1554c28fb380480ada5282fac8f0 /indoteknik_custom/models/product_template.py | |
| parent | c631620706a24426faea6b43c2a0602eebf9a5e4 (diff) | |
| parent | dbe24b9cd600c7b5a9d0587f80a782ed93c9a761 (diff) | |
Merge branch 'production' into iman/telegram
# Conflicts:
# indoteknik_custom/models/__init__.py
# indoteknik_custom/models/stock_picking.py
Diffstat (limited to 'indoteknik_custom/models/product_template.py')
| -rwxr-xr-x | indoteknik_custom/models/product_template.py | 166 |
1 files changed, 138 insertions, 28 deletions
diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 031d1b5b..4d186568 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -1,10 +1,11 @@ -from odoo import fields, models, api +from odoo import fields, models, api, tools, _ from datetime import datetime, timedelta, date from odoo.exceptions import UserError import logging import requests import json import re +from bs4 import BeautifulSoup _logger = logging.getLogger(__name__) @@ -60,6 +61,7 @@ class ProductTemplate(models.Model): sni = fields.Boolean(string='SNI') tkdn = fields.Boolean(string='TKDN') short_spesification = fields.Char(string='Short Spesification') + merchandise_ok = fields.Boolean(string='Product Promotion') @api.constrains('name', 'internal_reference', 'x_manufacture') def required_public_categ_ids(self): @@ -363,6 +365,7 @@ class ProductProduct(models.Model): specification = fields.Char(string='Specification') material = fields.Char(string='Material') qty_onhand_bandengan = fields.Float(string='Onhand BU', compute='_get_qty_onhand_bandengan') + clean_website_description = fields.Char(string='Clean Website Description', compute='_get_clean_website_description') qty_incoming_bandengan = fields.Float(string='Incoming BU', compute='_get_qty_incoming_bandengan') qty_outgoing_bandengan = fields.Float(string='Outgoing BU', compute='_get_qty_outgoing_bandengan') qty_available_bandengan = fields.Float(string='Available BU', compute='_get_qty_available_bandengan') @@ -372,6 +375,15 @@ class ProductProduct(models.Model): is_edited = fields.Boolean(string='Is Edited') qty_sold = fields.Float(string='Sold Quantity', compute='_get_qty_sold') short_spesification = fields.Char(string='Short Spesification') + max_qty_reorder = fields.Float(string='Max Qty Reorder', compute='_get_max_qty_reordering_rule') + qty_rpo = fields.Float(string='Qty RPO', compute='_get_qty_rpo') + plafon_qty = fields.Float(string='Max Plafon', compute='_get_plafon_qty_product') + merchandise_ok = fields.Boolean(string='Product Promotion') + + def _get_clean_website_description(self): + for rec in self: + cleaned_desc = BeautifulSoup(self.website_description or '', "html.parser").get_text() + rec.clean_website_description = cleaned_desc @api.constrains('name', 'internal_reference', 'x_manufacture') def required_public_categ_ids(self): @@ -382,22 +394,46 @@ class ProductProduct(models.Model): @api.constrains('active') def archive_product(self): for product in self: + if self.env.context.get('skip_unpublished_constraint'): + continue # Mencegah looping saat dipanggil dari metode lain + product_template = product.product_tmpl_id variants = product_template.product_variant_ids - if product_template.active and product.active: - if not product.active and len(variants) == 1: - product_template.with_context(skip_active_constraint=True).active = False - product_template.unpublished = True - elif not product.active and len(variants) > 1: + if len(variants) == 1: + # Jika hanya ada satu varian, atur status `unpublished` berdasarkan `active` + product_template.with_context(skip_unpublished_constraint=True).unpublished = not product.active + product.with_context(skip_unpublished_constraint=True).unpublished = not product.active + else: + if product.active: + product.with_context(skip_unpublished_constraint=True).unpublished = False + product_template.with_context(skip_unpublished_constraint=True).unpublished = any(variant.active for variant in variants) + else: + product.with_context(skip_unpublished_constraint=True).unpublished = True all_inactive = all(not variant.active for variant in variants) - if all_inactive: - product_template.with_context(skip_active_constraint=True).active = False - product_template.unpublished = True - else: - continue - if any(variant.active for variant in variants): - product_template.unpublished = False + product_template.with_context(skip_unpublished_constraint=True).unpublished = all_inactive + + @api.constrains('unpublished') + def archive_product_unpublished(self): + for product in self: + if self.env.context.get('skip_active_constraint'): + continue # Mencegah looping saat dipanggil dari metode lain + + product_template = product.product_tmpl_id + variants = product_template.product_variant_ids + + if len(variants) == 1: + # Jika hanya ada satu varian, atur status `unpublished` pada template, tetapi biarkan `active` tetap True + product_template.with_context(skip_active_constraint=True).unpublished = product.unpublished + else: + if not product.unpublished: + # Jika `unpublished` adalah False, pastikan `active` tetap True + product.with_context(skip_active_constraint=True).active = True + product_template.with_context(skip_active_constraint=True).active = any(not variant.unpublished for variant in variants) + else: + # Jika `unpublished` adalah True, atur template hanya jika semua varian di-unpublished + all_unpublished = all(variant.unpublished for variant in variants) + product_template.with_context(skip_active_constraint=True).active = not all_unpublished def update_internal_reference_variants(self, limit=100): variants = self.env['product.product'].search([ @@ -448,23 +484,38 @@ class ProductProduct(models.Model): def _get_qty_incoming_bandengan(self): for product in self: - qty_incoming = self.env['stock.move'].search([ - ('product_id', '=', product.id), - ('location_dest_id', 'in', [57, 83]), - ('state', 'not in', ['done', 'cancel']) - ]) - qty = sum(qty_incoming.mapped('product_uom_qty')) + qty = self.env['v.move.outstanding'].read_group( + domain=[ + ('product_id', '=', product.id), + ('location_dest_id', 'in', [57, 83]), + ], + fields=['qty_need'], + groupby=[] + )[0].get('qty_need', 0.0) + product.qty_incoming_bandengan = qty + + def _get_qty_incoming_bandengan_with_exclude(self): + for product in self: + qty = self.env['v.move.outstanding'].read_group( + domain=[ + ('product_id', '=', product.id), + ('location_dest_id', 'in', [57, 83]), + ], + fields=['qty_need'], + groupby=[] + )[0].get('qty_need', 0.0) product.qty_incoming_bandengan = qty def _get_qty_outgoing_bandengan(self): for product in self: - qty_incoming = self.env['stock.move'].search([ - ('product_id', '=', product.id), - ('location_dest_id', '=', 5), - ('location_id', 'in', [57, 83]), - ('state', 'not in', ['done', 'cancel']) - ]) - qty = sum(qty_incoming.mapped('product_uom_qty')) + qty = self.env['v.move.outstanding'].read_group( + domain=[ + ('product_id', '=', product.id), + ('location_id', 'in', [57, 83]), + ], + fields=['qty_need'], + groupby=[] + )[0].get('qty_need', 0.0) product.qty_outgoing_bandengan = qty def _get_qty_onhand_bandengan(self): @@ -479,13 +530,41 @@ class ProductProduct(models.Model): def _get_qty_available_bandengan(self): for product in self: qty_available = product.qty_incoming_bandengan + product.qty_onhand_bandengan - product.qty_outgoing_bandengan - product.qty_available_bandengan = qty_available + product.qty_available_bandengan = qty_available or 0 def _get_qty_free_bandengan(self): for product in self: qty_free = product.qty_onhand_bandengan - product.qty_outgoing_bandengan product.qty_free_bandengan = qty_free - + + def _get_max_qty_reordering_rule(self): + for product in self: + reordering = self.env['stock.warehouse.orderpoint'].search([ + ('product_id', '=', product.id) + ], limit=1) + if not reordering: + product.max_qty_reorder = 0 + else: + product.max_qty_reorder = reordering.product_max_qty + + def _get_qty_rpo(self): + for product in self: + rpo = self.env['v.requisition.match.po'].search([ + ('product_id', '=', product.id) + ], limit=1) + if not rpo: + product.qty_rpo = 0 + else: + product.qty_rpo = rpo.qty_rpo + + def _get_plafon_qty_product(self): + for product in self: + qty_available = product.qty_available_bandengan + max_qty = product.max_qty_reorder + qty_rpo = product.qty_rpo + product.plafon_qty = max_qty - qty_available + qty_rpo + + # def write(self, vals): # if 'solr_flag' not in vals: # for variant in self: @@ -526,3 +605,34 @@ class ProductProduct(models.Model): ('end_date', '>=', current_time) ], limit=1) return pricelist + + +class OutstandingMove(models.Model): + _name = 'v.move.outstanding' + _auto = False + _rec_name = 'id' + + id = fields.Integer(string='ID') + product_id = fields.Many2one('product.product', string='Product') + reference = fields.Char(string='Reference', help='Nomor Dokumen terkait') + qty_need = fields.Float(string='Qty Need', help='Qty yang akan outgoing / incoming') + location_id = fields.Many2one('stock.location', string='Location', help='Lokasi asal') + location_dest_id = fields.Many2one('stock.location', string='Location To', help='Lokasi tujuan') + + def init(self): + # where clause 'state in' follow the origin of outgoing and incoming odoo + tools.drop_view_if_exists(self.env.cr, self._table) + self.env.cr.execute(""" + CREATE OR REPLACE VIEW %s AS + select sm.id, sm.reference, sm.product_id, + sm.product_uom_qty as qty_need, + sm.location_id, sm.location_dest_id + from stock_move sm + where 1=1 + and sm.state in( + 'waiting', + 'confirmed', + 'assigned', + 'partially_available' + ) + """ % self._table) |
