from odoo import models, fields from datetime import datetime class PromotionProgramLine(models.Model): _name = 'promotion.program.line' program_id = fields.Many2one('promotion.program', 'Program') name = fields.Char('Name') promotion_type = fields.Selection([ ("special_price", "Special Price"), ("bundling", "Bundling"), ("discount_loading", "Discount Loading"), ("merchandise", "Merchandise") ], 'Type') package_limit = fields.Integer('Package limit') package_limit_user = fields.Integer('Package limit / user') package_limit_trx = fields.Integer('Package limit / transaction') product_ids = fields.One2many('promotion.product', 'program_line_id', 'Product') free_product_ids = fields.One2many('promotion.free_product', 'program_line_id', 'Free Product') display_on_homepage = fields.Boolean('Display on Homepage') price = fields.Float('Price') sequence = fields.Integer(string='Sequence') discount_type = fields.Selection([ ("percentage", "Percentage"), ("fixed", "Fixed") ], 'Discount Type') discount_amount = fields.Float('Discount Amount') order_promotion_ids = fields.One2many('sale.order.promotion', 'program_line_id', 'Promotions') active = fields.Boolean(string="Active", default=True) solr_flag = fields.Integer(string="Solr Flag", default=1) description = fields.Char('Description') price_tier_1 = fields.Float('Price Tier 1') price_tier_2 = fields.Float('Price Tier 2') price_tier_3 = fields.Float('Price Tier 3') price_tier_4 = fields.Float('Price Tier 4') price_tier_5 = fields.Float('Price Tier 5') def get_price_tier(self, product_id, qty): product = self.env['product.product'].browse(product_id.id) tiers = ['1_v2', '2_v2', '3_v2', '4_v2', '5_v2'] for index, tier in enumerate(tiers, start=1): price_tier_data = product._get_pricelist_tier(tier) price_field = f'price_tier_{index}' if price_field in self._fields: price = price_tier_data.get(f'price_tier{tier}', 0) * qty self[price_field] = price if index == 1: self.price = price def get_active_promotions(self, product_id): current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') return self.search([ ('program_id.start_time', '<=', current_time), ('program_id.end_time', '>=', current_time), ('product_ids.product_id', '=', product_id) ]) def _res_limit_qty(self): return { 'all': self.package_limit, 'user': self.package_limit_user, 'transaction': self.package_limit_trx, } def _get_remaining_qty(self, user): remaining_qty = { 'all': self.package_limit, 'user': self.package_limit_user, 'transaction': self.package_limit_trx } for promotion in self.order_promotion_ids: order = promotion.order_id if order.state != 'cancel': remaining_qty['all'] -= promotion.quantity if user and order.partner_id.id == user['partner_id']: remaining_qty['user'] -= promotion.quantity if remaining_qty['all'] < remaining_qty['user']: remaining_qty['user'] = remaining_qty['all'] if remaining_qty['user'] < remaining_qty['transaction']: remaining_qty['transaction'] = remaining_qty['user'] return remaining_qty def _res_promotion_type(self): return { 'value': self.promotion_type, 'label': dict(self._fields['promotion_type'].selection).get(self.promotion_type) } def _get_remaining_time(self): if not self.program_id.end_time: return 0 calculate_time = self.program_id.end_time - datetime.now() return round(calculate_time.total_seconds()) def formats(self, user): return [x.format(user) for x in self] def format(self, user = None, qty = 1): ir_attachment = self.env['ir.attachment'] limit_qty = self._res_limit_qty() remaining_qty = self._get_remaining_qty(user) percent_remaining = 0 if limit_qty['all'] > 0: percent_remaining = (limit_qty['all'] - remaining_qty['all']) / limit_qty['all'] * 100 products = self.product_ids.formats(purchase_qty=qty) free_products = self.free_product_ids.formats(purchase_qty=qty) merged_products = products + free_products weight = sum(x['package_weight'] for x in merged_products) # Sum of products and free products in 1 package quantity products_total = sum(x['price']['price'] * x['qty'] / qty for x in products) free_products_total = sum(x['price']['price'] * x['qty'] / qty for x in free_products) package_price = products_total + free_products_total image = self.env['ir.attachment'].api_image('promotion.program', 'image', self.program_id.id), response = { 'id': self.id, 'image_program': image, 'name': self.name, 'remaining_time': self._get_remaining_time(), 'promotion_type': self._res_promotion_type(), 'limit_qty': limit_qty, 'remaining_qty': remaining_qty, 'used_percentage': percent_remaining, 'package_price': package_price, 'price': { 'price': self.price, 'price_discount': self.price, 'discount_percentage': 0 }, 'products': products, 'free_products': free_products, 'weight': weight } if self.promotion_type == 'special_price': response['price'] = self._calc_special_price_price(products[0]) return response def _calc_special_price_price(self, product): result = product['price'] price = result['price'] if self.discount_type == 'percentage': result['discount_percentage'] = self.discount_amount result['price_discount'] = price * (1 - self.discount_amount / 100) elif self.discount_type == 'fixed': final_price = price - self.discount_amount result['price_discount'] = final_price result['discount_percentage'] = (price - final_price) / price * 100 return result