From 7985e9a32f93c144203a528d87912443a4fd9530 Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Fri, 22 May 2026 14:14:04 +0700 Subject: [PATCH] feat: implement loyalty data migration between membership levels during partner updates --- models/res_partner.py | 49 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/models/res_partner.py b/models/res_partner.py index fe58603..2c941ff 100644 --- a/models/res_partner.py +++ b/models/res_partner.py @@ -21,8 +21,8 @@ class ResPartner(models.Model): def write(self, vals): """ - When a partner's membership level changes, delete their loyalty cards - from the OLD level's program so they don't accumulate cards across levels. + When a partner's membership level changes, transfer points, history, + and archive their loyalty cards from the OLD level's program. """ if 'membership_level_id' in vals: new_level_id = vals['membership_level_id'] @@ -30,12 +30,51 @@ class ResPartner(models.Model): old_level_id = partner.membership_level_id.id if partner.membership_level_id else False # Only act when the level is actually changing to a different value if old_level_id and old_level_id != new_level_id: - old_cards = self.env['loyalty.card'].search([ + old_cards = self.env['loyalty.card'].sudo().search([ ('partner_id', '=', partner.id), ('program_id', '=', old_level_id), ]) + if old_cards and new_level_id: + new_card = self.env['loyalty.card'].sudo().search([ + ('partner_id', '=', partner.id), + ('program_id', '=', new_level_id), + ], limit=1) + + if not new_card: + new_card = self.env['loyalty.card'].sudo().create({ + 'partner_id': partner.id, + 'program_id': new_level_id, + 'points': 0, + }) + + # 1. Transfer points + for old_card in old_cards: + pts = old_card.points + if abs(pts) > 0.0001: + new_card.points += pts + + # 2. Transfer loyalty history (point transactions) + old_histories = self.env['loyalty.history'].sudo().search([ + ('card_id', 'in', old_cards.ids) + ]) + if old_histories: + old_histories.write({'card_id': new_card.id}) + + # 3. Transfer POS order line references + old_pos_lines = self.env['pos.order.line'].sudo().search([ + ('coupon_id', 'in', old_cards.ids) + ]) + if old_pos_lines: + old_pos_lines.write({'coupon_id': new_card.id}) + + # 4. Transfer Sales order line references + old_sale_lines = self.env['sale.order.line'].sudo().search([ + ('coupon_id', 'in', old_cards.ids) + ]) + if old_sale_lines: + old_sale_lines.write({'coupon_id': new_card.id}) + + # Archive old-level cards if old_cards: - # Archive instead of delete — loyalty cards may be referenced - # by pos_order_line.coupon_id (FK), so unlink() would fail. old_cards.write({'active': False}) return super().write(vals)