summaryrefslogtreecommitdiff
path: root/indoteknik_custom/models/product_template.py
diff options
context:
space:
mode:
authorit-fixcomart <it@fixcomart.co.id>2024-12-04 11:24:24 +0700
committerit-fixcomart <it@fixcomart.co.id>2024-12-04 11:24:24 +0700
commit1094670e6fc35e5150b612b32e1f497b36c022b3 (patch)
tree4482491680db1554c28fb380480ada5282fac8f0 /indoteknik_custom/models/product_template.py
parentc631620706a24426faea6b43c2a0602eebf9a5e4 (diff)
parentdbe24b9cd600c7b5a9d0587f80a782ed93c9a761 (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-xindoteknik_custom/models/product_template.py166
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)