diff options
20 files changed, 319 insertions, 441 deletions
diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index 255a12f6..3a5079f6 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -81,3 +81,6 @@ from . import account_general_ledger from . import account_report_financial from . import account_report_general_ledger from . import price_group +from . import po_sync_price +from . import base_import_import +from . import product_attribute diff --git a/indoteknik_custom/models/apache_solr.py b/indoteknik_custom/models/apache_solr.py index bd4dd3dc..086fb6d0 100644 --- a/indoteknik_custom/models/apache_solr.py +++ b/indoteknik_custom/models/apache_solr.py @@ -4,7 +4,6 @@ from datetime import datetime, timedelta import logging import pysolr import time -from odoo.tools.config import config _logger = logging.getLogger(__name__) _solr = pysolr.Solr('http://10.148.0.5:8983/solr/product/', always_commit=True, timeout=30) @@ -13,26 +12,9 @@ _variants_solr = pysolr.Solr('http://10.148.0.5:8983/solr/variants/', always_com class ApacheSolr(models.Model): - _name = 'apache.solr' + _name = 'apache.solr' _order = 'id desc' - def get_single_doc(self, schema, id): - try: - return self.connect(schema).search(f'id:{id}').docs[0] - except: - return {} - - def connect(self, schema): - env = config.get('solr_env', 'development') - - url = '' - if env == 'development': - url = 'http://192.168.23.5:8983/solr/' - elif env == 'production': - url = 'http://10.148.0.5:8983/solr/' - - return pysolr.Solr(url + schema, always_commit=True, timeout=30) - def _update_stock_product_to_solr(self, limit=10000): current_time = datetime.now() delta_time = current_time - timedelta(days=3) @@ -85,67 +67,11 @@ class ApacheSolr(models.Model): _logger.info(documents) _solr.add(documents, fieldUpdates={'product_rating_f':'set'}) - def _sync_product_template_to_solr(self, limit=500): - start_time = time.time() - _logger.info('run sync to solr...') - query = ["&","&",("type","=","product"),("active","=",True),"|",("solr_flag","=",0),("solr_flag","=",2)] - - templates = self.env['product.template'].search(query, limit=limit) - documents = [] - counter = 0 - for template in templates: - template_time = time.time() - counter += 1 - variants_name = variants_code = '' - if template.product_variant_count > 1: - for variant in template.product_variant_ids: - variants_name += variant.display_name or ''+', ' - variants_code += variant.default_code or ''+', ' - - category_id = '' - category_name = '' - for category in template.public_categ_ids: - category_id = category.id - category_name = category.name - - document = { - # Start Product Template - 'id': template.id, - 'display_name_s': template.display_name, - 'name_s': template.name, - 'default_code_s': template.default_code or '', - 'product_rating_f': template.virtual_rating, - 'product_id_i': template.id, - 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', template.id), - 'variant_total_i': template.product_variant_count, - 'stock_total_f': template.qty_stock_vendor, - 'weight_f': template.weight, - 'manufacture_id_i': template.x_manufacture.id or 0, - 'manufacture_name_s': template.x_manufacture.x_name or '', - 'manufacture_name': template.x_manufacture.x_name or '', - 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', template.x_manufacture.id), - 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', template.x_manufacture.id), - 'variants_name_t': variants_name, - 'variants_code_t': variants_code, - 'search_rank_i': template.search_rank, - 'search_rank_weekly_i': template.search_rank_weekly, - 'category_id_i': category_id or 0, - 'category_name_s': category_name or '', - 'category_name': category_name or '', - # End Product Template - } - documents.append(document) - template.solr_flag = 1 - _logger.info('[SYNC_PRODUCT_TO_SOLR] {}/{} {:.6f}'.format(counter, limit, time.time() - template_time)) - _logger.info('[SYNC_PRODUCT_TO_SOLR] Success add to solr product %s' % template.id) - _solr.add(documents) - end_time = time.time() - _logger.info("[SYNC_PRODUCT_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time)) - - def _sync_product_pricelist_to_solr(self, limit=500): + def _sync_product_to_solr(self, limit=500): start_time = time.time() _logger.info('run sync to solr...') query = ["&","&",("type","=","product"),("active","=",True),"|",("solr_flag","=",0),("solr_flag","=",2)] + # query = [('id', '=', 97942)] templates = self.env['product.template'].search(query, limit=limit) documents = [] @@ -190,25 +116,51 @@ class ApacheSolr(models.Model): tier2 = template.product_variant_id._get_pricelist_tier2() tier3 = template.product_variant_id._get_pricelist_tier3() + category_id = '' + category_name = '' + for category in template.public_categ_ids: + category_id = category.id + category_name = category.name + document = { - # Start Product Pricelist + 'id': template.id, + 'display_name_s': template.display_name, + 'name_s': template.name, + 'default_code_s': template.default_code or '', + 'product_rating_f': template.virtual_rating, + 'product_id_i': template.id, + 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', template.id), + 'price_f': price_excl, + 'discount_f': discount, + 'price_discount_f': price_excl_after_disc, + 'tax_f': tax, + 'variant_total_i': template.product_variant_count, + 'stock_total_f': template.qty_stock_vendor, + 'weight_f': template.weight, + 'manufacture_id_i': template.x_manufacture.id or 0, + 'manufacture_name_s': template.x_manufacture.x_name or '', + 'manufacture_name': template.x_manufacture.x_name or '', + 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', template.x_manufacture.id), + 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', template.x_manufacture.id), + 'category_id_i': category_id or 0, + 'category_name_s': category_name or '', + 'category_name': category_name or '', + 'variants_name_t': variants_name, + 'variants_code_t': variants_code, + 'search_rank_i': template.search_rank, + 'search_rank_weekly_i': template.search_rank_weekly, 'flashsale_id_i': flashsale_data['flashsale_id'] or 0, 'flashsale_tag_s': flashsale_data['flashsale_tag'] or '', 'flashsale_name_s': flashsale_data['flashsale_name'] or '', 'flashsale_base_price_f': flashsale_data['flashsale_base_price'] or 0, 'flashsale_discount_f': flashsale_data['flashsale_discount'] or 0, 'flashsale_price_f': flashsale_data['flashsale_price'] or 0, - 'price_f': price_excl, - 'discount_f': discount, - 'price_discount_f': price_excl_after_disc, - 'tax_f': tax, 'discount_tier1_f': tier1['discount_tier1'] or 0, 'price_tier1_f': tier1['price_tier1'] or 0, 'discount_tier2_f': tier2['discount_tier2'] or 0, 'price_tier2_f': tier2['price_tier2'] or 0, 'discount_tier3_f': tier3['discount_tier3'] or 0, 'price_tier3_f': tier3['price_tier3'] or 0 - # End Product Pricelist } documents.append(document) template.solr_flag = 1 diff --git a/indoteknik_custom/models/base_import_import.py b/indoteknik_custom/models/base_import_import.py new file mode 100644 index 00000000..9cffa6e6 --- /dev/null +++ b/indoteknik_custom/models/base_import_import.py @@ -0,0 +1,55 @@ +from odoo import models +from odoo.exceptions import UserError +from datetime import datetime + +class Import(models.TransientModel): + _inherit = 'base_import.import' + + def _get_config_enable_import(self): + return self.env['ir.config_parameter'].sudo().get_param('base_import.import.enable_import', '') + + def _get_config_restrict_model(self): + return self.env['ir.config_parameter'].sudo().get_param('base_import.import.restrict_model', '') + + def _check_time_range(self, config_string): + current_time = datetime.now().time() + ranges = config_string.split(' / ') + + for time_range in ranges: + start_str, end_str = time_range.split(' - ') + start_time = datetime.strptime(start_str, '%H:%M:%S').time() + end_time = datetime.strptime(end_str, '%H:%M:%S').time() + + if start_time <= current_time and current_time <= end_time: + return True + + return False + + def _check_enable_import(self): + enable_import = self._get_config_enable_import() + restrict_model = self._get_config_restrict_model() + + if self.res_model not in restrict_model: + return True + + if enable_import.lower() == 'true': + return True + elif enable_import.lower() == 'false': + return False + elif '-' in enable_import: + return self._check_time_range(enable_import) + + return True + + def _unable_import_notif(self): + enable_import_config = self._get_config_enable_import() + message = 'Import tidak dapat dilakukan saat ini. Hubungi Tim IT.' + if '-' in enable_import_config: + message = f'Import tidak dapat dilakukan saat ini. Anda bisa melakukannya di rentang waktu berikut: {enable_import_config}.' + raise UserError(message) + + def do(self, fields, columns, options, dryrun=False): + enable_import = self._check_enable_import() + if not enable_import: + self._unable_import_notif() + return super(Import, self).do(fields, columns, options, dryrun) diff --git a/indoteknik_custom/models/po_sync_price.py b/indoteknik_custom/models/po_sync_price.py new file mode 100644 index 00000000..3e0ef621 --- /dev/null +++ b/indoteknik_custom/models/po_sync_price.py @@ -0,0 +1,14 @@ +from odoo import fields, models, api + + +class POSyncPrice(models.Model): + _name = "po.sync.price" + _description = "PO Sync Price" + + order_line_id = fields.Many2one('purchase.order.line', string='Purchase Order') + # purchase_order_id = fields.Many2one('purchase.order', string='Purchase Order') + # product_variant_id = fields.Many2one('product.product', string='Product Variant') + # manufacture_id = fields.Many2one('x_manufactures',string="Brand") + # unit_price = fields.Float(string="Unit Price") + # vendor_price = fields.Float(string="Vendor Price") + # created = fields.Datetime(string="Create Date")
\ No newline at end of file diff --git a/indoteknik_custom/models/procurement_monitoring_detail.py b/indoteknik_custom/models/procurement_monitoring_detail.py index 6031e04a..80e71304 100644 --- a/indoteknik_custom/models/procurement_monitoring_detail.py +++ b/indoteknik_custom/models/procurement_monitoring_detail.py @@ -22,6 +22,7 @@ class SaleMonitoringDetail(models.Model): date_order = fields.Datetime(string="Date Order") status = fields.Char(string="Status") po_ids = fields.Many2many('purchase.order', string='PO', compute='_compute_po') + note = fields.Char(string="Note") def _compute_po(self): for line in self: @@ -58,7 +59,8 @@ class SaleMonitoringDetail(models.Model): get_qty_available(sol.product_id) as qty_available, get_qty_reserved(so.id, sol.product_id) as qty_reserved, get_qty_po(so.id, sol.product_id) AS qty_po, - so.date_order AS date_order + so.date_order AS date_order, + sol.note_procurement as note FROM sale_order so JOIN sale_order_line sol ON sol.order_id = so.id JOIN product_product p ON p.id = sol.product_id @@ -66,7 +68,7 @@ class SaleMonitoringDetail(models.Model): WHERE pt.type IN ('consu','product') AND so.state IN ('sale','done') AND so.create_date >= '2022-08-10' - and so.so_status not in ('terproses') + and so.so_status not in('terproses') ) a --where a.qty_po < a.qty_so ) diff --git a/indoteknik_custom/models/product_attribute.py b/indoteknik_custom/models/product_attribute.py new file mode 100644 index 00000000..784ccd81 --- /dev/null +++ b/indoteknik_custom/models/product_attribute.py @@ -0,0 +1,15 @@ +from odoo import fields, models, api, _ +from odoo.exceptions import AccessError, UserError, ValidationError +import re + +class ProductAttributeValue(models.Model): + _inherit = 'product.attribute.value' + + @api.constrains('name') + def _validate_name(self): + pattern = r'^[a-zA-Z0-9\[\]\(\)\.\s/%]+$' + if not re.match(pattern, self.name): + pattern_suggest = r'[a-zA-Z0-9\[\]\(\)\.\s/%]+' + suggest = ''.join(re.findall(pattern_suggest, self.name)) + raise UserError(f'Nama hanya bisa menggunakan angka, huruf kecil, huruf besar, titik, kurung lengkung, kurung siku, garis miring. Contoh: {suggest}') +
\ No newline at end of file diff --git a/indoteknik_custom/models/product_pricelist.py b/indoteknik_custom/models/product_pricelist.py index 73eebdcf..2053accc 100644 --- a/indoteknik_custom/models/product_pricelist.py +++ b/indoteknik_custom/models/product_pricelist.py @@ -1,10 +1,8 @@ from odoo import models, fields, api from odoo.exceptions import UserError from datetime import datetime -import logging -import time -_logger = logging.getLogger(__name__) + class ProductPricelist(models.Model): _inherit = 'product.pricelist' @@ -26,125 +24,22 @@ class ProductPricelist(models.Model): remaining_time = (self.end_date - datetime.now()).total_seconds() remaining_time = round(remaining_time) return max(remaining_time, 0) + + def update_product_solr_flag(self): + for item in self.item_ids: + item.product_id.product_tmpl_id.solr_flag = 2 + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { 'title': 'Notification', 'message': f'{len(self.item_ids)} produk akan diupdate ke SOLR' } + } class ProductPricelistItem(models.Model): _inherit = 'product.pricelist.item' manufacture_id = fields.Many2one('x_manufactures', string='Manufacture') - @api.constrains('applied_on', 'product_id', 'base', 'base_pricelist_id', 'price_discount') - def _constrains_related_solr_field(self): - self.update_template_solr() - self.update_variant_solr() - - def update_template_solr(self): - price_excl_after_disc = price_excl = discount = tax = 0 - flashsale_data = tier1 = tier2 = tier3 = {} - - template = self.product_id.product_tmpl_id - if template.product_variant_count > 1: - for variant in template.product_variant_ids: - if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: - price_excl = variant._get_website_price_exclude_tax() - price_excl_after_disc = variant._get_website_price_after_disc_and_tax() - discount = variant._get_website_disc(0) - tax = variant._get_website_tax() - flashsale_data = variant._get_flashsale_price() - # add price tiering for base price, discount, and price after discount (tier 1 - 3) - tier1 = variant._get_pricelist_tier1() - tier2 = variant._get_pricelist_tier2() - tier3 = variant._get_pricelist_tier3() - else: - price_excl_after_disc = price_excl_after_disc - price_excl = price_excl - discount = discount - tax = tax - flashsale_data = flashsale_data - tier1 = tier1 - tier2 = tier2 - tier3 = tier3 - else: - price_excl = template.product_variant_id._get_website_price_exclude_tax() - discount = template.product_variant_id._get_website_disc(0) - price_excl_after_disc = template.product_variant_id._get_website_price_after_disc_and_tax() - tax = template.product_variant_id._get_website_tax() - flashsale_data = template.product_variant_id._get_flashsale_price() - tier1 = template.product_variant_id._get_pricelist_tier1() - tier2 = template.product_variant_id._get_pricelist_tier2() - tier3 = template.product_variant_id._get_pricelist_tier3() - - solr_model = self.env['apache.solr'] - solr = solr_model.connect('product') - document = solr_model.get_single_doc('product', template.id) - document.update({ - 'id': template.id, - 'flashsale_id_i': flashsale_data['flashsale_id'] or 0, - 'flashsale_tag_s': flashsale_data['flashsale_tag'] or '', - 'flashsale_name_s': flashsale_data['flashsale_name'] or '', - 'flashsale_base_price_f': flashsale_data['flashsale_base_price'] or 0, - 'flashsale_discount_f': flashsale_data['flashsale_discount'] or 0, - 'flashsale_price_f': flashsale_data['flashsale_price'] or 0, - 'price_f': price_excl, - 'discount_f': discount, - 'price_discount_f': price_excl_after_disc, - 'tax_f': tax, - 'discount_tier1_f': tier1['discount_tier1'] or 0, - 'price_tier1_f': tier1['price_tier1'] or 0, - 'discount_tier2_f': tier2['discount_tier2'] or 0, - 'price_tier2_f': tier2['price_tier2'] or 0, - 'discount_tier3_f': tier3['discount_tier3'] or 0, - 'price_tier3_f': tier3['price_tier3'] or 0 - }) - solr.add([document]) - template.change_solr_data('Ada perubahan pada harga product') - - def update_variant_solr(self): - price_excl_after_disc = price_excl = discount = tax = 0 - flashsale_data = tier1 = tier2 = tier3 = {} - - product = self.product_id - for variant in product: - if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: - price_excl = variant._get_website_price_exclude_tax() - price_excl_after_disc = variant._get_website_price_after_disc_and_tax() - discount = variant._get_website_disc(0) - tax = variant._get_website_tax() - flashsale_data = variant._get_flashsale_price() - # add price tiering for base price, discount, and price after discount (tier 1 - 3) - tier1 = variant._get_pricelist_tier1() - tier2 = variant._get_pricelist_tier2() - tier3 = variant._get_pricelist_tier3() - else: - price_excl_after_disc = price_excl_after_disc - price_excl = price_excl - discount = discount - tax = tax - flashsale_data = flashsale_data - tier1 = tier1 - tier2 = tier2 - tier3 = tier3 - - solr_model = self.env['apache.solr'] - solr = solr_model.connect('variants') - document = solr_model.get_single_doc('variants', product.id) - document.update({ - 'id': product.id, - 'flashsale_id_i': flashsale_data['flashsale_id'] or 0, - 'flashsale_tag_s': flashsale_data['flashsale_tag'] or '', - 'flashsale_name_s': flashsale_data['flashsale_name'] or '', - 'flashsale_base_price_f': flashsale_data['flashsale_base_price'] or 0, - 'flashsale_discount_f': flashsale_data['flashsale_discount'] or 0, - 'flashsale_price_f': flashsale_data['flashsale_price'] or 0, - 'price_f': price_excl, - 'discount_f': discount, - 'price_discount_f': price_excl_after_disc, - 'tax_f': tax, - 'discount_tier1_f': tier1['discount_tier1'] or 0, - 'price_tier1_f': tier1['price_tier1'] or 0, - 'discount_tier2_f': tier2['discount_tier2'] or 0, - 'price_tier2_f': tier2['price_tier2'] or 0, - 'discount_tier3_f': tier3['discount_tier3'] or 0, - 'price_tier3_f': tier3['price_tier3'] or 0 - }) - solr.add([document]) - product.change_solr_data('Ada perubahan pada harga product')
\ No newline at end of file + @api.constrains('fixed_price','price_discount') + def update_product_solr_flag(self): + for item in self: + item.product_id.product_tmpl_id.solr_flag = 2
\ No newline at end of file diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 3caa3125..52f72729 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -1,9 +1,10 @@ from odoo import fields, models, api -from datetime import datetime, timedelta, timezone +from datetime import datetime, timedelta from odoo.exceptions import AccessError, UserError, ValidationError import logging import requests import json +import re _logger = logging.getLogger(__name__) @@ -50,13 +51,19 @@ class ProductTemplate(models.Model): is_new_product = fields.Boolean(string='Produk Baru', help='Centang jika ingin ditammpilkan di website sebagai segment Produk Baru') seq_new_product = fields.Integer(string='Seq New Product', help='Urutan Sequence New Product') - last_update_solr = fields.Datetime(string='Last Update Solr') - desc_update_solr = fields.Char(string='Desc Update Solr') - def change_solr_data(self, desc): - current_time = datetime.utcnow() - self.desc_update_solr = desc - self.last_update_solr = current_time + @api.constrains('name') + def _validate_name(self): + pattern = r'^[a-zA-Z0-9\[\]\(\)\.\s/%]+$' + if not re.match(pattern, self.name): + pattern_suggest = r'[a-zA-Z0-9\[\]\(\)\.\s/%]+' + suggest = ''.join(re.findall(pattern_suggest, self.name)) + raise UserError(f'Nama hanya bisa menggunakan angka, huruf kecil, huruf besar, titik, kurung lengkung, kurung siku, garis miring. Contoh: {suggest}') + + # def write(self, vals): + # if 'solr_flag' not in vals and self.solr_flag == 1: + # vals['solr_flag'] = 2 + # return super().write(vals) def _compute_virtual_rating(self): for product in self: @@ -121,6 +128,12 @@ class ProductTemplate(models.Model): product.default_code = 'ITV.'+str(product.id) _logger.info('Updated Variant %s' % product.name) + @api.onchange('name','default_code','x_manufacture','product_rating','website_description','image_1920','weight','public_categ_ids') + def update_solr_flag(self): + for tmpl in self: + if tmpl.solr_flag == 1: + tmpl.solr_flag = 2 + def _compute_qty_stock_vendor(self): for product_template in self: product_template.qty_stock_vendor = 0 @@ -252,62 +265,7 @@ class ProductTemplate(models.Model): self.env['token.storage'].create([values]) return values - @api.constrains( - 'name', - 'default_code', - 'weight', - 'x_manufacture', - 'public_categ_ids', - 'product_variant_ids.display_name', - 'product_variant_ids.default_code', - 'search_rank', - 'search_rank_weekly', - 'image_1920' - ) - def _sync_product_template_to_solr(self, limit=500): - template = self - if not template.active or template.type != 'product': - return - - variant_names = ', '.join([x.display_name or '' for x in template.product_variant_ids]) - variant_codes = ', '.join([x.default_code or '' for x in template.product_variant_ids]) - - category_id = 0 - category_name = '' - for category in template.public_categ_ids: - category_id, category_name = category.id, category.name - break - - solr_model = self.env['apache.solr'] - solr = solr_model.connect('product') - document = solr_model.get_single_doc('product', template.id) - document.update({ - 'id': template.id, - 'display_name_s': template.display_name, - 'name_s': template.name, - 'default_code_s': template.default_code or '', - 'product_rating_f': template.virtual_rating, - 'product_id_i': template.id, - 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', template.id), - 'variant_total_i': template.product_variant_count, - 'stock_total_f': template.qty_stock_vendor, - 'weight_f': template.weight, - 'manufacture_id_i': template.x_manufacture.id or 0, - 'manufacture_name_s': template.x_manufacture.x_name or '', - 'manufacture_name': template.x_manufacture.x_name or '', - 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', template.x_manufacture.id), - 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', template.x_manufacture.id), - 'variants_name_t': variant_names, - 'variants_code_t': variant_codes, - 'search_rank_i': template.search_rank, - 'search_rank_weekly_i': template.search_rank_weekly, - 'category_id_i': category_id, - 'category_name_s': category_name, - 'category_name': category_name, - }) - solr.add([document]) - self.change_solr_data('Perubahan pada data product') - + class ProductProduct(models.Model): _inherit = "product.product" web_price = fields.Float( @@ -329,13 +287,14 @@ class ProductProduct(models.Model): qty_onhand_bandengan = fields.Float(string='Qty Incoming Bandengan', compute='_get_qty_onhand_bandengan') qty_incoming_bandengan = fields.Float(string='Qty Incoming Bandengan', compute='_get_qty_incoming_bandengan') sla_version = fields.Integer(string="SLA Version", default=0) - last_update_solr = fields.Datetime(string='Last Update Solr') - desc_update_solr = fields.Char(string='Desc Update Solr') - def change_solr_data(self, desc): - current_time = datetime.now() - self.desc_update_solr = desc - self.last_update_solr = current_time + @api.constrains('name') + def _validate_name(self): + pattern = r'^[a-zA-Z0-9\[\]\(\)\.\s/%]+$' + if not re.match(pattern, self.name): + pattern_suggest = r'[a-zA-Z0-9\[\]\(\)\.\s/%]+' + suggest = ''.join(re.findall(pattern_suggest, self.name)) + raise UserError(f'Nama hanya bisa menggunakan angka, huruf kecil, huruf besar, titik, kurung lengkung, kurung siku, garis miring. Contoh: {suggest}') def _get_qty_incoming_bandengan(self): for product in self: @@ -356,6 +315,14 @@ class ProductProduct(models.Model): qty = sum(qty_onhand.mapped('quantity')) product.qty_onhand_bandengan = qty + # def write(self, vals): + # if 'solr_flag' not in vals: + # for variant in self: + # if variant.solr_flag == 1: + # variant.product_tmpl_id.solr_flag = 2 + # vals['solr_flag'] = 2 + # return super().write(vals) + def _compute_web_price(self): for product in self: product_pricelist_item = self.env['product.pricelist.item'].search( @@ -379,57 +346,4 @@ class ProductProduct(models.Model): ('start_date', '<=', current_time), ('end_date', '>=', current_time) ], limit=1) - return pricelist - - @api.constrains( - 'name', - 'default_code', - 'virtual_rating', - 'weight', - 'x_manufacture', - 'public_categ_ids', - 'product_tmpl_id.default_code', - 'product_tmpl_id.image_1920', - 'search_rank', - 'search_rank_weekly', - 'image_1920' - ) - def _sync_variants_to_solr(self): - variant = self - if not variant.product_tmpl_id.active and variant.product_tmpl_id.type != 'product': - return - - category_id = 0 - category_name = '' - for category in variant.product_tmpl_id.public_categ_ids: - category_id = category.id - category_name = category.name - break - - solr_model = self.env['apache.solr'] - solr = solr_model.connect('variants') - document = solr_model.get_single_doc('variants', variant.id) - document.update({ - 'id': variant.id, - 'display_name_s': variant.display_name, - 'name_s': variant.name, - 'default_code_s': variant.default_code or '', - 'product_rating_f': variant.product_tmpl_id.virtual_rating, - 'product_id_i': variant.id, - 'template_id_i': variant.product_tmpl_id.id, - 'image_s': self.env['ir.attachment'].api_image('product.template', 'image_512', variant.product_tmpl_id.id), - 'stock_total_f': variant.qty_stock_vendor, - 'weight_f': variant.product_tmpl_id.weight, - 'manufacture_id_i': variant.product_tmpl_id.x_manufacture.id or 0, - 'manufacture_name_s': variant.product_tmpl_id.x_manufacture.x_name or '', - 'manufacture_name': variant.product_tmpl_id.x_manufacture.x_name or '', - 'image_promotion_1_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', variant.product_tmpl_id.x_manufacture.id), - 'image_promotion_2_s': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', variant.product_tmpl_id.x_manufacture.id), - 'category_id_i': category_id, - 'category_name_s': category_name, - 'category_name': category_name, - 'search_rank_i': variant.product_tmpl_id.search_rank, - 'search_rank_weekly_i': variant.product_tmpl_id.search_rank_weekly, - }) - solr.add([document]) - self.change_solr_data('Perubahan pada data product')
\ No newline at end of file + return pricelist
\ No newline at end of file diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index c968ed53..3fb61955 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -2,7 +2,13 @@ from odoo import fields, models, api, _ from odoo.exceptions import AccessError, UserError, ValidationError from datetime import datetime, timedelta import logging -from pytz import timezone +from pytz import timezone, utc +import io +import base64 +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter _logger = logging.getLogger(__name__) @@ -43,7 +49,7 @@ class PurchaseOrder(models.Model): def add_product_to_pricelist(self): for line in self.order_line: - current_time = fields.Datetime.now(timezone('Asia/Jakarta')).strftime('%Y-%m-%d %H:%M:%S') + current_time = datetime.utcnow() purchase_pricelist = self.env['purchase.pricelist'].search([ ('product_id', '=', line.product_id.id), @@ -224,7 +230,8 @@ class PurchaseOrder(models.Model): raise UserError("Terdapat barang yang tidak bisa diproses") if line.product_id: self.add_product_to_pricelist() - if line.price_unit != line.price_vendor: + if line.price_unit != line.price_vendor and line.price_vendor != 0: + self._send_po_not_sync() send_email = True break @@ -244,9 +251,67 @@ class PurchaseOrder(models.Model): return res + def _send_po_not_sync(self): + # Mengirim data ke model Po Sync Price jika harga po dan purchase pricelist tidak singkron + for line in self.order_line: + if line.price_unit != line.price_vendor and line.price_vendor != 0: + self.env['po.sync.price'].create([{ + 'order_line_id': line.id, + }]) + + + def _send_mail(self): - template_id = self.env.ref('indoteknik_custom.mail_template_po_sync_price').id - template = self.env['mail.template'].browse(template_id) + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + worksheet = workbook.add_worksheet() + + format6 = workbook.add_format({'font_size': 12, 'align': 'center', 'bg_color': '#D3D3D3', 'bold': True}) + format1 = workbook.add_format({'font_size': 11, 'align': 'center', 'valign': 'vcenter'}) + + worksheet.set_column(0, 0, 10) + worksheet.set_column(1, 1, 20) + worksheet.set_column(2, 2, 20) + worksheet.set_column(3, 3, 20) + worksheet.set_column(4, 4, 15) + worksheet.set_column(5, 5, 15) + + worksheet.write('A1', 'PO', format6) + worksheet.write('B1', 'SKU', format6) + worksheet.write('C1', 'Product', format6) + worksheet.write('D1', 'Brand', format6) + worksheet.write('E1', 'PO Price', format6) + worksheet.write('F1', 'Purchase Pricelist', format6) + worksheet.write('G1', 'Created On', format6) + + row_number = 1 + po_sync = self.env['po.sync.price'].search([], order='create_date desc') + for po in po_sync: + worksheet.write(row_number, 0, po.order_line_id.order_id.name, format1) + worksheet.write(row_number, 1, po.order_line_id.product_id.default_code, format1) + worksheet.write(row_number, 2, po.order_line_id.product_id.name, format1) + worksheet.write(row_number, 3, po.order_line_id.product_id.x_manufacture.x_name, format1) + worksheet.write(row_number, 4, po.order_line_id.price_unit, format1) + worksheet.write(row_number, 5, po.order_line_id.price_vendor, format1) + worksheet.write(row_number, 6, po.create_date.replace(tzinfo=utc).astimezone(timezone('Asia/Jakarta')).strftime('%Y-%m-%d %H:%M:%S'), format1) + row_number += 1 + + workbook.close() + + output.seek(0) + + template = self.env.ref('indoteknik_custom.mail_template_po_sync_price') + template.attachment_ids.unlink() + attachment_vals = { + 'name': 'Purchase Order.xlsx', + 'datas': base64.b64encode(output.read()), + 'mimetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'res_model': 'mail.template', + 'res_id': template.id, + } + attachment_id = self.env['ir.attachment'].create(attachment_vals) + + template.attachment_ids = [(4, attachment_id.id)] template.send_mail(self.id, force_send=True) def po_approve(self): diff --git a/indoteknik_custom/models/sale_monitoring_detail.py b/indoteknik_custom/models/sale_monitoring_detail.py index 43a8aeb0..dc4caa14 100755 --- a/indoteknik_custom/models/sale_monitoring_detail.py +++ b/indoteknik_custom/models/sale_monitoring_detail.py @@ -55,7 +55,7 @@ class SaleMonitoringDetail(models.Model): get_qty_received(so.id, sol.product_id) AS qty_po_received, get_qty_reserved(so.id, sol.product_id) as qty_reserved, sol.note_procurement as note - FROM sale_order so + FROM sale_order so JOIN sale_order_line sol ON sol.order_id = so.id JOIN product_product p ON p.id = sol.product_id JOIN product_template pt ON pt.id = p.product_tmpl_id diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index ca98cde4..a0bc54b8 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -1,6 +1,6 @@ from odoo import fields, models, api, _ from odoo.exceptions import UserError -import logging, random, string, requests, math, json, re +import logging, random, string, requests, math, json, re _logger = logging.getLogger(__name__) @@ -342,7 +342,7 @@ class SaleOrder(models.Model): return { 'type': 'ir.actions.client', 'tag': 'display_notification', - 'params': { 'title': title, 'message': message } + 'params': { 'title': title, 'message': message, 'next': {'type': 'ir.actions.act_window_close'} }, } def _set_sppkp_npwp_contact(self): diff --git a/indoteknik_custom/models/stock_vendor.py b/indoteknik_custom/models/stock_vendor.py index 075b63d2..f214a5e1 100755 --- a/indoteknik_custom/models/stock_vendor.py +++ b/indoteknik_custom/models/stock_vendor.py @@ -50,3 +50,9 @@ class StockVendor(models.Model): for template in templates: template.virtual_qty = template.qty_stock_vendor or 0 _logger.info("Update Stock Product Template %s : %s" % (template.id, template.virtual_qty)) + + # @api.onchange('quantity') + # def update_solr_flag(self): + # for stock in self: + # if stock.product_variant_id.product_tmpl_id.solr_flag == 1: + # stock.product_variant_id.product_tmpl_id.solr_flag = 2 diff --git a/indoteknik_custom/models/website_categories_homepage.py b/indoteknik_custom/models/website_categories_homepage.py index 2f5b3d92..a0fc1011 100644 --- a/indoteknik_custom/models/website_categories_homepage.py +++ b/indoteknik_custom/models/website_categories_homepage.py @@ -1,5 +1,4 @@ -from odoo import fields, models, api -import json +from odoo import fields, models class WebsiteCategoriesHomepage(models.Model): @@ -14,31 +13,4 @@ class WebsiteCategoriesHomepage(models.Model): ('tayang', 'Tayang'), ('tidak_tayang', 'Tidak Tayang') ], string='Status') - product_ids = fields.Many2many('product.template', string='Product category') - - - @api.constrains('category_id', 'image', 'url', 'sequence', 'status', 'product_ids') - def _sync_category_homepage_to_solr(self): - solr_model = self.env['apache.solr'] - solr = solr_model.connect('product_category_homepage') - - for category in self: - document = solr_model.get_single_doc(solr, category.id) - result = [self.env['product.template'].api_single_response(x) for x in category.product_ids] - products = json.dumps(result, indent=None) - - document.update({ - 'id': category.id, - 'category_id_i': category.category_id.id, - 'name_s': category.category_id.name, - 'image_s': self.env['ir.attachment'].api_image('website.categories.homepage', 'image', category.id), - 'sequence_i': category.sequence or '', - 'url_s': category.url or '', - 'products_s': products, - }) - solr.add([document]) - - def sync_to_solr(self): - categories_ids = self.env.context.get('active_ids', []) - categories = self.env['website.categories.homepage'].search([('id', 'in', categories_ids)]) - categories._sync_category_homepage_to_solr() + product_ids = fields.Many2many('product.template', string='Product Template') diff --git a/indoteknik_custom/models/x_manufactures.py b/indoteknik_custom/models/x_manufactures.py index 1d0870a5..e48a5367 100755 --- a/indoteknik_custom/models/x_manufactures.py +++ b/indoteknik_custom/models/x_manufactures.py @@ -72,3 +72,13 @@ class XManufactures(models.Model): variant.solr_flag = 2 _logger.info("Reset Solr Flag variant to 2 %s" % variant.id) manufacture.cache_reset_status = 'done' + + @api.onchange('x_name','image_promotion_1','image_promotion_2') + def update_solr_flag(self): + for manufacture in self: + templates = self.env['product.template'].search([ + ('x_manufacture', '=', manufacture.id) + ]) + for template in templates: + if template.solr_flag == 1: + template.solr_flag = 2 diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 6f9ba9e4..c5dbdb19 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -67,3 +67,5 @@ access_account_move_multi_update,access.account.move.multi_update,model_account_ access_airway_bill,access.airway.bill,model_airway_bill,,1,1,1,1 access_airway_bill_manifest,access.airway.bill.manifest,model_airway_bill_manifest,,1,1,1,1 access_price_group,access.price.group,model_price_group,,1,1,1,1 +access_po_sync_price,access.po.sync.price,model_po_sync_price,,1,1,1,1 +access_product_attribute_value,access.product.attribute.value,model_product_attribute_value,,1,1,1,1 diff --git a/indoteknik_custom/views/mail_template_po.xml b/indoteknik_custom/views/mail_template_po.xml index 02053767..f4eb3577 100644 --- a/indoteknik_custom/views/mail_template_po.xml +++ b/indoteknik_custom/views/mail_template_po.xml @@ -12,69 +12,43 @@ style="padding-top: 16px; background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"> <tr> <td align="center"> - <table border="0" cellpadding="0" cellspacing="0" width="590" - style="padding: 16px; background-color: white; color: #454748; border-collapse:separate;"> - <tbody> - <!-- HEADER --> - <tr> - <td align="center" style="min-width: 590px;"> - <table border="0" cellpadding="0" cellspacing="0" width="590" - style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> - <tr> - <td valign="middle"> - <span style="font-size: 10px;">PO</span><br /> - <span style="font-size: 20px; font-weight: bold;"> - ${object.name} - </span> - </td> - </tr> - <tr> - <td colspan="2" style="text-align:center;"> - <hr width="100%" - style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> - </td> - </tr> - </table> - </td> - </tr> - <!-- CONTENT --> - <tr> - <td align="center" style="min-width: 590px;"> - <table border="0" cellpadding="0" cellspacing="0" width="590" - style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"> - <tr> - <td valign="top" style="font-size: 13px;"> - <div> - Dear Stefanus Darren & Tyas K Putra, - <br/><br/> - Terdapat PO yang harga Unit Price nya tidak sama dengan yang ada di purchase pricelist nya. - <br/><br/> - Berikut adalah rincian PO: - % for line in object.order_line: - % if line.price_unit != line.price_vendor - <ul> - <li>Nama Produk: ${line.product_id.name}</li> - <li>Harga Unit dalam PO: Rp ${'{:,.2f}'.format(line.price_unit)}</li> - <li>Harga Unit dalam Purchase Pricelist: Rp ${'{:,.2f}'.format(line.price_vendor)}</li> - </ul> - % endif - % endfor - Silahkan periksa dan lakukan koreksi jika diperlukan. - <br/><br/> - Terima kasih. - </div> - </td> - </tr> - <tr> - <td style="text-align:center;"> - <hr width="100%" - style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 16px 0px;" /> - </td> - </tr> - </table> - </td> - </tr> - </tbody> + <table border="0" cellpadding="0" cellspacing="0" width="100%" + style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse: separate;"> + <tr> + <td valign="top" style="font-size: 13px;"> + <div> + Dear Stefanus Darren & Tyas K Putra, + <br /><br /> + Terdapat PO yang harga Unit Price nya tidak sama dengan yang ada di purchase pricelist nya. + <br /><br /> + Berikut adalah rincian PO: + </div> + <table border="1" cellpadding="5" cellspacing="0" + style="border-collapse: collapse; width: 100%; font-size: 13px;"> + <tr> + <th>Nama Produk</th> + <th>Brand</th> + <th>Harga Unit dalam PO</th> + <th>Harga Unit dalam Purchase Pricelist</th> + </tr> + % for line in object.order_line: + % if line.price_vendor != 0 and line.price_unit != line.price_vendor + <tr> + <td>${line.product_id.name}</td> + <td>${line.product_id.x_manufacture.x_name}</td> + <td>Rp ${'{:,.2f}'.format(line.price_unit)}</td> + <td>Rp ${'{:,.2f}'.format(line.price_vendor)}</td> + </tr> + % endif + % endfor + </table> + <div> + Silahkan periksa dan lakukan koreksi jika diperlukan. + <br /><br /> + Terima kasih. + </div> + </td> + </tr> </table> </td> </tr> diff --git a/indoteknik_custom/views/procurement_monitoring_detail.xml b/indoteknik_custom/views/procurement_monitoring_detail.xml index 8f3827c1..e4939213 100644 --- a/indoteknik_custom/views/procurement_monitoring_detail.xml +++ b/indoteknik_custom/views/procurement_monitoring_detail.xml @@ -17,10 +17,11 @@ <field name="po_ids" widget="many2many_tags"/> <field name="qty_po"/> <field name="status" - widget="badge" - decoration-danger="status == 'harus beli'" - decoration-success="status == 'cukup'" + widget="badge" + decoration-danger="status == 'harus beli'" + decoration-success="status == 'cukup'" /> + <field name="note" optional="hide"/> </tree> </field> </record> diff --git a/indoteknik_custom/views/product_pricelist.xml b/indoteknik_custom/views/product_pricelist.xml index 55139a24..34876cc4 100644 --- a/indoteknik_custom/views/product_pricelist.xml +++ b/indoteknik_custom/views/product_pricelist.xml @@ -25,4 +25,12 @@ </page> </field> </record> + + <record id="product_pricelist_sync_product_solr_ir_actions_server" model="ir.actions.server"> + <field name="name">Sync Product to SOLR</field> + <field name="model_id" ref="product.model_product_pricelist"/> + <field name="binding_model_id" ref="product.model_product_pricelist"/> + <field name="state">code</field> + <field name="code">action = records.update_product_solr_flag()</field> + </record> </odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml index 82b7ce4d..558805b1 100755 --- a/indoteknik_custom/views/product_template.xml +++ b/indoteknik_custom/views/product_template.xml @@ -9,8 +9,6 @@ <field name="categ_id" position="after"> <field name="web_tax_id"/> <field name="x_manufacture"/> - <field name="desc_update_solr"/> - <field name="last_update_solr"/> <field name="x_model_product"/> <field name="x_studio_field_tGhJR" widget="many2many_tags"/> </field> diff --git a/indoteknik_custom/views/website_categories_homepage.xml b/indoteknik_custom/views/website_categories_homepage.xml index 0a3f684b..0a7ef2c2 100644 --- a/indoteknik_custom/views/website_categories_homepage.xml +++ b/indoteknik_custom/views/website_categories_homepage.xml @@ -49,14 +49,6 @@ </field> </record> - <record id="website_categories_homepage_ir_actions_server" model="ir.actions.server"> - <field name="name">Sync To Solr</field> - <field name="model_id" ref="indoteknik_custom.model_website_categories_homepage"/> - <field name="binding_model_id" ref="indoteknik_custom.model_website_categories_homepage"/> - <field name="state">code</field> - <field name="code">model.sync_to_solr()</field> - </record> - <menuitem id="website_categories_homepage" name="Website Categories Homepage" |
