From 40e70a21c1f97c7325fef6164ef098582eb39534 Mon Sep 17 00:00:00 2001 From: FIN-IT_AndriFP Date: Fri, 27 Feb 2026 11:26:25 +0700 Subject: approval SO 2 parameter dengan menambahkan pengecekan value --- indoteknik_api/controllers/api_v1/sale_order.py | 4 ++-- indoteknik_api/models/sale_order.py | 2 +- indoteknik_custom/models/sale_order.py | 23 ++++++++++++++++++++--- indoteknik_custom/views/sale_order.xml | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index cff1921d..f4a2a9d4 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -154,13 +154,13 @@ class SaleOrder(controller.Controller): elif status == 'belum_bayar': domain += [ ('state', '=', 'draft'), - ('approval_status', 'in', ['pengajuan1', 'pengajuan2']), + ('approval_status', 'in', ['pengajuan0','pengajuan1', 'pengajuan2']), ('payment_status', 'in', [False, None, '', 'pending', 'expire']) ] elif status == 'diproses': domain += [ ('state', '=', 'draft'), - ('approval_status', 'in', ['pengajuan1', 'pengajuan2']), + ('approval_status', 'in', ['pengajuan0','pengajuan1', 'pengajuan2']), ('payment_status', '!=', False), ('payment_status', 'not in', ['', 'pending', 'expire']), ] diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py index 23be358a..7951de45 100644 --- a/indoteknik_api/models/sale_order.py +++ b/indoteknik_api/models/sale_order.py @@ -66,7 +66,7 @@ class SaleOrder(models.Model): elif sale_order.state == 'draft': if not sale_order.approval_status: data['status'] = 'draft' - elif sale_order.approval_status in ('pengajuan1', 'pengajuan2'): + elif sale_order.approval_status in ('pengajuan0', 'pengajuan1', 'pengajuan2'): if sale_order.payment_status in ('', 'pending', False, None, 'expire'): data['status'] = 'belum_bayar' elif sale_order.payment_status not in ['', 'pending', False, None, 'expire']: diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index e6fc4732..fd0d6bdd 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -156,6 +156,7 @@ class SaleOrder(models.Model): total_margin_excl_third_party = fields.Float('Before Margin', help="Before Margin in Sales Order Header") approval_status = fields.Selection([ + ('pengajuan0', 'Approval Team Sales'), ('pengajuan1', 'Approval Manager'), ('pengajuan2', 'Approval Pimpinan'), ('approved', 'Approved'), @@ -2384,7 +2385,8 @@ class SaleOrder(models.Model): # if order.validate_partner_invoice_due(): # return self._create_notification_action('Notification', # 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension') - + value_trigger = order._requires_approval_by_value() + if order._requires_approval_margin_leader(): order.approval_status = 'pengajuan2' order.message_post(body="Mengajukan approval ke Pimpinan") @@ -2400,9 +2402,16 @@ class SaleOrder(models.Model): self.check_product_bom() self.check_credit_limit() self.check_limit_so_to_invoice() - order.approval_status = 'pengajuan1' + order.approval_status = 'pengajuan0' order.message_post(body="Mengajukan approval ke Team Sales") return self._create_approval_notification('Team Sales') + elif value_trigger: + self.check_product_bom() + self.check_credit_limit() + self.check_limit_so_to_invoice() + order.approval_status = 'pengajuan0' + order.message_post(body="Mengajukan approval ke Team Sales (Amount Total > 50jt)") + return self._create_approval_notification('Team Sales') if not order.with_context(ask_approval=True)._is_request_to_own_team_leader(): return self._create_notification_action( @@ -2657,6 +2666,7 @@ class SaleOrder(models.Model): 'Warning', 'Hanya bisa konfirmasi SO tim Anda.' ) + value_trigger = order._requires_approval_by_value() if order._requires_approval_margin_leader(): order.approval_status = 'pengajuan2' return self._create_approval_notification('Pimpinan') @@ -2667,6 +2677,10 @@ class SaleOrder(models.Model): order.approval_status = 'pengajuan1' order.message_post(body="Mengajukan approval ke Team Sales") return self._create_approval_notification('Team Sales') + elif value_trigger: + order.approval_status = 'pengajuan1' + order.message_post(body="Mengajukan approval ke Team Sales (Total SO > 50jt)") + return self._create_approval_notification('Team Sales') order.approval_status = 'approved' order._set_sppkp_npwp_contact() @@ -2778,6 +2792,9 @@ class SaleOrder(models.Model): and not self.env.user.is_leader ) + def _requires_approval_by_value(self): + LIMIT_VALUE = 50000000 + return self.amount_total > LIMIT_VALUE def _is_request_to_own_team_leader(self): user = self.env.user @@ -3397,7 +3414,7 @@ class SaleOrder(models.Model): #payment term vals if 'payment_term_id' in vals and any( - order.approval_status in ['pengajuan1', 'pengajuan2', 'approved'] for order in self): + order.approval_status in ['pengajuan0','pengajuan1', 'pengajuan2', 'approved'] for order in self): raise UserError( "Payment Term tidak dapat diubah karena Sales Order sedang dalam proses approval atau sudah diapprove.") diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index c3df92ec..2d4488ab 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -385,7 +385,7 @@ { 'readonly': [ '|', - ('approval_status', 'in', ['pengajuan1', 'pengajuan2', 'approved']), + ('approval_status', 'in', ['pengajuan0','pengajuan1', 'pengajuan2', 'approved']), ('state', 'not in', ['cancel', 'draft']) ] } -- cgit v1.2.3 From 4d8b06efe10c33d44301b05d86bf96a62033820a Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 27 Feb 2026 14:42:29 +0700 Subject: push --- indoteknik_custom/models/automatic_purchase.py | 72 ++++++++++++++++---------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index f4ecdcd6..7e324061 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -314,6 +314,8 @@ class AutomaticPurchase(models.Model): sale_ids_set = set() sale_ids_name = set() + retur_cache = {} + incoming_cache = {} for sale_order in matches_so: exist = self.env['purchase.order.sales.match'].search([ ('product_id', '=', sale_order.product_id.id), @@ -324,32 +326,50 @@ class AutomaticPurchase(models.Model): skip_line = False - for existing in exist: - if existing.purchase_order_id.state in ['done', 'purchase']: - # if existing.purchase_line_id.qty_received != existing.purchase_line_id.product_qty: - # break - - incoming = self.env['stock.move'].search([ - ('reference', 'ilike', 'BU/INPUT'), - ('state', 'not in', ['done','cancel']), - ('product_id', '=', existing.product_id.id), - ('purchase_line_id', '=', existing.purchase_line_id.id), - ], limit=1) - - if incoming: - skip_line = True - break - - retur = self.env['stock.move'].search([ - ('reference', 'ilike', 'BU/INPUT'), - ('state', 'in', ['done']), - ('product_id', '=', existing.product_id.id), - ('purchase_line_id', '=', existing.purchase_line_id.id), - ], limit=1) - - if retur and existing.purchase_line_id.qty_received == existing.purchase_line_id.product_qty: - skip_line = True - break + sale_line_id = sale_order.sale_line_id.id + + if sale_line_id not in incoming_cache: + + qty_incoming = 0 + + for existing in exist: + if existing.purchase_order_id.state in ['done', 'purchase']: + + incoming_moves = self.env['stock.move'].search([ + ('reference', 'ilike', 'BU/INPUT'), + ('state', 'not in', ['done','cancel']), + ('product_id', '=', existing.product_id.id), + ('purchase_line_id', '=', existing.purchase_line_id.id), + ]) + + qty_incoming += sum(incoming_moves.mapped('product_uom_qty')) + + incoming_cache[sale_line_id] = qty_incoming + + + qty_need = sale_order.sale_line_id.product_uom_qty + + if incoming_cache[sale_line_id] >= qty_need: + skip_line = True + + sale_line_id = sale_order.sale_line_id.id + + if sale_line_id not in retur_cache: + + fully_received = True + + for existing in exist: + if existing.purchase_order_id.state in ['done', 'purchase']: + + if existing.purchase_line_id.qty_received != existing.purchase_line_id.product_qty: + fully_received = False + break + + retur_cache[sale_line_id] = fully_received + + + if retur_cache[sale_line_id]: + skip_line = True if skip_line: continue -- cgit v1.2.3 From deba773edb01799a13a047dcae080272145badc7 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 27 Feb 2026 14:59:16 +0700 Subject: push --- indoteknik_custom/models/automatic_purchase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index 7e324061..f7c0d75e 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -368,7 +368,7 @@ class AutomaticPurchase(models.Model): retur_cache[sale_line_id] = fully_received - if retur_cache[sale_line_id]: + if retur_cache[sale_line_id] and exist: skip_line = True if skip_line: -- cgit v1.2.3 From f1a0f0edb52a0d68bb711cf96ef6be8904e3faa3 Mon Sep 17 00:00:00 2001 From: FIN-IT_AndriFP Date: Fri, 27 Feb 2026 16:47:17 +0700 Subject: approve 2 layer dengan penambahan ketentuan cek amount baru cek margin --- indoteknik_custom/models/sale_order.py | 59 +++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 27bda20c..df72c9cb 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -2386,8 +2386,14 @@ class SaleOrder(models.Model): # return self._create_notification_action('Notification', # 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension') value_trigger = order._requires_approval_by_value() - - if order._requires_approval_margin_leader(): + if value_trigger: + self.check_product_bom() + self.check_credit_limit() + self.check_limit_so_to_invoice() + order.approval_status = 'pengajuan0' + order.message_post(body="Mengajukan approval ke Team Sales_") + return self._create_approval_notification('Team Sales') + elif order._requires_approval_margin_leader(): order.approval_status = 'pengajuan2' order.message_post(body="Mengajukan approval ke Pimpinan") return self._create_approval_notification('Pimpinan') @@ -2405,13 +2411,13 @@ class SaleOrder(models.Model): order.approval_status = 'pengajuan0' order.message_post(body="Mengajukan approval ke Team Sales") return self._create_approval_notification('Team Sales') - elif value_trigger: - self.check_product_bom() - self.check_credit_limit() - self.check_limit_so_to_invoice() - order.approval_status = 'pengajuan0' - order.message_post(body="Mengajukan approval ke Team Sales (Amount Total > 50jt)") - return self._create_approval_notification('Team Sales') + # elif value_trigger: + # self.check_product_bom() + # self.check_credit_limit() + # self.check_limit_so_to_invoice() + # order.approval_status = 'pengajuan0' + # order.message_post(body="Mengajukan approval ke Team Sales_") + # return self._create_approval_notification('Team Sales') if not order.with_context(ask_approval=True)._is_request_to_own_team_leader(): return self._create_notification_action( @@ -2677,20 +2683,24 @@ class SaleOrder(models.Model): 'Hanya bisa konfirmasi SO tim Anda.' ) value_trigger = order._requires_approval_by_value() - if order._requires_approval_margin_leader(): + if value_trigger: + order.approval_status = 'pengajuan0' + order.message_post(body="Mengajukan approval ke Team Sales") + return self._create_approval_notification('Team Sales') + elif order._requires_approval_margin_leader(): order.approval_status = 'pengajuan2' return self._create_approval_notification('Pimpinan') elif order._requires_approval_margin_manager(): order.approval_status = 'pengajuan1' return self._create_approval_notification('Sales Manager') - elif order._requires_approval_team_sales(): - order.approval_status = 'pengajuan1' + elif value_trigger or order._requires_approval_team_sales(): + order.approval_status = 'pengajuan0' order.message_post(body="Mengajukan approval ke Team Sales") return self._create_approval_notification('Team Sales') - elif value_trigger: - order.approval_status = 'pengajuan1' - order.message_post(body="Mengajukan approval ke Team Sales (Total SO > 50jt)") - return self._create_approval_notification('Team Sales') + # elif value_trigger: + # order.approval_status = 'pengajuan0' + # order.message_post(body="Mengajukan approval ke Team Sales (Total SO > 50jt)") + # return self._create_approval_notification('Team Sales') order.approval_status = 'approved' order._set_sppkp_npwp_contact() @@ -2788,14 +2798,14 @@ class SaleOrder(models.Model): return False def _requires_approval_margin_leader(self): - return self.total_percent_margin <= 15 and not self.env.user.is_leader + return self.total_percent_margin <= 40 and not self.env.user.is_leader def _requires_approval_margin_manager(self): - return 15 < self.total_percent_margin < 18 and not self.env.user.is_sales_manager and not self.env.user.id == 375 and not self.env.user.is_leader + return 40 < self.total_percent_margin < 50 and not self.env.user.is_sales_manager and not self.env.user.id == 375 and not self.env.user.is_leader def _requires_approval_team_sales(self): return ( - 18 <= self.total_percent_margin <= 24 + 60 <= self.total_percent_margin <= 70 # self.total_percent_margin >= 18 and self.env.user.id not in [11, 9, 375] # Eko, Ade, Putra and not self.env.user.is_sales_manager @@ -2803,9 +2813,14 @@ class SaleOrder(models.Model): ) def _requires_approval_by_value(self): - LIMIT_VALUE = 50000000 - return self.amount_total > LIMIT_VALUE - + # LIMIT_VALUE = 50000000 + LIMIT_VALUE = float(self.env['ir.config_parameter'].sudo().get_param('so.limit_value_approve', default='50000000')) + return ( + self.amount_total > LIMIT_VALUE + and self.env.user.id not in [11, 9, 375] # Eko, Ade, Putra + and not self.env.user.is_sales_manager + and not self.env.user.is_leader + ) def _is_request_to_own_team_leader(self): user = self.env.user -- cgit v1.2.3 From 82e3d96181f5d68a9fb405114aa361a8709fd70f Mon Sep 17 00:00:00 2001 From: FIN-IT_AndriFP Date: Fri, 27 Feb 2026 16:48:35 +0700 Subject: balikin margin, abis testing soalnya mwehehehehe --- indoteknik_custom/models/sale_order.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index df72c9cb..8eff613e 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -2798,14 +2798,14 @@ class SaleOrder(models.Model): return False def _requires_approval_margin_leader(self): - return self.total_percent_margin <= 40 and not self.env.user.is_leader + return self.total_percent_margin <= 15 and not self.env.user.is_leader def _requires_approval_margin_manager(self): - return 40 < self.total_percent_margin < 50 and not self.env.user.is_sales_manager and not self.env.user.id == 375 and not self.env.user.is_leader + return 15 < self.total_percent_margin < 18 and not self.env.user.is_sales_manager and not self.env.user.id == 375 and not self.env.user.is_leader def _requires_approval_team_sales(self): return ( - 60 <= self.total_percent_margin <= 70 + 18 <= self.total_percent_margin <= 24 # self.total_percent_margin >= 18 and self.env.user.id not in [11, 9, 375] # Eko, Ade, Putra and not self.env.user.is_sales_manager -- cgit v1.2.3 From 5af63f0a3c3a39cc52252c6a1235ef6dc3203c2a Mon Sep 17 00:00:00 2001 From: FIN-IT_AndriFP Date: Fri, 27 Feb 2026 16:58:31 +0700 Subject: fix --- indoteknik_custom/models/sale_order.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 8eff613e..0cb6670e 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -2816,7 +2816,7 @@ class SaleOrder(models.Model): # LIMIT_VALUE = 50000000 LIMIT_VALUE = float(self.env['ir.config_parameter'].sudo().get_param('so.limit_value_approve', default='50000000')) return ( - self.amount_total > LIMIT_VALUE + self.amount_total >= LIMIT_VALUE and self.env.user.id not in [11, 9, 375] # Eko, Ade, Putra and not self.env.user.is_sales_manager and not self.env.user.is_leader -- cgit v1.2.3 From 5d51a05b422fb259e14288fd1271a8c7e65a6aa4 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Mon, 2 Mar 2026 09:03:11 +0700 Subject: push --- indoteknik_custom/models/account_asset.py | 111 ++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/indoteknik_custom/models/account_asset.py b/indoteknik_custom/models/account_asset.py index 211ab229..c54f1d97 100644 --- a/indoteknik_custom/models/account_asset.py +++ b/indoteknik_custom/models/account_asset.py @@ -14,3 +14,114 @@ class AccountAsset(models.Model): if asset.value > 0: raise UserError("Asset masih mempunyai Value") asset.state = 'close' + + def create_move(self, post_move=True): + created_moves = self.env['account.move'] + prec = self.env['decimal.precision'].precision_get('Account') + if self.mapped('move_id'): + raise UserError(_( + 'This depreciation is already linked to a journal entry! Please post or delete it.')) + for line in self: + category_id = line.asset_id.category_id + depreciation_date = self.env.context.get( + 'depreciation_date') or line.depreciation_date or fields.Date.context_today( + self) + company_currency = line.asset_id.company_id.currency_id + current_currency = line.asset_id.currency_id + amount = current_currency.with_context( + date=depreciation_date).compute(line.amount, company_currency) + asset_name = line.asset_id.name + ' (%s/%s)' % ( + line.sequence, len(line.asset_id.depreciation_line_ids)) + partner = self.env['res.partner']._find_accounting_partner( + line.asset_id.partner_id) + move_line_1 = { + 'name': asset_name, + 'account_id': category_id.account_depreciation_id.id, + 'debit': 0.0 if float_compare(amount, 0.0, + precision_digits=prec) > 0 else -amount, + 'credit': amount if float_compare(amount, 0.0, + precision_digits=prec) > 0 else 0.0, + 'journal_id': category_id.journal_id.id, + 'partner_id': partner.id, + 'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'sale' else False, + 'currency_id': company_currency != current_currency and current_currency.id or False, + 'amount_currency': company_currency != current_currency and - 1.0 * line.amount or 0.0, + } + move_line_2 = { + 'name': asset_name, + 'account_id': category_id.account_depreciation_expense_id.id, + 'credit': 0.0 if float_compare(amount, 0.0, + precision_digits=prec) > 0 else -amount, + 'debit': amount if float_compare(amount, 0.0, + precision_digits=prec) > 0 else 0.0, + 'journal_id': category_id.journal_id.id, + 'partner_id': partner.id, + 'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'purchase' else False, + 'currency_id': company_currency != current_currency and current_currency.id or False, + 'amount_currency': company_currency != current_currency and line.amount or 0.0, + } + move_vals = { + 'ref': line.asset_id.code, + 'date': depreciation_date or False, + 'journal_id': category_id.journal_id.id, + 'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)], + } + move = self.env['account.move'].create(move_vals) + line.write({'move_id': move.id, 'move_check': True}) + created_moves |= move + + if post_move and created_moves: + created_moves.filtered(lambda m: any( + m.asset_depreciation_ids.mapped( + 'asset_id.category_id.open_asset'))).post() + created_moves.action_post() + return [x.id for x in created_moves] + + def create_grouped_move(self, post_move=True): + if not self.exists(): + return [] + + created_moves = self.env['account.move'] + category_id = self[ + 0].asset_id.category_id # we can suppose that all lines have the same category + depreciation_date = self.env.context.get( + 'depreciation_date') or fields.Date.context_today(self) + amount = 0.0 + for line in self: + # Sum amount of all depreciation lines + company_currency = line.asset_id.company_id.currency_id + current_currency = line.asset_id.currency_id + amount += current_currency.compute(line.amount, company_currency) + + name = category_id.name + _(' (grouped)') + move_line_1 = { + 'name': name, + 'account_id': category_id.account_depreciation_id.id, + 'debit': 0.0, + 'credit': amount, + 'journal_id': category_id.journal_id.id, + 'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'sale' else False, + } + move_line_2 = { + 'name': name, + 'account_id': category_id.account_depreciation_expense_id.id, + 'credit': 0.0, + 'debit': amount, + 'journal_id': category_id.journal_id.id, + 'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'purchase' else False, + } + move_vals = { + 'ref': category_id.name, + 'date': depreciation_date or False, + 'journal_id': category_id.journal_id.id, + 'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)], + } + move = self.env['account.move'].create(move_vals) + self.write({'move_id': move.id, 'move_check': True}) + created_moves |= move + + if post_move and created_moves: + self.post_lines_and_close_asset() + created_moves.post() + created_moves.action_post() + return [x.id for x in created_moves] \ No newline at end of file -- cgit v1.2.3