From 0383396bc2675fffa9fb48d8dfd5172b9c900f13 Mon Sep 17 00:00:00 2001 From: HafidBuroiroh Date: Thu, 12 Mar 2026 13:10:02 +0700 Subject: fix notif sourcing --- indoteknik_custom/models/sourcing_job_order.py | 304 +++++++++++++++++-------- indoteknik_custom/models/users.py | 1 + indoteknik_custom/views/users.xml | 1 + 3 files changed, 210 insertions(+), 96 deletions(-) diff --git a/indoteknik_custom/models/sourcing_job_order.py b/indoteknik_custom/models/sourcing_job_order.py index ce0bc4ec..66d03703 100644 --- a/indoteknik_custom/models/sourcing_job_order.py +++ b/indoteknik_custom/models/sourcing_job_order.py @@ -8,6 +8,7 @@ from pytz import timezone import base64 import xlrd, xlwt import io +from collections import defaultdict _logger = logging.getLogger(__name__) @@ -259,6 +260,52 @@ class SourcingJobOrder(models.Model): } } + def action_send_untaken_to_telegram(self): + bot_sjo = '8335015210:AAGbObP0jQf7ptyqJhYdBYn5Rm0CWOd_yIM' + chat_group_sjo = '-5081839952' + # chat_group_sjo = '-5147961921' + api_base = f'https://api.telegram.org/bot{bot_sjo}' + + lines = self.env['sourcing.job.order.line'].search( + [('state', '=', 'draft')], + order='create_date asc' + ) + + if not lines: + text = "✅ Tidak ada Sourcing Job Line yang berstatus Untaken saat ini." + else: + text = "⚠️ *Daftar SJO Line yang masih Untaken:*\n\n" + + line_counter = defaultdict(int) + + for line in lines: + sjo_id = line.order_id.id + line_counter[sjo_id] += 1 + + sjo_number = line.order_id.name if line.order_id else '-' + line_no = line_no = line_counter[sjo_id] + product_name = line.product_name or '-' + salesperson = line.show_salesperson.user_id.name if line.show_salesperson.user_id else '-' + + text += f"{sjo_number} | Line {line_no} | {product_name} | {salesperson}\n" + + payload = { + 'chat_id': chat_group_sjo, + 'text': text, + 'parse_mode': 'Markdown' + } + + try: + response = requests.post(f"{api_base}/sendMessage", data=payload, timeout=20) + if response.status_code == 200: + _logger.info("✅ Telegram notification sent successfully") + else: + _logger.error(f"❌ Failed to send Telegram message: {response.text}") + except Exception as e: + _logger.error(f"⚠️ Error while sending Telegram message: {str(e)}") + + return True + class SourcingJobOrderLine(models.Model): _name = 'sourcing.job.order.line' @@ -292,7 +339,7 @@ class SourcingJobOrderLine(models.Model): descriptions = fields.Text(string='Deskripsi / Spesifikasi') reason = fields.Text(string='Reason Unavailable') sla = fields.Char(string='SLA Product') - quantity = fields.Float(string='Quantity Product', required=True) + quantity = fields.Float(string='Quantity Product', required=True, default=1) price = fields.Float(string='Purchase Price') now_price = fields.Float(string='Current Purchase Price', readonly=True) last_updated_price = fields.Datetime(string='Last Update Price', readonly=True) @@ -525,82 +572,83 @@ class SourcingJobOrderLine(models.Model): if rec.order_id.state != 'draft': continue - def action_multi_ask_approval(self): - bot_sjo = '8335015210:AAGbObP0jQf7ptyqJhYdBYn5Rm0CWOd_yIM' - chat_sjo = '6076436058' - api_base = f'https://api.telegram.org/bot{bot_sjo}/sendMessage' - - order_ids = self.mapped('order_id') - if len(order_ids) != 1: - raise UserError("❌ Semua line harus berasal dari Sourcing Job yang sama.") - - order_ids = self.mapped('order_id') - if len(order_ids) != 1: - raise UserError("❌ Semua line harus berasal dari Sourcing Job yang sama.") - - job = order_ids[0] - - md_users = self.mapped('md_person_ids') - if len(md_users) != 1 or md_users[0] != self.env.user: - raise UserError("❌ Hanya MD yang memegang semua line ini yang bisa request approval.") - - for line in self: - if line.state != 'sourcing': - raise UserError(f"⚠️ Produk '{line.product_name_md}' bukan status Sourcing.") - - if ( - not line.vendor_id - or not line.product_name_md - or not brand_id - or not line.price or line.price <= 0 - or not line.tax_id - or not line.subtotal or line.subtotal <= 0 - or not line.product_type - or not line.product_category - or not line.product_class - ): - raise UserError(f"❌ Data produk '{line.product_name_md}' belum lengkap.") - - activity_type = self.env.ref('mail.mail_activity_data_todo') - - approved_lines_text = "" - - for line in self: - line.state = 'sent' - - line.activity_schedule( - activity_type_id=activity_type.id, - user_id=job.create_uid.id, - note=f"{self.env.user.name} meminta approval untuk produk '{line.product_name_md}' di SJO '{job.name}'.", - ) - - approved_lines_text += f"
  • {line.product_name_md} - {line.price or 0}
  • " - - line.message_post( - body=f"📤 Request approval dikirim (Multi)", - subtype_xmlid="mail.mt_comment", - ) - - job.message_post( - body=( - f"📤 Multi Request Approval
    " - f"" - f"MD: {self.env.user.name}" - ), - subtype_xmlid="mail.mt_comment", - ) - - self.env.user.notify_success( - message=f"{len(self)} produk berhasil dikirim untuk approval.", - title="Multi Request Sent" - ) - - # return {'type': 'ir.actions.client', 'tag': 'reload'} + # def action_multi_ask_approval(self): + # bot_sjo = '8335015210:AAGbObP0jQf7ptyqJhYdBYn5Rm0CWOd_yIM' + # chat_sjo = '6076436058' + # api_base = f'https://api.telegram.org/bot{bot_sjo}/sendMessage' + + # order_ids = self.mapped('order_id') + # if len(order_ids) != 1: + # raise UserError("❌ Semua line harus berasal dari Sourcing Job yang sama.") + + # order_ids = self.mapped('order_id') + # if len(order_ids) != 1: + # raise UserError("❌ Semua line harus berasal dari Sourcing Job yang sama.") + + # job = order_ids[0] + + # md_users = self.mapped('md_person_ids') + # if len(md_users) != 1 or md_users[0] != self.env.user: + # raise UserError("❌ Hanya MD yang memegang semua line ini yang bisa request approval.") + + # for line in self: + # if line.state != 'sourcing': + # raise UserError(f"⚠️ Produk '{line.product_name_md}' bukan status Sourcing.") + + # if ( + # not line.vendor_id + # or not line.product_name_md + # or not brand_id + # or not line.price or line.price <= 0 + # or not line.tax_id + # or not line.subtotal or line.subtotal <= 0 + # or not line.product_type + # or not line.product_category + # or not line.product_class + # ): + # raise UserError(f"❌ Data produk '{line.product_name_md}' belum lengkap.") + + # activity_type = self.env.ref('mail.mail_activity_data_todo') + + # approved_lines_text = "" + + # for line in self: + # line.state = 'sent' + + # line.activity_schedule( + # activity_type_id=activity_type.id, + # user_id=line.show_salesperson.id, + # note=f"{self.env.user.name} meminta approval untuk produk '{line.product_name_md}' di SJO '{job.name}'.", + # ) + + # approved_lines_text += f"
  • {line.product_name_md} - {line.price or 0}
  • " + + # line.message_post( + # body=f"📤 Request approval dikirim (Multi)", + # subtype_xmlid="mail.mt_comment", + # ) + + # job.message_post( + # body=( + # f"📤 Multi Request Approval
    " + # f"" + # f"MD: {self.env.user.name}" + # ), + # subtype_xmlid="mail.mt_comment", + # ) + + # self.env.user.notify_success( + # message=f"{len(self)} produk berhasil dikirim untuk approval.", + # title="Multi Request Sent" + # ) + + # # return {'type': 'ir.actions.client', 'tag': 'reload'} def action_ask_approval(self): bot_sjo = '8335015210:AAGbObP0jQf7ptyqJhYdBYn5Rm0CWOd_yIM' - chat_sjo = '6076436058' + chat_sjo = self.show_salesperson.chat_id_telegram or False + # chat_sjo = '6076436058' api_base = f'https://api.telegram.org/bot{bot_sjo}/sendMessage' for line in self: @@ -653,14 +701,14 @@ class SourcingJobOrderLine(models.Model): line.activity_schedule( activity_type_id=activity_type.id, - user_id=job.create_uid.id, + user_id=line.show_salesperson.id, note=f"{self.env.user.name} meminta approval untuk produk '{line.product_name_md}' di SJO '{job.name}'.", ) line.message_post( body=( f"📤 Request approval dikirim
    " - f"Kepada: {job.create_uid.name}
    " + f"Kepada: {line.show_salesperson.name}
    " f"Produk: {line.product_name_md}" ), subtype_xmlid="mail.mt_comment" @@ -680,35 +728,36 @@ class SourcingJobOrderLine(models.Model): ) self.env.user.notify_success( - message=f"Request approval untuk '{line.product_name_md}' dikirim ke {job.create_uid.name}", + message=f"Request approval untuk '{line.product_name_md}' dikirim ke {line.show_salesperson.name}", title="Request Sent", ) base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') url = f"{base_url}/web#id={job.id}&model=sourcing.job.order&view_type=form" + + if chat_sjo: + try: + msg_text = ( + f"📢 Request Approval Produk\n\n" + f"🧾 Sourcing Job: 📎 {job.name}\n" + f"📦 Produk: {line.product_name_md}\n" + f"👤 MD: {self.env.user.name}\n" + f"💰 Harga: {line.price or 0}\n" + f"📅 Tanggal: {fields.Datetime.now().strftime('%d-%m-%Y %H:%M')}\n\n" + f"Silakan review di Odoo." + ) - try: - msg_text = ( - f"📢 Request Approval Produk\n\n" - f"🧾 Sourcing Job: 📎 {job.name}\n" - f"📦 Produk: {line.product_name_md}\n" - f"👤 MD: {self.env.user.name}\n" - f"💰 Harga: {line.price or 0}\n" - f"📅 Tanggal: {fields.Datetime.now().strftime('%d-%m-%Y %H:%M')}\n\n" - f"Silakan review di Odoo." - ) - - payload = { - 'chat_id': chat_sjo, - 'text': msg_text, - 'parse_mode': 'HTML' - } + payload = { + 'chat_id': chat_sjo, + 'text': msg_text, + 'parse_mode': 'HTML' + } - response = requests.post(api_base, data=payload, timeout=10) - response.raise_for_status() + response = requests.post(api_base, data=payload, timeout=10) + response.raise_for_status() - except Exception as e: - _logger.warning(f"Gagal kirim telegram approval line: {e}") + except Exception as e: + _logger.warning(f"Gagal kirim telegram approval line: {e}") return {'type': 'ir.actions.client', 'tag': 'reload'} @@ -717,6 +766,11 @@ class SourcingJobOrderLine(models.Model): PurchasePricelist = self.env['purchase.pricelist'] SaleOrderLine = self.env['sale.order.line'] + bot_sjo = '8335015210:AAGbObP0jQf7ptyqJhYdBYn5Rm0CWOd_yIM' + chat_sjo = '-5081839952' + # chat_sjo = '-5147961921' + api_base = f'https://api.telegram.org/bot{bot_sjo}/sendMessage' + for rec in self: job = rec.order_id @@ -852,6 +906,32 @@ class SourcingJobOrderLine(models.Model): title="Approved" ) + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + url = f"{base_url}/web#id={job.id}&model=sourcing.job.order&view_type=form" + + try: + msg_text = ( + f"📢 ✅ Sourcing Approved\n\n" + f"🧾 Sourcing Job: 📎 {job.name}\n" + f"📦 Produk: {rec.product_name_md}\n" + f"👤 Approved By: {rec.show_salesperson.name}\n" + f"👤 MD: {rec.md_person_ids.name}\n" + f"💰 Harga: {rec.price or 0}\n" + f"📅 Tanggal: {fields.Datetime.now().strftime('%d-%m-%Y %H:%M')}\n\n" + ) + + payload = { + 'chat_id': chat_sjo, + 'text': msg_text, + 'parse_mode': 'HTML' + } + + response = requests.post(api_base, data=payload, timeout=10) + response.raise_for_status() + + except Exception as e: + _logger.warning(f"Gagal kirim telegram approved line: {e}") + so = self.mapped('so_id')[:1] if so: return { @@ -1524,11 +1604,42 @@ class SourcingRejectWizard(models.TransientModel): def action_confirm_reject(self): self.ensure_one() + bot_sjo = '8335015210:AAGbObP0jQf7ptyqJhYdBYn5Rm0CWOd_yIM' + chat_sjo = '-5081839952' + api_base = f'https://api.telegram.org/bot{bot_sjo}/sendMessage' + line = self.line_id job = line.order_id line.state = 'sourcing' + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + url = f"{base_url}/web#id={job.id}&model=sourcing.job.order&view_type=form" + + try: + msg_text = ( + f"🚫 Approval Sourcing Ditolak\n\n" + f"🧾 Sourcing Job: 📎 {job.name}\n" + f"📦 Produk: {line.product_name}\n" + f"👤 Sales: {line.show_salesperson.name if line.show_salesperson else '-'}\n" + f"👤 MD: {line.md_person_ids.name if line.md_person_ids else '-'}\n" + f"❌ Ditolak Oleh: {self.env.user.name}\n" + f"📝 Alasan Reject:\n{self.reason}\n\n" + f"📅 Tanggal: {fields.Datetime.now().strftime('%d-%m-%Y %H:%M')}" + ) + + payload = { + 'chat_id': chat_sjo, + 'text': msg_text, + 'parse_mode': 'HTML' + } + + response = requests.post(api_base, data=payload, timeout=10) + response.raise_for_status() + + except Exception as e: + _logger.warning(f"Gagal kirim telegram reject line: {e}") + activities = self.env['mail.activity'].search([ ('res_model', '=', line._name), ('res_id', '=', line.id), @@ -1599,4 +1710,5 @@ class ReopenCancelLineWizard(models.TransientModel): line.write({ 'state': 'draft', 'md_person_ids': False, + 'reason': False, }) \ No newline at end of file diff --git a/indoteknik_custom/models/users.py b/indoteknik_custom/models/users.py index d95b56e7..f646c75b 100644 --- a/indoteknik_custom/models/users.py +++ b/indoteknik_custom/models/users.py @@ -14,6 +14,7 @@ class Users(models.Model): is_admin_reconcile = fields.Boolean(string='Admin Reconcile', help='Berhak Mengedit Journal Reconcile') is_inbound = fields.Boolean(string='Operator Inbound') is_outbound = fields.Boolean(string='Operator Outbound') + chat_id_telegram = fields.Char(string='ChatId Telegram') def notify_internal_users(self, message, title): users = self.search([('share', '=', False)]) diff --git a/indoteknik_custom/views/users.xml b/indoteknik_custom/views/users.xml index 6519aeaa..13561e2b 100644 --- a/indoteknik_custom/views/users.xml +++ b/indoteknik_custom/views/users.xml @@ -16,6 +16,7 @@ + -- cgit v1.2.3