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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
from odoo import models, api, fields
from odoo.exceptions import AccessError, UserError, ValidationError
from datetime import timedelta, date, datetime
import logging
_logger = logging.getLogger(__name__)
class ApprovalPaymentTerm(models.Model):
_name = "approval.payment.term"
_description = "Approval Payment Term"
_inherit = ['mail.thread']
_rec_name = 'number'
number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True)
partner_id = fields.Many2one('res.partner', string='Partner', copy=False)
property_payment_term_id = fields.Many2one('account.payment.term', string='Payment Term', copy=False, tracking=True)
parent_id = fields.Many2one('res.partner', string='Related Company', copy=False)
blocking_stage = fields.Float(string='Blocking Amount',
help="Cannot make sales once the selected "
"customer is crossed blocking amount."
"Set its value to 0.00 to disable "
"this feature", tracking=True, copy=False)
warning_stage = fields.Float(string='Warning Amount',
help="A warning message will appear once the "
"selected customer is crossed warning "
"amount. Set its value to 0.00 to"
" disable this feature", tracking=True, copy=False)
active_limit = fields.Boolean('Active Credit Limit', copy=False, tracking=True)
approve_sales_manager = fields.Boolean('Approve Sales Manager', tracking=True, copy=False)
approve_finance = fields.Boolean('Approve Finance', tracking=True, copy=False)
approve_leader = fields.Boolean('Approve Pimpinan', tracking=True, copy=False)
reason = fields.Text('Reason', tracking=True)
approve_date = fields.Datetime('Approve Date')
state = fields.Selection([
('waiting_approval_sales_manager', 'Waiting Approval Sales Manager'),
('waiting_approval_finance', 'Waiting Approval Finance'),
('waiting_approval_leader', 'Waiting Approval Leader'),
('approved', 'Approved'),
('rejected', 'Rejected')],
default='waiting_approval_sales_manager', tracking=True)
reason_reject = fields.Selection([('reason1', 'Reason 1'), ('reason2', 'Reason 2'), ('reason3', 'Reason 3')], string='Reason Reject', tracking=True)
reject_reason = fields.Text('Reject Reason', tracking=True)
sale_order_ids = fields.Many2many(
'sale.order',
string='Sale Orders',
copy=False,
tracking=True
)
total = fields.Char(
string='Sale Order Totals',
compute='_compute_total'
)
grand_total = fields.Float(string='Grand Total', compute="_compute_grand_total")
change_log_688 = fields.Text(string="Change Log", readonly=True, copy=False)
def write(self, vals):
# Ambil nilai lama sebelum perubahan
old_values_dict = {
rec.id: rec.read(vals.keys())[0]
for rec in self
}
res = super().write(vals)
self._track_changes_for_user_688(vals, old_values_dict)
return res
def _track_changes_for_user_688(self, vals, old_values_dict):
# if self.env.user.id != 688:
# return
tracked_fields = {"blocking_stage", "warning_stage", "property_payment_term_id"}
for rec in self:
changes = []
old_values = old_values_dict.get(rec.id, {})
for field_name, new_value in vals.items():
if field_name not in tracked_fields:
continue
field = rec._fields[field_name]
old_value = old_values.get(field_name)
field_label = field.string # label user-friendly
if field.type == 'many2one':
old_id = old_value[0] if old_value else False
is_different = old_id != new_value
if is_different:
old_display = old_value[1] if old_value else 'False'
new_display = rec.env[field.comodel_name].browse(new_value).display_name if new_value else 'False'
changes.append(f"[{field_label}] dari '{old_display}' ke '{new_display}'")
else:
# Float khusus
if field.type == 'float':
is_different = not self._float_equal(old_value, new_value)
else:
is_different = old_value != new_value
if is_different:
changes.append(f"[{field_label}] dari '{old_value}' ke '{new_value}'")
if changes:
timestamp = fields.Datetime.now().strftime('%Y-%m-%d %H:%M:%S')
user = self.env.user
rec.change_log_688 = f"{timestamp} - Perubahan oleh {user.name}:\n" + "\n".join(changes)
@staticmethod
def _float_equal(val1, val2, eps=1e-6):
try:
return abs(float(val1 or 0.0) - float(val2 or 0.0)) < eps
except Exception:
return False
def _compute_grand_total(self):
for rec in self:
grand_total = sum(order.amount_total for order in rec.sale_order_ids)
rec.grand_total = grand_total
def _compute_total(self):
for rec in self:
totals_list = []
for order in rec.sale_order_ids:
formatted_total = "{:,.2f}".format(order.amount_total)
totals_list.append(f"{order.name}: {formatted_total}")
rec.total = "\n".join(totals_list) if totals_list else "No Sale Orders"
@api.constrains('partner_id')
def constrains_partner_id(self):
if self.partner_id:
self.parent_id = self.partner_id.parent_id.id if self.partner_id.parent_id else None
self.blocking_stage = self.partner_id.blocking_stage
self.warning_stage = self.partner_id.warning_stage
self.active_limit = self.partner_id.active_limit
self.property_payment_term_id = self.partner_id.property_payment_term_id.id
def button_approve(self):
user = self.env.user
is_it = user.has_group('indoteknik_custom.group_role_it')
if (not user.id ==7 and user.id == 19 and not self.approve_sales_manager) or (is_it and not self.approve_sales_manager):
self.approve_sales_manager = True
self.state = 'waiting_approval_finance'
return
if (not user.id ==7 and user.id == 688 and not self.approve_finance) or (is_it and not self.approve_finance):
self.approve_finance = True
self.state = 'waiting_approval_leader'
return
if (user.id == 7 and self.approve_finance) or (is_it and not self.approve_leader):
self.approve_leader = True
if not self.approve_finance and not is_it:
raise UserError('Harus Approval Finance!!')
if not self.approve_leader and not is_it:
raise UserError('Harus Approval Pimpinan!!')
if user.id == 7:
if not self.approve_finance:
raise UserError('Belum Di Approve Oleh Finance')
if self.approve_leader == True:
self.partner_id.write({
'blocking_stage': self.blocking_stage,
'warning_stage': self.warning_stage,
'active_limit': self.active_limit,
'property_payment_term_id': self.property_payment_term_id.id,
'is_cbd_locked': False,
})
self.approve_date = datetime.utcnow()
self.state = 'approved'
def button_reject(self):
if self.env.user.id not in [688, 7]:
raise UserError("Hanya Finance atau Pimpinan Yang Bisa Reject")
self.state = 'rejected'
@api.model
def create(self, vals):
vals['number'] = self.env['ir.sequence'].next_by_code('approval.payment.term') or '0'
result = super(ApprovalPaymentTerm, self).create(vals)
return result
|