from odoo import fields, models, api from datetime import datetime class PromotionProgramLine(models.Model): _name = "promotion.program.line" name = fields.Char(string="Name") image = fields.Binary(string="Image") product_id = fields.Many2one(comodel_name="product.product", string="Product Variant") program_id = fields.Many2one(comodel_name="promotion.program", string="Program") discount_type = fields.Selection(selection=[ ("percentage", "Percentage"), ("fixed_price", "Fixed Price"), ], string="Discount Type") discount_amount = fields.Float(string="Discount Amount") promotion_type = fields.Selection(selection=[ ("special_price", "Special Price"), ("bundling", "Bundling"), ("discount_loading", "Discount Loading"), ("merchandise", "Merchandise") ], string="Promotion Type") minimum_purchase_qty = fields.Integer(string="Minimum Purchase Qty", help="Minimum Qty to applied discount loading") applies_multiply = fields.Boolean(string="Applies Multiply", help="Is applies multiply") limit_qty = fields.Integer(string="Limit Qty", help="Limit Qty product in promotion") limit_qty_user = fields.Integer(string="Limit Qty / User", help="Limit Qty per User") limit_qty_transaction = fields.Integer(string="Limit Qty / Transaction", help="Limit Qty per Transaction") line_free_item = fields.One2many(comodel_name="promotion.program.free_item", inverse_name="line_id", string="Line Free Item") display_on_homepage = fields.Boolean(string="Display on Homepage") order_line_ids = fields.One2many('sale.order.line', 'program_line_id') @api.onchange('product_id') def _onchange_product_id(self): if self.product_id and not self.name: self.name = self.product_id.display_name self._discount_loading_auto() @api.onchange('promotion_type') def onchange_promotion_type(self): self._discount_loading_auto() def _discount_loading_auto(self): program_line = self product = program_line.product_id promotion_type = program_line.promotion_type if promotion_type != 'discount_loading' or not product: return line = self.browse(self.ids) line.product_id = self.product_id.id line.promotion_type = self.promotion_type product_added = False line_free_item = program_line.line_free_item for line in line_free_item: if line.product_id.id == product.id: product_added = True continue line.unlink() if not product_added: data = {'product_id': product.id, 'qty': 1, 'line_id': program_line.id} line_free_item.create(data) def calculate_price(self, price): initial_price = price['price'] if self.discount_type == 'percentage': price['discount_percentage'] = self.discount_amount price['price_discount'] = initial_price - (initial_price * self.discount_amount / 100) elif self.discount_type == 'fixed_price': price['price_discount'] = self.discount_amount price['discount_percentage'] = round((initial_price - self.discount_amount) / initial_price * 100) return 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_id', '=', product_id) ]) def _get_remaining_qty(self, user): remaining_qty = { 'all': self.limit_qty, 'user': self.limit_qty_user, 'transaction': self.limit_qty_transaction } for order in self.order_line_ids: parent_order = order.order_id if parent_order.state != 'cancel': remaining_qty['all'] -= order.product_uom_qty if user and parent_order.partner_id.id == user['partner_id']: remaining_qty['user'] -= order.product_uom_qty 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 _get_remaining_time(self): calculate_time = self.program_id.end_time - datetime.now() return round(calculate_time.total_seconds()) def _res_limit_qty(self): return { 'all': self.limit_qty, 'user': self.limit_qty_user, 'transaction': self.limit_qty_transaction, } def _res_promotion_type(self): return { 'value': self.promotion_type, 'label': dict(self._fields['promotion_type'].selection).get(self.promotion_type) } def format(self, user = None): ir_attachment = self.env['ir.attachment'] product_price = self.product_id.calculate_website_price() 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 return { 'id': self.id, 'name': self.name, 'image': ir_attachment.api_image('promotion.program.line', 'image', self.id), 'minimum_purchase_qty': self.minimum_purchase_qty, 'applies_multiply': self.applies_multiply, 'remaining_time': self._get_remaining_time(), 'type': self._res_promotion_type(), 'limit_qty': limit_qty, 'remaining_qty': remaining_qty, 'used_percentage': percent_remaining, 'price': self.calculate_price(price=product_price) } def res_format(self, user): data = [x.format(user) for x in self] return data def res_format_cart(self, user): data = self.format(user) return data