from odoo import fields, models, api from datetime import datetime, timedelta class WebsiteUserCart(models.Model): _name = 'website.user.cart' _rec_name = 'user_id' user_id = fields.Many2one('res.users', string='User') product_id = fields.Many2one('product.product', string='Product') program_line_id = fields.Many2one('promotion.program.line', string='Program', help="Apply program") qty = fields.Float(string='Quantity', digits='Product Unit of Measure') is_selected = fields.Boolean(string='Selected?', digits='Is selected to process checkout') source = fields.Selection([ ('add_to_cart', 'Add To Cart'), ('buy', 'Buy') ], 'Source', default='add_to_cart') user_other_carts = fields.One2many('website.user.cart', 'id', 'Other Products', compute='_compute_user_other_carts') is_reminder = fields.Boolean(string='Reminder?') phone_user = fields.Char(string='Phone', related='user_id.mobile') price = fields.Float(string='Price', compute='_compute_price') program_product_id = fields.Many2one('product.product', string='Program Products', compute='_compute_program_product_ids') @api.depends('program_line_id') def _compute_program_product_ids(self): for record in self: if record.program_line_id and record.program_line_id.product_ids: product = record.program_line_id.product_ids[0] record.program_product_id = product.product_id record.product_id = product.product_id else: # Handle case where there are no product_ids record.program_product_id = False def _compute_price(self): for record in self: record.price = record.get_price_website(record.product_id.id)['price'] if record.program_line_id: record.price = record.get_price_coret(record.program_line_id.id) def _compute_user_other_carts(self): for record in self: others = self.search([('user_id', '=', record.user_id.id)]) record.user_other_carts = others def get_product(self): res = { 'cart_id': self.id, 'quantity': self.qty, 'selected': self.is_selected, 'can_buy': True } if self.product_id: res['cart_type'] = 'product' product = self.product_id.v2_api_single_response(self.product_id) res.update(product) # Add category information res['categories'] = [{ 'id': cat.id, 'name': cat.name } for cat in self.product_id.public_categ_ids] # Check if the product's inventory location is in ID 57 or 83 target_locations = [57, 83] stock_quant = self.env['stock.quant'].search([ ('product_id', '=', self.product_id.id), ('location_id', 'in', target_locations) ]) if stock_quant: res['is_in_bu'] = True res['on_hand_qty'] = sum(stock_quant.mapped('quantity')) res['available_quantity'] = sum(stock_quant.mapped('available_quantity')) else: res['is_in_bu'] = False res['on_hand_qty'] = 0 res['available_quantity'] = 0 flashsales = self.product_id._get_active_flash_sale() res['has_flashsale'] = True if len(flashsales) > 0 else False elif self.program_line_id: res['cart_type'] = 'promotion' userdata = { 'partner_id': self.user_id.partner_id.id, 'user_id': self.user_id.id } program = self.program_line_id.format(user=userdata, qty=self.qty) res.update(program) if program['remaining_qty']['transaction'] < self.qty: res['can_buy'] = False res['subtotal'] = self.qty * res['price']['price_discount'] return res def get_products(self): products = [x.get_product() for x in self] for i, cart_item in enumerate(self): if cart_item.product_id and i < len(products): products[i]['categories'] = [{ 'id': cat.id, 'name': cat.name } for cat in cart_item.product_id.public_categ_ids] return products def get_product_by_user(self, user_id, selected=False, source=False): user_id = int(user_id) if source == 'buy': source = ['buy'] else: source = ['add_to_cart', 'buy'] parameters = [ ('user_id', '=', user_id), ('source', 'in', source) ] carts = self.search(parameters) for cart in carts: if cart.product_id: price = cart.product_id._v2_get_website_price_include_tax() if not cart.product_id.active or price < 1: cart.is_selected = False if selected: parameters.append(('is_selected', '=', True)) products_active = self.search(parameters) products = products_active.get_products() return products def get_user_checkout(self, user_id, voucher=False, voucher_shipping=False, source=False): products = self.get_product_by_user(user_id=user_id, selected=True, source=source) total_purchase = 0 total_discount = 0 for product in products: if product['cart_type'] == 'promotion': price = product['package_price'] * product['quantity'] else: price = product['price']['price'] * product['quantity'] discount_price = price - product['price']['price_discount'] * product['quantity'] total_purchase += price total_discount += discount_price subtotal = total_purchase - total_discount discount_voucher = 0 discount_voucher_shipping = 0 order_line = [] if voucher or voucher_shipping: for product in products: if product['cart_type'] == 'promotion': continue order_line.append({ 'product_id': self.env['product.product'].browse(product['id']), 'price': product['price']['price'], 'discount': product['price']['discount_percentage'], 'qty': product['quantity'], 'subtotal': product['subtotal'] }) if voucher: voucher_info = voucher.apply(order_line) discount_voucher = voucher_info['discount']['all'] subtotal -= discount_voucher if voucher_shipping: voucher_shipping_info = voucher_shipping.apply(order_line) discount_voucher_shipping = voucher_shipping_info['discount']['all'] tax = round(subtotal * 0.11) grand_total = subtotal + tax total_weight = sum(x['weight'] * x['quantity'] for x in products) total_weight = round(total_weight, 2) result = { 'total_purchase': total_purchase, 'total_discount': total_discount, 'discount_voucher': discount_voucher, 'discount_voucher_shipping': discount_voucher_shipping, 'subtotal': subtotal, 'tax': tax, 'grand_total': round(grand_total), 'total_weight': { 'kg': total_weight, 'g': total_weight * 1000 }, 'has_product_without_weight': any( not product.get('weight') or product.get('weight') == 0 for product in products), 'products': products } return result def action_mail_reminder_to_checkout(self, limit=200): user_ids = self.search([('is_reminder', '=', False)]).mapped('user_id')[:limit] for user in user_ids: latest_cart = self.search([('user_id', '=', user.id)], order='create_date desc', limit=1) carts_to_remind = self.search([('user_id', '=', user.id)]) if latest_cart and not latest_cart.is_reminder: for cart in carts_to_remind: check = cart.check_product_flashsale(cart.product_id.id) if not cart.program_line_id and cart.product_id.default_code and not 'BOM' in cart.product_id.default_code and \ check['is_flashsale'] == False: cart.is_selected = True if cart.program_line_id or check[ 'is_flashsale'] or cart.product_id.default_code and 'BOM' in cart.product_id.default_code: cart.is_selected = False cart.is_reminder = True template = self.env.ref('indoteknik_custom.mail_template_user_cart_reminder_to_checkout') template.send_mail(latest_cart.id, force_send=True) def calculate_discount(self, user_id): carts = self.search([('user_id', '=', user_id)]) voucher = self.env['voucher'].browse(146) total_discount = 0.0 total_voucher = 0.0 subtotal_website = 0.0 for cart in carts: check = cart.check_product_flashsale(cart.product_id.id) product_manufacture = cart.product_id.x_manufacture.id product_price = cart.get_price_website(cart.product_id.id) subtotal = product_price['price'] * cart.qty subtotal_promo = 0.0 if cart.program_line_id: subtotal_website += cart.program_line_id.price subtotal_promo = cart.program_line_id.price * cart.qty elif check['is_flashsale']: subtotal_website += check['price'] subtotal_promo = check['price'] * cart.qty else: subtotal_website += product_price['price'] discount_amount = 0.0 if product_manufacture: for line in voucher.voucher_line: if line.manufacture_id.id == product_manufacture: discount_amount = line.discount_amount break product_discount = subtotal_promo if cart.program_line_id or check['is_flashsale'] else subtotal total_discount += product_discount if check[ 'is_flashsale'] == False and cart.product_id.default_code and not 'BOM' in cart.product_id.default_code: voucher_product = subtotal * (discount_amount / 100.0) total_voucher += voucher_product if total_discount > 0: ppn = total_discount * 0.11 return { 'total_discount': self.format_currency(total_discount), 'total_voucher': self.format_currency(total_voucher), 'subtotal_website': self.format_currency(subtotal_website), 'ppn': self.format_currency(ppn), 'grand_total': self.format_currency(total_discount + ppn) } return self.format_currency(0.0) def check_product_flashsale(self, product_id): product = product_id current_time = datetime.utcnow() found_product = self.env['product.pricelist.item'].search( [('product_id', '=', product_id), ('pricelist_id.is_flash_sale', '=', True)]) if found_product: for found in found_product: pricelist_flashsale = found.pricelist_id if pricelist_flashsale.start_date <= current_time <= pricelist_flashsale.end_date: return { 'is_flashsale': True, 'price': found.fixed_price } else: return { 'is_flashsale': False } return { 'is_flashsale': False } # if found_product: # start_date = found_product.pricelist_id.start_date # end_date = found_product.pricelist_id.end_date # current_time = datetime.now() # if start_date and end_date: # if start_date >= current_time and end_date <= current_time: # return { # 'is_flashsale': False # } # return { # 'is_flashsale': True, # 'price': found_product.fixed_price # } # return { # 'is_flashsale': False # } def get_data_promo(self, program_line_id): program_line_product = self.env['promotion.product'].search([ ('program_line_id', '=', program_line_id) ]) program_free_product = self.env['promotion.free_product'].search([ ('program_line_id', '=', program_line_id) ]) return program_line_product, program_free_product def get_weight_product(self, program_line_id): program_line_product = self.env['promotion.product'].search([ ('program_line_id', '=', program_line_id) ]) program_free_product = self.env['promotion.free_product'].search([ ('program_line_id', '=', program_line_id) ]) real_weight = 0.0 if program_line_product: for product in program_line_product: real_weight += product.product_id.weight if program_free_product: for product in program_free_product: real_weight += product.product_id.weight return real_weight def get_price_coret(self, program_line_id): program_line_product = self.env['promotion.product'].search([ ('program_line_id', '=', program_line_id) ]) program_free_product = self.env['promotion.free_product'].search([ ('program_line_id', '=', program_line_id) ]) price_coret = 0.0 for product in program_line_product: price = self.get_price_website(product.product_id.id) price_coret += price['price'] * product.qty for product in program_free_product: price = self.get_price_website(product.product_id.id) price_coret += price['price'] * product.qty return price_coret def get_price_website(self, product_id): price_website = self.env['product.pricelist.item'].search( [('product_id', '=', product_id), ('pricelist_id', '=', 17022)], limit=1) price_tier = self.env['product.pricelist.item'].search( [('product_id', '=', product_id), ('pricelist_id', '=', 17023)], limit=1) fixed_price = price_website.fixed_price if price_website else 0.0 discount = price_tier.price_discount if price_tier else 0.0 discounted_price = fixed_price - (fixed_price * discount / 100) final_price = discounted_price / 1.11 return { 'price': final_price, 'web_price': discounted_price } def format_integer(self, number): number = int(number) return number def format_currency(self, number): number = int(number) return "{:,}".format(number).replace(',', '.')