diff options
Diffstat (limited to 'indoteknik_custom')
| -rw-r--r-- | indoteknik_custom/models/sourcing_job_order.py | 316 | ||||
| -rw-r--r-- | indoteknik_custom/models/users.py | 1 | ||||
| -rw-r--r-- | indoteknik_custom/views/users.xml | 1 |
3 files changed, 222 insertions, 96 deletions
diff --git a/indoteknik_custom/models/sourcing_job_order.py b/indoteknik_custom/models/sourcing_job_order.py index ce0bc4ec..5099b91d 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) @@ -411,11 +458,13 @@ class SourcingJobOrderLine(models.Model): return rec def write(self, vals): + bypass_md_check = self.env.context.get('bypass_md_check') for rec in self: if ( rec.md_person_ids and self.env.uid != rec.md_person_ids.id and rec.order_id.create_uid != self.env.user + and not bypass_md_check ): raise UserError("❌ Hanya MD yang memegang job yang boleh mengedit Sourcing Job.") @@ -525,82 +574,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"<li>{line.product_name_md} - {line.price or 0}</li>" - - line.message_post( - body=f"📤 <b>Request approval dikirim (Multi)</b>", - subtype_xmlid="mail.mt_comment", - ) - - job.message_post( - body=( - f"📤 <b>Multi Request Approval</b><br/>" - f"<ul>{approved_lines_text}</ul>" - f"<b>MD:</b> {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"<li>{line.product_name_md} - {line.price or 0}</li>" + + # line.message_post( + # body=f"📤 <b>Request approval dikirim (Multi)</b>", + # subtype_xmlid="mail.mt_comment", + # ) + + # job.message_post( + # body=( + # f"📤 <b>Multi Request Approval</b><br/>" + # f"<ul>{approved_lines_text}</ul>" + # f"<b>MD:</b> {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 +703,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"📤 <b>Request approval dikirim</b><br/>" - f"Kepada: <b>{job.create_uid.name}</b><br/>" + f"Kepada: <b>{line.show_salesperson.name}</b><br/>" f"Produk: <b>{line.product_name_md}</b>" ), subtype_xmlid="mail.mt_comment" @@ -680,35 +730,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"📢 <b>Request Approval Produk</b>\n\n" + f"🧾 <b>Sourcing Job:</b> <a href='{url}'>📎 {job.name}</a>\n" + f"📦 <b>Produk:</b> {line.product_name_md}\n" + f"👤 <b>MD:</b> {self.env.user.name}\n" + f"💰 <b>Harga:</b> {line.price or 0}\n" + f"📅 <b>Tanggal:</b> {fields.Datetime.now().strftime('%d-%m-%Y %H:%M')}\n\n" + f"Silakan review di Odoo." + ) - try: - msg_text = ( - f"📢 <b>Request Approval Produk</b>\n\n" - f"🧾 <b>Sourcing Job:</b> <a href='{url}'>📎 {job.name}</a>\n" - f"📦 <b>Produk:</b> {line.product_name_md}\n" - f"👤 <b>MD:</b> {self.env.user.name}\n" - f"💰 <b>Harga:</b> {line.price or 0}\n" - f"📅 <b>Tanggal:</b> {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 +768,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 +908,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"📢 <b>✅ Sourcing Approved</b>\n\n" + f"🧾 <b>Sourcing Job:</b> <a href='{url}'>📎 {job.name}</a>\n" + f"📦 <b>Produk:</b> {rec.product_name_md}\n" + f"👤 <b>Approved By:</b> {rec.show_salesperson.name}\n" + f"👤 <b>MD:</b> {rec.md_person_ids.name}\n" + f"💰 <b>Harga:</b> {rec.price or 0}\n" + f"📅 <b>Tanggal:</b> {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 { @@ -922,6 +1004,16 @@ class SourcingJobOrderLine(models.Model): rec.reason or '-' ) ) + if rec.show_salesperson: + rec.message_notify( + partner_ids=[rec.show_salesperson.partner_id.id], + subject="SJO Line Cancelled", + body=( + f"⚠️ Line <b>{line_no}</b> dari SJO <b>{rec.order_id.name}</b> " + f"telah di Cancel oleh <b>{self.env.user.name}</b>.<br/>" + f"<b>Reason:</b> {rec.reason}" + ) + ) @api.onchange('product_id') def _oncange_code(self): @@ -1524,11 +1616,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"🚫 <b>Approval Sourcing Ditolak</b>\n\n" + f"🧾 <b>Sourcing Job:</b> <a href='{url}'>📎 {job.name}</a>\n" + f"📦 <b>Produk:</b> {line.product_name}\n" + f"👤 <b>Sales:</b> {line.show_salesperson.name if line.show_salesperson else '-'}\n" + f"👤 <b>MD:</b> {line.md_person_ids.name if line.md_person_ids else '-'}\n" + f"❌ <b>Ditolak Oleh:</b> {self.env.user.name}\n" + f"📝 <b>Alasan Reject:</b>\n{self.reason}\n\n" + f"📅 <b>Tanggal:</b> {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 +1722,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 @@ <field name="is_admin_reconcile"/> <field name="is_outbound"/> <field name="is_inbound"/> + <field name="chat_id_telegram" groups="indoteknik_custom.group_role_it"/> </field> </field> </record> |
