From 8ee7bd9211a75809e1819de32ddf974c3736ebde Mon Sep 17 00:00:00 2001 From: Mqdd Date: Fri, 5 Dec 2025 16:46:24 +0700 Subject: Initial COmmit baru --- indoteknik_custom/models/product_template.py | 171 ++++++++++++++------------- 1 file changed, 86 insertions(+), 85 deletions(-) (limited to 'indoteknik_custom/models/product_template.py') diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index ee33a185..400d31e0 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -68,7 +68,7 @@ class ProductTemplate(models.Model): ('sp', 'Spare Part'), ('acc', 'Accessories') ], string='Kind of', copy=False) - sni = fields.Boolean(string='SNI') + sni = fields.Boolean(string='SNI') tkdn = fields.Boolean(string='TKDN') short_spesification = fields.Char(string='Short Spesification') merchandise_ok = fields.Boolean(string='Product Promotion') @@ -85,7 +85,7 @@ class ProductTemplate(models.Model): raise UserError('Hanya MD yang bisa membuat Product') result = super(ProductTemplate, self).create(vals) return result - + # def write(self, values): # group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id # users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])]) @@ -112,7 +112,7 @@ class ProductTemplate(models.Model): # qr_code_img = base64.b64encode(buffer.getvalue()).decode() # rec.qr_code = qr_code_img - + @api.constrains('name', 'internal_reference', 'x_manufacture') def required_public_categ_ids(self): for rec in self: @@ -125,7 +125,7 @@ class ProductTemplate(models.Model): def day_product_to_edit(self): day_products = [] - + for product in self: day_product = (product.write_date - product.create_date).days day_products.append(day_product) @@ -138,25 +138,25 @@ class ProductTemplate(models.Model): variants = product.product_variant_ids names = [x.name for x in variants] if variants else [product.name] default_codes = [x.default_code for x in variants] if variants else [product.default_code] - + domain = [ - ('default_code', '!=', False), + ('default_code', '!=', False), ('id', '!=', product.id), - '|', - ('name', 'in', names), + '|', + ('name', 'in', names), ('default_code', 'in', default_codes) ] - + product_exist = self.search(domain, limit=1) if len(product_exist) > 0: raise UserError('Name atau Internal Reference sudah digunakan pada produk lain') - + if self.env.user.is_purchasing_manager or self.env.user.is_editor_product or self.env.user.id in [1, 25]: continue - + if sum(product.day_product_to_edit()) > 0: raise UserError('Produk ini tidak dapat diubah') - + @api.constrains('name') def _validate_name(self): rule_regex = self.env['ir.config_parameter'].sudo().get_param('product.product.rule_name_regex') or '' @@ -165,7 +165,7 @@ class ProductTemplate(models.Model): pattern_suggest = rf"{rule_regex}" suggest = ''.join(re.findall(pattern_suggest, self.name)) raise UserError(f'Contoh yang benar adalah {suggest}') - + # def write(self, vals): # if 'solr_flag' not in vals and self.solr_flag == 1: # vals['solr_flag'] = 2 @@ -204,7 +204,7 @@ class ProductTemplate(models.Model): def unlink(self): if self._name == 'product.template': raise UserError('Maaf anda tidak bisa delete product') - + def update_new_product(self): current_time = datetime.now() delta_time = current_time - timedelta(days=30) @@ -235,7 +235,7 @@ class ProductTemplate(models.Model): for template in templates: if not template.default_code: template.default_code = 'IT.'+str(template.id) - + for variant in template.product_variant_ids: if not variant.default_code: variant.default_code = 'ITV.%s' % str(variant.id) @@ -327,7 +327,7 @@ class ProductTemplate(models.Model): def _get_stock_website(self): qty = self._get_stock_altama() print(qty) - + def get_stock_altama(self, item_code): current_time = datetime.now() current_time = current_time.strftime('%Y-%m-%d %H:%M:%S') @@ -338,7 +338,7 @@ class ProductTemplate(models.Model): token = token_data['access_token'] else: token = token_data.access_token - + url = "https://erpapi.altama.co.id/erp/api/stock/buffer/btob" auth = "Bearer "+token headers = { @@ -352,7 +352,7 @@ class ProductTemplate(models.Model): response = requests.post(url, headers=headers, json=json_data) if response.status_code != 200: return 0 - + datas = json.loads(response.text)['data'] qty = 0 for data in datas: @@ -371,12 +371,12 @@ class ProductTemplate(models.Model): data = { 'grant_type': 'client_credentials', } - + response = requests.post(url, headers=headers, data=data).json() lookup_json = json.dumps(response, indent=4, sort_keys=True) token = json.loads(lookup_json)['access_token'] expires_in = json.loads(lookup_json)['expires_in'] - + current_time = datetime.now() delta_time = current_time + timedelta(seconds=int(expires_in)) @@ -392,18 +392,18 @@ class ProductTemplate(models.Model): self.env['token.storage'].create([values]) return values - # ============================== + # ============================== def get_vendor_name(self, rec): """Get formatted name for vendor/supplier""" return rec.name.name if rec.name else f"ID {rec.id}" - + def get_attribute_line_name(self, rec): """Get formatted name for attribute line""" if rec.attribute_id and rec.value_ids: values = ", ".join(rec.value_ids.mapped('name')) return f"{rec.attribute_id.name}: {values}" return f"ID {rec.id}" - + def _get_vendor_field_label(self, field_name): """Get human-readable label for vendor fields""" field_labels = { @@ -419,10 +419,10 @@ class ProductTemplate(models.Model): 'date_end': 'End Date', 'min_qty': 'Quantity' } - return field_labels.get(field_name, field_name.replace('_', ' ').title()) + return field_labels.get(field_name, field_name.replace('_', ' ').title()) # ============================== - + def _collect_old_values(self, vals): """Collect old values before write""" return { @@ -433,7 +433,7 @@ class ProductTemplate(models.Model): } for record in self } - + def _prepare_attribute_line_info(self): """Prepare attribute line info for logging and update comparison""" line_info = {} @@ -446,7 +446,7 @@ class ProductTemplate(models.Model): 'value_names': ", ".join(line.value_ids.mapped('name')) } return line_info - + def _prepare_vendor_info(self): """Prepare vendor info for logging before they are deleted""" vendor_info = {} @@ -465,13 +465,13 @@ class ProductTemplate(models.Model): 'date_end': seller.date_end, } return vendor_info - + # ========================== - + def _get_context_with_all_info(self, vals): """Get context with all necessary info (attributes and vendors)""" context = dict(self.env.context) - + # Check for attribute line changes if 'attribute_line_ids' in vals: attribute_line_info = {} @@ -479,7 +479,7 @@ class ProductTemplate(models.Model): product_line_info = product._prepare_attribute_line_info() attribute_line_info.update(product_line_info) context['attribute_line_info'] = attribute_line_info - + # Check for vendor changes - store both for deletion and for comparing old values if 'seller_ids' in vals: vendor_info = {} @@ -488,18 +488,18 @@ class ProductTemplate(models.Model): # For deletion logging product_vendor_info = product._prepare_vendor_info() vendor_info.update(product_vendor_info) - + # For update comparison product_vendor_old = product._prepare_vendor_info() vendor_old_values.update(product_vendor_old) - + context['vendor_info'] = vendor_info context['vendor_old_values'] = vendor_old_values - + return context - + # ======================== - + def _log_image_changes(self, field_name, old_val, new_val): """Log image field changes""" label_map = { @@ -517,18 +517,18 @@ class ProductTemplate(models.Model): elif old_val != new_val: return f"
  • {label}: image updated
  • " return None - + def _log_attribute_line_changes(self, commands): """Log changes to attribute lines with complete information""" # Get stored info from context stored_info = self.env.context.get('attribute_line_info', {}) - + for cmd in commands: if cmd[0] == 0: # Add new = self.env['product.template.attribute.line'].new(cmd[2]) attribute_name = new.attribute_id.name if new.attribute_id else 'Attribute' values = ", ".join(new.value_ids.mapped('name')) if new.value_ids else '' - + message = f"Product Attribute:
    {attribute_name} added
    " if values: message += f"Values: '{values}'" @@ -537,7 +537,7 @@ class ProductTemplate(models.Model): elif cmd[0] == 1: # Update rec_id = cmd[1] vals = cmd[2] - + # Get old values from context old_data = stored_info.get(rec_id, {}) if not old_data: @@ -552,10 +552,10 @@ class ProductTemplate(models.Model): 'value_ids': [(v.id, v.name) for v in rec.value_ids], 'value_names': ", ".join(rec.value_ids.mapped('name')) } - + changes = [] attribute_name = old_data.get('attribute_name', 'Attribute') - + # Check for attribute change if 'attribute_id' in vals: old_attr = old_data.get('attribute_name', '-') @@ -567,7 +567,7 @@ class ProductTemplate(models.Model): # Check for value changes if 'value_ids' in vals: old_vals = old_data.get('value_names', '') - + # Parse the command for value_ids new_value_ids = [] for value_cmd in vals['value_ids']: @@ -579,14 +579,14 @@ class ProductTemplate(models.Model): elif value_cmd[0] == 3: # Remove # This is more complex, would need current state pass - + # Get new value names if new_value_ids: new_values = self.env['product.attribute.value'].browse(new_value_ids) new_vals = ", ".join(new_values.mapped('name')) else: new_vals = "" - + if old_vals != new_vals: changes.append(f"Values: '{old_vals}' → '{new_vals}'") @@ -596,7 +596,7 @@ class ProductTemplate(models.Model): message += "
    ".join(changes) self.message_post(body=message) - elif cmd[0] in (2, 3): # Remove + elif cmd[0] in (2, 3): # Remove # Use info from stored data line_data = stored_info.get(cmd[1]) if line_data: @@ -610,7 +610,7 @@ class ProductTemplate(models.Model): else: attribute_name = 'Attribute' values = f"ID {cmd[1]}" - + message = f"Product Attribute:
    {attribute_name} removed
    " if values: message += f"Values: '{values}'" @@ -618,25 +618,25 @@ class ProductTemplate(models.Model): elif cmd[0] == 5: # Clear all self.message_post(body=f"Product Attribute:
    All attributes removed") - + def _log_vendor_pricelist_changes(self, commands): """Log changes to vendor pricelist with complete information""" # Get stored info from context stored_info = self.env.context.get('vendor_info', {}) old_values_info = self.env.context.get('vendor_old_values', {}) - + for cmd in commands: if cmd[0] == 0: # Add vals = cmd[2] - + # Create temporary record to get proper display values temp_values = vals.copy() temp_values['product_tmpl_id'] = self.id new = self.env['product.supplierinfo'].new(temp_values) - + name = self.get_vendor_name(new) details = [] - + if 'price' in vals and vals['price'] is not None: details.append(f"
  • Price: {vals['price']}
  • ") if 'min_qty' in vals and vals['min_qty'] is not None: @@ -653,18 +653,18 @@ class ProductTemplate(models.Model): if 'product_uom' in vals and vals['product_uom']: uom = self.env['uom.uom'].browse(vals['product_uom']) details.append(f"
  • Unit of Measure: {uom.name}
  • ") - + if details: detail_str = f" with:" else: detail_str = "" - + self.message_post(body=f"Vendor Pricelist: added '{name}'{detail_str}") - + elif cmd[0] == 1: # Update rec_id = cmd[1] vals = cmd[2] - + # Get old values from context old_data = old_values_info.get(rec_id, {}) if not old_data: @@ -685,10 +685,10 @@ class ProductTemplate(models.Model): 'date_start': rec.date_start, 'date_end': rec.date_end, } - + name = old_data.get('name', f'ID {rec_id}') changes = [] - + # Check each field in vals for changes for field, new_value in vals.items(): if field == 'name': @@ -698,9 +698,9 @@ class ProductTemplate(models.Model): new_name = self.env['res.partner'].browse(new_value).name if new_value else 'None' changes.append(f"
  • Vendor: {old_name} → {new_name}
  • ") continue - + old_value = old_data.get(field) - + # Format values based on field type if field == 'currency_id': if old_value != new_value: @@ -732,14 +732,14 @@ class ProductTemplate(models.Model): # Compare numeric values properly old_num = float(old_value) if old_value is not None else 0.0 new_num = float(new_value) if new_value is not None else 0.0 - + if field == 'delay': # Integer field old_num = int(old_num) new_num = int(new_num) - + if old_num == new_num: continue - + old_str = str(old_value) if old_value is not None else 'None' new_str = str(new_value) if new_value is not None else 'None' else: @@ -748,20 +748,20 @@ class ProductTemplate(models.Model): continue old_str = str(old_value) if old_value is not None else 'None' new_str = str(new_value) if new_value is not None else 'None' - + label = self._get_vendor_field_label(field) changes.append(f"
  • {label}: {old_str} → {new_str}
  • ") - + if changes: changes_str = f"" self.message_post(body=f"Vendor Pricelist: updated '{name}':{changes_str}") - + elif cmd[0] in (2, 3): # Remove vendor_data = stored_info.get(cmd[1]) if vendor_data: name = vendor_data['name'] details = [] - + if vendor_data.get('price'): details.append(f"
  • Price: {vendor_data['price']}
  • ") if vendor_data.get('min_qty'): @@ -770,7 +770,7 @@ class ProductTemplate(models.Model): details.append(f"
  • Product Name: {vendor_data['product_name']}
  • ") if vendor_data.get('delay'): details.append(f"
  • Delivery Lead Time: {vendor_data['delay']}
  • ") - + if details: detail_str = f"" else: @@ -786,7 +786,7 @@ class ProductTemplate(models.Model): details.append(f"
  • Quantity: {rec.min_qty}
  • ") if rec.product_name: details.append(f"
  • Product Name: {rec.product_name}
  • ") - + if details: detail_str = f"" else: @@ -794,12 +794,12 @@ class ProductTemplate(models.Model): else: name = f"ID {cmd[1]}" detail_str = "" - + self.message_post(body=f"Vendor Pricelist: removed '{name}'{detail_str}") - + elif cmd[0] == 5: # Clear all self.message_post(body=f"Vendor Pricelist: all removed") - + def _log_field_changes_product(self, vals, old_values): """Revised - Log general field changes for product template without posting to variants""" exclude_fields = ['solr_flag', 'desc_update_solr', 'last_update_solr', 'is_edited'] @@ -891,7 +891,7 @@ class ProductTemplate(models.Model): # # raise UserError('Tidak dapat mengubah produk sementara') # self._log_field_changes(vals) # return super(ProductTemplate, self).write(vals) - + class ProductProduct(models.Model): _inherit = "product.product" web_price = fields.Float( @@ -929,6 +929,7 @@ class ProductProduct(models.Model): qr_code_variant = fields.Binary("QR Code Variant", compute='_compute_qr_code_variant') qty_pcs_box = fields.Float("Pcs Box") barcode_box = fields.Char("Barcode Box") + keyword_id = fields.Many2one('keywords', string='Keyword') def generate_product_sla(self): product_variant_ids = self.env.context.get('active_ids', []) @@ -951,7 +952,7 @@ class ProductProduct(models.Model): raise UserError('Hanya MD yang bisa membuat Product') result = super(ProductProduct, self).create(vals) return result - + # def write(self, values): # group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id # active_model = self.env.context.get('active_model') @@ -967,7 +968,7 @@ class ProductProduct(models.Model): if not rec.active: rec.qr_code_variant = False # Clear the QR Code for archived variants continue - + qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, @@ -1055,11 +1056,11 @@ class ProductProduct(models.Model): if self.qty_available_bandengan < qty_purchase: return 'harus beli' return 'masih cukup' - + def _get_qty_upcoming(self): for product in self: product.qty_upcoming = product.incoming_qty + product.qty_available - + def _get_qty_sold(self): for product in self: order_line = self.env['sale.order.line'].search([ @@ -1070,13 +1071,13 @@ class ProductProduct(models.Model): def day_product_to_edit(self): day_products = [] - + for product in self: day_product = (product.write_date - product.create_date).days day_products.append(day_product) return day_products - + @api.constrains('name') def _validate_name(self): rule_regex = self.env['ir.config_parameter'].sudo().get_param('product.product.rule_name_regex') or '' @@ -1085,7 +1086,7 @@ class ProductProduct(models.Model): pattern_suggest = rf"{rule_regex}" suggest = ''.join(re.findall(pattern_suggest, self.name)) raise UserError(f'Contoh yang benar adalah {suggest}') - + def _get_qty_incoming_bandengan(self): for product in self: qty = self.env['v.move.outstanding'].read_group( @@ -1207,11 +1208,11 @@ class ProductProduct(models.Model): for product in self: stock_vendor = self.env['stock.vendor'].search([('product_variant_id', '=', product.id)], limit=1) product.qty_stock_vendor = stock_vendor.quantity + product.qty_available - + def unlink(self): if self._name == 'product.product': raise UserError('Maaf anda tidak bisa delete product') - + def _get_active_flash_sale(self): current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') pricelist = self.env['product.pricelist'].search([ @@ -1237,7 +1238,7 @@ class ProductProduct(models.Model): def _log_field_changes_product_variants(self, vals, old_values): """Revised - Log field changes for variants without posting to template""" exclude_fields = ['solr_flag', 'desc_update_solr', 'last_update_solr', 'is_edited'] - + # Custom labels for image fields custom_labels = { 'image_1920': 'Main Image', @@ -1314,7 +1315,7 @@ class ProductProduct(models.Model): 'public_categ_ids', 'search_rank', 'search_rank_weekly', 'image_1920', 'unpublished', 'image_carousel_lines' ] - + if any(field in vals for field in tracked_fields): old_values = self._collect_old_values(vals) result = super().write(vals) @@ -1343,7 +1344,7 @@ class OutstandingMove(models.Model): 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, + select sm.id, sm.reference, sm.product_id, sm.product_uom_qty as qty_need, sm.location_id, sm.location_dest_id, sm.raw_material_production_id as mo_id, -- cgit v1.2.3 From 097f53b8cb0b2c39fb14f5f3a665410df2c7ebf3 Mon Sep 17 00:00:00 2001 From: Mqdd Date: Fri, 12 Dec 2025 08:55:07 +0700 Subject: done temp add product to keywords --- indoteknik_custom/models/product_template.py | 33 +++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'indoteknik_custom/models/product_template.py') diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 400d31e0..2cbef168 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -1,3 +1,4 @@ +from this import s from odoo import fields, models, api, tools, _ from datetime import datetime, timedelta, date from odoo.exceptions import UserError @@ -84,6 +85,7 @@ class ProductTemplate(models.Model): if self.env.user.id not in users_in_group.mapped('id') and active_model == None: raise UserError('Hanya MD yang bisa membuat Product') result = super(ProductTemplate, self).create(vals) + self.env['product.product']._add_product_to_keywords(result) return result # def write(self, values): @@ -883,6 +885,12 @@ class ProductTemplate(models.Model): result = super().write(vals) # Log changes self._log_field_changes_product(vals, old_values) + + # Add product to keywords + keyword_trigger = ['name', 'website_description', 'unpublished'] + if any(field in vals for field in keyword_trigger): + for product in self: + self.env['product.product']._add_product_to_keywords(product) return result # def write(self, vals): @@ -931,6 +939,24 @@ class ProductProduct(models.Model): barcode_box = fields.Char("Barcode Box") keyword_id = fields.Many2one('keywords', string='Keyword') + def _add_product_to_keywords(self,product): + keywords_model = self.env['keywords'] + if not product: + return False + + for product in self: + match_keywords = keywords_model.search([ + '|', + ('name', 'ilike', product.name), + ('keywords', 'ilike', product.website_description) + ]) + + for kw in match_keywords.filtered(lambda k: not k.skip): + if not self.unpublished and product.id not in kw.product_ids.ids: + kw.write({'product_ids': [(4, product.id)]}) + + return True + def generate_product_sla(self): product_variant_ids = self.env.context.get('active_ids', []) product_variant = self.search([('id', 'in', product_variant_ids)]) @@ -951,6 +977,7 @@ class ProductProduct(models.Model): if self.env.user.id not in users_in_group.mapped('id') and active_model == None: raise UserError('Hanya MD yang bisa membuat Product') result = super(ProductProduct, self).create(vals) + self._add_product_to_keywords(result) return result # def write(self, values): @@ -1315,7 +1342,11 @@ class ProductProduct(models.Model): 'public_categ_ids', 'search_rank', 'search_rank_weekly', 'image_1920', 'unpublished', 'image_carousel_lines' ] - + # pake ini kalau mau Cek semua field + # if vals: + trigger_fields = ['name', 'website_description', 'unpublished'] + if any(f in vals for f in trigger_fields): + self._add_product_to_keywords(vals) if any(field in vals for field in tracked_fields): old_values = self._collect_old_values(vals) result = super().write(vals) -- cgit v1.2.3