from .. import controller from odoo import http from odoo.http import request, Response from datetime import datetime, timedelta import pytz import ast import logging import math import json _logger = logging.getLogger(__name__) class Product(controller.Controller): prefix = '/api/v1/' @http.route(prefix + 'product//category-breadcrumb', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_product_categories_by_id(self, id, **kw): categories = [] product = request.env['product.template'].search( [('id', '=', int(id))], limit=1) if not product: return self.response(code=400, description='Product not found') if len(product.public_categ_ids) == 0: return self.response(categories) category = product.public_categ_ids[0] while category: categories.append({'id': category.id, 'name': category.name}) category = category.parent_id categories.reverse() return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')]) @http.route(prefix + 'product/variants/sla', auth='public', methods=['POST', 'OPTIONS'] , csrf=False) @controller.Controller.must_authorized() def get_product_template_sla_by_id(self, **kwargs): raw_data = kwargs.get('products', '[]') product_data = json.loads(raw_data) product_ids = [int(item["id"]) for item in product_data] products = request.env['purchase.pricelist'].search([ ('product_id', 'in', product_ids), ('is_winner', '=', True) ]) jakarta = pytz.timezone("Asia/Jakarta") start_date = datetime.now(jakarta) offset, is3pm = request.env['sale.order'].get_days_until_next_business_day(start_date) additional_days = offset include_instant = True if(len(products) == len(product_ids)): products_data_params = {product["id"] : product for product in product_data } all_fast_products = all( product.product_id.qty_free_bandengan >= products_data_params.get(product.product_id.id, {}).get("quantity", 0) for product in products ) if all_fast_products: return self.response({ 'include_instant': include_instant, 'sla_duration': 1, 'sla_additional_days': int(additional_days), 'sla_total' : int(additional_days), 'sla_unit': 'Hari' }) max_slatime = 1 for vendor in products: vendor_sla = request.env['vendor.sla'].search([('id_vendor', '=', vendor.vendor_id.id)], limit=1) slatime = 15 if vendor_sla: if vendor_sla.unit == 'hari': vendor_duration = vendor_sla.duration * 24 * 60 include_instant = False else : vendor_duration = vendor_sla.duration * 60 include_instant = True estimation_sla = (1 * 24 * 60) + vendor_duration estimation_sla_days = estimation_sla / (24 * 60) slatime = math.ceil(estimation_sla_days) max_slatime = max(max_slatime, slatime) return self.response({ 'include_instant': include_instant, 'sla_duration': max_slatime, 'sla_additional_days': additional_days, 'sla_total' : int(max_slatime) + int(additional_days), 'sla_unit': 'Hari' }) @http.route(prefix + 'product_variant//stock', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_product_template_stock_by_id(self, **kw): id = int(kw.get('id')) # date_7_days_ago = datetime.now() - timedelta(days=7) product = request.env['product.product'].search([('id', '=', id)], limit=1) if not product: return self.response({'qty': 0, 'sla_date': 'N/A'}, headers=[('Cache-Control', 'max-age=600, private')]) product_pruchase = request.env['purchase.pricelist'].search([ ('product_id', '=', id), ('is_winner', '=', True) ], limit=1) # stock_vendor = request.env['stock.vendor'].search([ # ('product_variant_id', '=', id), # ('write_date', '>=', date_7_days_ago.strftime("%Y-%m-%d %H:%M:%S")) # ], limit=1) # product = product_pruchase.product_id vendor_sla = request.env['vendor.sla'].search([('id_vendor', '=', product_pruchase.vendor_id.id)], limit=1) slatime = 15 if vendor_sla: if vendor_sla.unit == 'hari': vendor_duration = vendor_sla.duration * 24 * 60 else : vendor_duration = vendor_sla.duration * 60 estimation_sla = (1 * 24 * 60) + vendor_duration estimation_sla_days = estimation_sla / (24 * 60) slatime = math.ceil(estimation_sla_days) qty_available = product.qty_free_bandengan if qty_available < 1 : qty_available = 0 # qty = 0 qty = qty_available sla_date = f'{slatime} Hari' if qty_available > 0: sla_date = '1 Hari' # Qty Stock Vendor # qty_vendor = stock_vendor.quantity # qty_vendor -= int(qty_vendor * 0.1) # qty_vendor = math.ceil(float(qty_vendor)) # total_excell = qty_vendor # is_altama_product = product.x_manufacture.id in [10, 122, 89] # if is_altama_product: # try: # # Qty Altama # qty_altama = request.env['product.template'].get_stock_altama( # product.default_code) # qty_altama -= int(qty_altama * 0.1) # qty_altama = math.ceil(float(qty_altama)) # total_adem = qty_altama # if qty_available > 0: # qty = qty_available + total_adem + total_excell # sla_date = '1 Hari' # elif qty_altama > 0 or qty_vendor > 0: # qty = total_adem if qty_altama > 0 else total_excell # sla_date = f'{slatime} Hari' # else: # sla_date = f'{slatime} Hari' # except: # print('error') # else: # if qty_available > 0: # qty = qty_available # sla_date = f'1 Hari' # elif qty_vendor > 0: # qty = total_excell # sla_date = f'{slatime} Hari' data = { 'qty': qty, 'sla_date': sla_date } return self.response(data, headers=[('Cache-Control', 'max-age=600, private')]) # def get_product_template_stock_by_id(self, **kw): # id = int(kw.get('id')) # date_7_days_ago = datetime.now() - timedelta(days=7) # product = request.env['product.product'].search( # [('id', '=', id)], limit=1) # product_sla = request.env['product.sla'].search( # [('product_variant_id', '=', id)], limit=1) # stock_vendor = request.env['stock.vendor'].search([ # ('product_variant_id', '=', id), # ('write_date', '>=', date_7_days_ago.strftime("%Y-%m-%d %H:%M:%S")) # ], limit=1) # qty_available = product.qty_free_bandengan # if qty_available < 1 : # qty_available = 0 # qty = 0 # sla_date = '-' # # Qty Stock Vendor # qty_vendor = stock_vendor.quantity # qty_vendor -= int(qty_vendor * 0.1) # qty_vendor = math.ceil(float(qty_vendor)) # total_excell = qty_vendor # is_altama_product = product.x_manufacture.id in [10, 122, 89] # if is_altama_product: # try: # # Qty Altama # qty_altama = request.env['product.template'].get_stock_altama( # product.default_code) # qty_altama -= int(qty_altama * 0.1) # qty_altama = math.ceil(float(qty_altama)) # total_adem = qty_altama # if qty_available > 0: # qty = qty_available + total_adem + total_excell # sla_date = product_sla.sla or 1 # elif qty_altama > 0 or qty_vendor > 0: # qty = total_adem if qty_altama > 0 else total_excell # sla_date = product_sla.sla # else: # sla_date = product_sla.sla # except: # print('error') # else: # if qty_available > 0: # qty = qty_available # sla_date = product_sla.sla or 'Indent' # elif qty_vendor > 0: # qty = total_excell # sla_date = '2-4 Hari' # data = { # 'qty': qty, # 'sla_date': sla_date # } # return self.response(data, headers=[('Cache-Control', 'max-age=600, private')]) @http.route(prefix + 'product_variant//qty_available', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_product_variant_stock_available_by_id(self, **kw): id = int(kw.get('id')) product = request.env['product.product'].search( [('id', '=', id)], limit=1) qty_available = product.qty_free_bandengan if qty_available < 1: qty_available = 0 data = { 'qty': qty_available, } return self.response(data, headers=[('Cache-Control', 'max-age=600, private')]) @http.route(prefix + 'product/template/price/', auth='public', methods=['GET', 'OPTIONS']) def get_product_template_price_by_id(self, **kw): if not self.authenticate(): return self.response(code=401, description='Unauthorized') id = kw.get('id') partner_id = int(kw.get('partner_id', 0)) product_template = request.env['product.template'].search( [('id', '=', id)], limit=1) data = { 'price_include': product_template.product_variant_id._get_website_price_include_tax(), 'price_exclude': product_template.product_variant_id._get_website_price_exclude_tax(), 'discount': product_template.product_variant_id._get_website_disc(partner_id), 'price_include_after_discount': product_template.product_variant_id._get_website_price_after_disc(), 'price_exclude_after_discount': product_template.product_variant_id._get_website_price_after_disc_and_tax(), 'tax': product_template.product_variant_id._get_website_tax(), } if product_template.product_variant_count > 1: price_excl_after_disc = price_excl = 0 for variant in product_template.product_variant_ids: if price_excl_after_disc == 0: price_excl = variant._get_website_price_exclude_tax() price_excl_after_disc = variant._get_website_price_after_disc_and_tax() elif variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: price_excl_after_disc = variant._get_website_price_after_disc_and_tax() price_excl = variant._get_website_price_exclude_tax() else: price_excl_after_disc = price_excl_after_disc price_excl = price_excl start_from = { 'price_start_from': price_excl, 'price_disc_start_from': price_excl_after_disc } data.update(start_from) return self.response(data, headers=[('Cache-Control', 'max-age=180, private')]) @http.route(prefix + 'product/product/price/', auth='public', methods=['GET', 'OPTIONS']) def get_product_product_price_by_id(self, **kw): if not self.authenticate(): return self.response(code=401, description='Unauthorized') id = kw.get('id') partner_id = int(kw.get('partner_id', 0)) product_product = request.env['product.product'].search( [('id', '=', id)], limit=1) data = { 'price_include': product_product._get_website_price_include_tax(), 'price_exclude': product_product._get_website_price_exclude_tax(), 'discount': product_product._get_website_disc(partner_id), 'price_include_after_discount': product_product._get_website_price_after_disc(), 'price_exclude_after_discount': product_product._get_website_price_after_disc_and_tax(), 'tax': product_product._get_website_tax() } return self.response(data, headers=[('Cache-Control', 'max-age=180, private')]) @http.route(prefix + 'new_product', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_new_product(self, **kw): is_brand_only = int(kw.get('is_brand_only', 0)) base_url = request.env['ir.config_parameter'].get_param('web.base.url') limit_new_products = request.env['ir.config_parameter'].get_param( 'limit.new.product') limit_new_products = int(limit_new_products) # current_time = datetime.now() # delta_time = current_time - timedelta(days=30) # delta_time = delta_time.strftime('%Y-%m-%d %H:%M:%S') query_products = [ ('type', '=', 'product'), ('active', '=', True), ('image_128', '!=', False), ('website_description', '!=', False), # ('write_uid', '!=', 1), ('x_manufacture', '!=', False), # ('create_date', '>=', delta_time), ] new_products = request.env['product.template'].search( query_products, order='create_date desc', limit=limit_new_products) brands = [] for product in new_products: brands.append(product.x_manufacture) brands = list(dict.fromkeys(brands)) data = [] count = 0 for brand in brands: if is_brand_only == 1: data.append({ 'manufacture_id': brand.id, 'sequence': brand.sequence if brand.sequence else count, 'name': brand.x_name, # 'image': base_url + 'api/image/x_manufactures/x_logo_manufacture/' + str( # brand.id) if brand.x_logo_manufacture else '', 'image': request.env['ir.attachment'].api_image('x_manufactures', 'x_logo_manufacture', brand.id), }) continue if count == 11: break query = [ ('type', '=', 'product'), ('active', '=', True), ('x_manufacture', '=', brand.id), ('image_128', '!=', False), ('website_description', '!=', False), # ('write_uid', '!=', 1), ('x_manufacture', '!=', False), # ('create_date', '>=', delta_time), ] count_products = request.env['product.template'].search_count( query) if count_products < 6: _logger.info('Brand Skipped %s' % brand.x_name) continue products = request.env['product.template'].search( query, order='create_date desc', limit=12) data.append({ 'manufacture_id': brand.id, 'sequence': brand.sequence if brand.sequence else count, 'name': brand.x_name, # 'image': base_url + 'api/image/x_manufactures/x_logo_manufacture/' + str( # brand.id) if brand.x_logo_manufacture else '', 'image': request.env['ir.attachment'].api_image('x_manufactures', 'x_logo_manufacture', brand.id), 'products_total': count_products, 'products': [request.env['product.template'].api_single_response(x) for x in products] }) count += 1 return self.response(data) @http.route(prefix + 'product', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_product(self, **kw): name = kw.get('name') manufactures = kw.get('manufactures') categories = kw.get('categories') promotions = kw.get('promotions') ready_stock = kw.get('ready_stock') require_betweens = ['name', 'manufactures', 'categories', 'ready_stock', 'promotions'] is_fulfill = False for required in require_betweens: if kw.get(required): is_fulfill = True if not is_fulfill: return self.response(code=400, description='name or manufactures or categories or ready_stock or promotions is required') query = [('sale_ok', '=', True)] if name: name = '%' + name.replace(' ', '%') + '%' query += [ '|', ('default_code', 'ilike', name), ('name', 'ilike', name), ] if manufactures: query.append(('x_manufacture', 'in', [ int(x) for x in manufactures.split(',')])) if categories: query.append(('public_categ_ids', 'child_of', [ int(x) for x in categories.split(',')])) if ready_stock == '1': query.append(('virtual_qty', '>', 0)) if promotions: coupon_programs = request.env['coupon.program'].search( [('id', 'in', promotions.split(','))]) promotion_query = [x for coupon_program in coupon_programs for x in ast.literal_eval( coupon_program.rule_products_domain)] query += promotion_query price_from = kw.get('price_from') if price_from and int(price_from): query.append(('web_price_sorting', '>=', int(price_from))) price_to = kw.get('price_to') if price_to and int(price_to): query.append(('web_price_sorting', '<=', int(price_to))) product_variants = request.env['product.product'].search(query) product_variant_ids = [x.id for x in product_variants] query = [('product_variant_ids', 'in', product_variant_ids)] limit = int(kw.get('limit', 0)) offset = int(kw.get('offset', 0)) order = self.get_product_default_order(kw.get('order')) product_templates = request.env['product.template'].search( query, limit=limit, offset=offset, order=order) data = { 'product_total': request.env['product.template'].search_count(query), 'products': [request.env['product.template'].api_single_response(x) for x in product_templates] } return self.response(data) @http.route(prefix + 'product/solr', auth='public', methods=['GET']) @controller.Controller.must_authorized() def get_product_solr(self, **kw): name = kw.get('name') solr_flag = kw.get('flag') limit = int(kw.get('limit', 0)) offset = int(kw.get('offset', 0)) if not solr_flag: return self.response(code=400, description='flag is required') query = [ ('sale_ok', '=', True), ('solr_flag', '=', int(solr_flag)) ] if name: name = '%' + name.replace(' ', '%') + '%' query += [ '|', ('default_code', 'ilike', name), ('name', 'ilike', name), ] product_templates = request.env['product.template'].search( query, limit=limit, offset=offset) data = { 'product_total': request.env['product.template'].search_count(query), 'products': [request.env['product.template'].api_single_response(x, with_detail='SOLR') for x in product_templates] } return self.response(data) @http.route(prefix + 'product/', auth='public', methods=['GET']) @controller.Controller.must_authorized() def get_product_by_id(self, **kw): id = kw.get('id') if not id: return self.response(code=400, description='id is required') data = [] id = [int(x) for x in id.split(',')] product_templates = request.env['product.template'].search( [('id', 'in', id)]) if product_templates: data = [request.env['product.template'].api_single_response( x, with_detail='DEFAULT') for x in product_templates] return self.response(data) @http.route(prefix + 'product//similar', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_product_similar_by_id(self, **kw): id = kw.get('id') if not id: return self.response(code=400, description='id is required') id = int(id) product_template = request.env['product.template'].search( [('id', '=', id)]) if not product_template: return self.response([]) query = [('id', '!=', id)] if product_template.x_manufacture: query.append( ('x_manufacture', '=', product_template.x_manufacture.id)) if product_template.public_categ_ids: query.append(('public_categ_ids', 'in', [ x.id for x in product_template.public_categ_ids])) if len(query) == 2: query.insert(0, '|') limit = int(kw.get('limit', 0)) offset = int(kw.get('offset', 0)) order = self.get_product_default_order(kw.get('order')) product_templates = request.env['product.template'].search( query, limit=limit, offset=offset, order=order) data = { 'product_total': request.env['product.template'].search_count(query), 'products': [request.env['product.template'].api_single_response(x) for x in product_templates] } return self.response(data) def get_product_default_order(self, order): orders = ['product_rating desc'] if order != 'price-asc': orders.append('web_price_sorting desc') if order == 'price-asc': orders.append('web_price_sorting asc') elif order == 'latest': orders.append('create_date desc') return ','.join(orders) @http.route(prefix + 'product/category-homepage', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_product_category_homepage(self, **kw): solr_model = request.env['apache.solr'] query = '*:*' id = kw.get('id') if id: query = f'id:{id}' categories = solr_model.connect('product_category_homepage').search( query, sort='sequence_i asc').docs categories = solr_model.clean_key_docs(categories) for category in categories: product_ids = category.get('product_ids', []) category.pop('product_ids', None) products = request.env['product.template'].browse(product_ids) category['products'] = products.solr_results() return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')])