1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
order_promotion_ids = fields.One2many('sale.order.promotion', 'order_id', 'Promotions')
def add_free_product(self, promotions):
for promotion in promotions:
program_line = self.env['promotion.program.line'].browse(promotion['program_line_id'])
for free_product in program_line.free_product_ids:
if free_product.product_id.merchandise_ok:
self.env['sale.order.line'].create({
'order_id': self.id,
'name': f"Free Product {free_product.product_id.display_name} Quantity ({free_product.qty})",
'display_type': 'line_note'
})
def apply_promotion_program(self):
userdata = {
'user_id': self.partner_id.user_id.id,
'partner_id': self.partner_id.id
}
order_lines = []
iu_products = [] # Internal Use products
for line in self.order_promotion_ids:
promotion = line.program_line_id.format(user=userdata, qty=line.quantity)
products = promotion['products']
free_products = promotion['free_products']
all_products = products.copy()
if promotion['promotion_type']['value'] == 'merchandise':
iu_products += filter(lambda x: x['qty'] > 0, free_products)
else:
all_products = self._merge_promotion_products(promotion)
promotion_price = promotion['price']['price_discount'] * line.quantity * 1.11
promotion_amt_total = sum(product['price']['price'] * product['qty'] for product in all_products)
promotion_used_price = 0
for index, product in enumerate(all_products):
order_line_default = {
'company_id': 1,
'order_id': self.id,
'order_promotion_id': line.id,
'product_id': product['id'],
'product_uom_qty': product['qty'],
}
if promotion['promotion_type']['value'] == 'special_price':
order_lines.append({
**order_line_default,
'price_unit': product['price']['price'],
'discount': product['price']['discount_percentage']
})
continue
product_price = product['price']['price']
contrib_decimal = product_price * product['qty'] / promotion_amt_total
if index < len(all_products) - 1:
contrib_price = contrib_decimal * promotion_price
else:
contrib_price = promotion_price - promotion_used_price
contrib_price_unit = contrib_price / product['qty']
contrib_disc_unit = round((product_price - contrib_price_unit) / product_price * 100, 2)
product_subtotal = round((100 - contrib_disc_unit) / 100 * product_price, 2) * product['qty']
promotion_used_price += product_subtotal
order_lines.append({
**order_line_default,
'price_unit': product_price,
'discount': contrib_disc_unit
})
self.env['sale.order.line'].create(order_lines)
self._create_promotion_program_iu_docs(iu_products)
def _merge_promotion_products(self, promotion):
"""
Merges the products and free products from a promotion into a single dictionary.
Parameters:
promotion (dict): A dictionary representing a promotion with 'products' and 'free_products' keys.
Returns:
list: A list containing the merged products from the promotion.
"""
merged_products = {}
for product in promotion['products'] + promotion['free_products']:
product_id = product['id']
product_qty = product['qty']
if product_id in merged_products:
merged_products[product_id]['qty'] += product_qty
else:
merged_products[product_id] = product
return list(merged_products.values())
def _create_promotion_program_iu_docs(self, products):
if len(products) == 0:
return False
default = {
'picking_type_id': 33, # PT Indoteknik (Bandengan): Internal Transfers
'location_id': 57, # BU/Stock
'location_dest_id': 49, # Virtual Locations/Internal Use
'account_id': 596, # Biaya awareness
'product_uom': 1 # Unit
}
picking_type = self.env['stock.picking.type'].browse(default['picking_type_id'])
picking = self.env['stock.picking'].create({
'name': picking_type.sequence_id.next_by_id(),
'picking_type_id': default['picking_type_id'],
'partner_id': self.partner_id.id,
'real_shipping_id': self.real_shipping_id.id,
'location_id': default['location_id'],
'location_dest_id': default['location_dest_id'],
'account_id': default['account_id'],
'origin': self.display_name,
'is_internal_use': True
})
for product in products:
picking.move_ids_without_package.create({
'product_id': product['id'],
'name': product['display_name'],
'product_uom_qty': product['qty'],
'product_uom': default['product_uom'],
'location_id': default['location_id'],
'location_dest_id': default['location_dest_id'],
'picking_id': picking.id
})
self.picking_iu_id = picking.id
|