diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-08-09 13:59:43 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-08-09 13:59:43 +0700 |
| commit | 48159b92cfa466ff7df454aa3c860b79c7e18467 (patch) | |
| tree | 8f50df9b54dadac53d40d2f487de1b89c24ca561 | |
| parent | b6ae7b2c9f1c564f3bf2a471f4871fda745d215d (diff) | |
| parent | 06b661f2fa9e07e4b3d1d2b5c7aa9f16f057a3a3 (diff) | |
Merge branch 'odoo-backup' of https://bitbucket.org/altafixco/indoteknik-addons into odoo-backup
| -rw-r--r-- | indoteknik_custom/models/account_move.py | 265 | ||||
| -rw-r--r-- | indoteknik_custom/models/res_partner.py | 5 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 9 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 9 | ||||
| -rw-r--r-- | indoteknik_custom/views/mail_template_invoice_reminder.xml | 22 | ||||
| -rw-r--r-- | indoteknik_custom/views/res_partner.xml | 3 |
6 files changed, 202 insertions, 111 deletions
diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index c5e01f0c..fd08ed60 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -134,102 +134,175 @@ class AccountMove(models.Model): # result.append((move.id, move.display_name)) # return result - # def send_due_invoice_reminder(self): - # today = fields.Date.today() - # target_dates = [ - # today - timedelta(days=7), - # today - timedelta(days=3), - # today, - # today + timedelta(days=3), - # today + timedelta(days=7), - # ] - - # partner = self.env['res.partner'].search([('name', 'ilike', 'BANGUNAN TEKNIK GRUP')], limit=1) - # if not partner: - # _logger.info("Partner tidak ditemukan.") - # return - - # invoices = self.env['account.move'].search([ - # ('move_type', '=', 'out_invoice'), - # ('state', '=', 'posted'), - # ('payment_state', 'not in', ['paid','in_payment', 'reversed']), - # ('invoice_date_due', 'in', target_dates), - # ('partner_id', '=', partner.id), - # ]) - - # _logger.info(f"Invoices tahap 1: {invoices}") - - # invoices = invoices.filtered( - # lambda inv: inv.invoice_payment_term_id and 'tempo' in (inv.invoice_payment_term_id.name or '').lower() - # ) - # _logger.info(f"Invoices tahap 2: {invoices}") - - # if not invoices: - # _logger.info(f"Tidak ada invoice yang due untuk partner: {partner.name}") - # return - - # grouped = {} - # for inv in invoices: - # grouped.setdefault(inv.partner_id, []).append(inv) - - # template = self.env.ref('indoteknik_custom.mail_template_invoice_due_reminder') - - # for partner, invs in grouped.items(): - # if not partner.email: - # _logger.info(f"Partner {partner.name} tidak memiliki email") - # continue - - # invoice_table_rows = "" - # for inv in invs: - # days_to_due = (inv.invoice_date_due - today).days if inv.invoice_date_due else 0 - # invoice_table_rows += f""" - # <tr> - # <td>{inv.name}</td> - # <td>{fields.Date.to_string(inv.invoice_date) or '-'}</td> - # <td>{fields.Date.to_string(inv.invoice_date_due) or '-'}</td> - # <td>{days_to_due}</td> - # <td>{formatLang(self.env, inv.amount_total, currency_obj=inv.currency_id)}</td> - # <td>{inv.ref or '-'}</td> - # </tr> - # """ - - # subject = f"Reminder Invoice Due - {partner.name}" - # body_html = re.sub( - # r"<tbody[^>]*>.*?</tbody>", - # f"<tbody>{invoice_table_rows}</tbody>", - # template.body_html, - # flags=re.DOTALL - # ).replace('${object.name}', partner.name) \ - # .replace('${object.partner_id.name}', partner.name) - # # .replace('${object.email}', partner.email or '') - - # values = { - # 'subject': subject, - # 'email_to': 'andrifebriyadiputra@gmail.com', # Ubah ke partner.email untuk produksi - # 'email_from': 'finance@indoteknik.co.id', - # 'body_html': body_html, - # 'reply_to': f'invoice+account.move_{invs[0].id}@indoteknik.co.id', - # } - - # _logger.info(f"VALUES: {values}") - - # template.send_mail(invs[0].id, force_send=True, email_values=values) - - # # Default System User - # user_system = self.env['res.users'].browse(25) - # system_id = user_system.partner_id.id if user_system else False - # _logger.info(f"System User: {user_system.name} ({user_system.id})") - # _logger.info(f"System User ID: {system_id}") - - # for inv in invs: - # inv.message_post( - # subject=subject, - # body=body_html, - # subtype_id=self.env.ref('mail.mt_note').id, - # author_id=system_id, - # ) - - # _logger.info(f"Reminder terkirim ke {partner.name} ({values['email_to']}) → {len(invs)} invoice") + def send_due_invoice_reminder(self): + today = fields.Date.today() + target_dates = [ + today - timedelta(days=7), + today - timedelta(days=3), + today, + today + timedelta(days=3), + today + timedelta(days=7), + ] + + # --- TESTING --- + # partner = self.env['res.partner'].search([('name', 'ilike', 'DIRGANTARA YUDHA ARTHA')], limit=1) + # if not partner: + # _logger.info("Partner tidak ditemukan.") + # return + # invoices = self.env['account.move'].search([ + # ('move_type', '=', 'out_invoice'), + # ('state', '=', 'posted'), + # ('payment_state', 'not in', ['paid', 'in_payment', 'reversed']), + # ('invoice_date_due', 'in', target_dates), + # ('partner_id', '=', partner.id), + # ]) + + invoices = self.env['account.move'].search([ + ('move_type', '=', 'out_invoice'), + ('state', '=', 'posted'), + ('payment_state', 'not in', ['paid', 'in_payment', 'reversed']), + ('invoice_date_due', 'in', target_dates), + ]) + _logger.info(f"Invoices tahap 1: {invoices}") + + invoices = invoices.filtered( + lambda inv: inv.invoice_payment_term_id and 'tempo' in (inv.invoice_payment_term_id.name or '').lower() + ) + _logger.info(f"Invoices tahap 2: {invoices}") + + if not invoices: + _logger.info("Tidak ada invoice yang due") + return + + invoice_group = {} + for inv in invoices: + dtd = (inv.invoice_date_due - today).days if inv.invoice_date_due else 0 + invoice_group.setdefault((inv.partner_id, dtd), []).append(inv) + + template = self.env.ref('indoteknik_custom.mail_template_invoice_due_reminder') + + for (partner, dtd), invs in invoice_group.items(): + # Ambil child contact yang di-checklist reminder_invoices + reminder_contacts = self.env['res.partner'].search([ + ('parent_id', '=', partner.id), + ('reminder_invoices', '=', True), + ('email', '!=', False), + ]) + _logger.info(f"Email Reminder Child {reminder_contacts}") + + if not reminder_contacts: + _logger.info(f"Partner {partner.name} tidak memiliki email yang sudah ceklis reminder") + continue + + emails = list(filter(None, [partner.email])) + reminder_contacts.mapped('email') + if not emails: + _logger.info(f"Partner {partner.name} tidak memiliki email yang bisa dikirimi") + continue + + email_to = ",".join(emails) + _logger.info(f"Email tujuan: {email_to}") + + invoice_table_rows = "" + for inv in invs: + days_to_due = (inv.invoice_date_due - today).days if inv.invoice_date_due else 0 + invoice_table_rows += f""" + <tr> + <td>{inv.partner_id.name}</td> + <td>{inv.purchase_order_id.name or '-'}</td> + <td>{inv.name}</td> + <td>{fields.Date.to_string(inv.invoice_date) or '-'}</td> + <td>{fields.Date.to_string(inv.invoice_date_due) or '-'}</td> + <td>{formatLang(self.env, inv.amount_total, currency_obj=inv.currency_id)}</td> + <td>{inv.invoice_payment_term_id.name or '-'}</td> + <td>{days_to_due}</td> + </tr> + """ + + days_to_due_message = "" + closing_message = "" + if dtd < 0: + days_to_due_message = ( + f"Kami ingin mengingatkan bahwa tagihan anda akan jatuh tempo dalam {abs(dtd)} hari ke depan, " + "dengan rincian sebagai berikut:" + ) + closing_message = ( + "Kami mengharapkan pembayaran dapat dilakukan tepat waktu untuk mendukung kelancaran " + "hubungan kerja sama yang baik antara kedua belah pihak.<br/>" + "Mohon konfirmasi apabila pembayaran telah dijadwalkan. " + "Terima kasih atas perhatian dan kerja samanya." + ) + + if dtd == 0: + days_to_due_message = ( + "Kami ingin mengingatkan bahwa tagihan anda telah memasuki tanggal jatuh tempo pada hari ini, " + "dengan rincian sebagai berikut:" + ) + closing_message = ( + "Mohon kesediaannya untuk segera melakukan pembayaran tepat waktu guna menghindari status " + "keterlambatan dan menjaga kelancaran hubungan kerja sama yang telah terjalin dengan baik.<br/>" + "Apabila pembayaran telah dijadwalkan atau diproses, mohon dapat dikonfirmasi kepada kami. " + "Terima kasih atas perhatian dan kerja samanya." + ) + + if dtd > 0: + days_to_due_message = ( + f"Kami ingin mengingatkan bahwa tagihan anda telah jatuh tempo selama {dtd} hari, " + "dengan rincian sebagai berikut:" + ) + closing_message = ( + "Mohon kesediaan Bapak/Ibu untuk segera melakukan pembayaran guna menghindari keterlambatan " + "dan menjaga kelancaran kerja sama yang telah terjalin dengan baik.<br/>" + "Apabila pembayaran sudah dilakukan, mohon konfirmasi dan lampirkan bukti transfer agar dapat kami proses lebih lanjut. " + "Terima kasih atas perhatian dan kerja samanya." + ) + + body_html = re.sub( + r"<tbody[^>]*>.*?</tbody>", + f"<tbody>{invoice_table_rows}</tbody>", + template.body_html, + flags=re.DOTALL + ).replace('${object.name}', partner.name) \ + .replace('${object.partner_id.name}', partner.name) \ + .replace('${days_to_due_message}', days_to_due_message) \ + .replace('${closing_message}', closing_message) + + cc_list = [ + 'finance@indoteknik.co.id', + 'akbar@indoteknik.co.id', + 'stephan@indoteknik.co.id', + 'darren@indoteknik.co.id' + ] + sales_email = invs[0].invoice_user_id.partner_id.email if invs[0].invoice_user_id else None + if sales_email and sales_email not in cc_list: + cc_list.append(sales_email) + + # Siapkan email values + values = { + 'subject': f"Reminder Invoice Due - {partner.name}", + # 'email_to': 'andrifebriyadiputra@gmail.com', + 'email_to': email_to, + 'email_from': 'finance@indoteknik.co.id', + 'email_cc': ",".join(cc_list), + 'body_html': body_html, + 'reply_to': 'finance@indoteknik.co.id', + } + + _logger.info(f"Mengirim email ke: {values['email_to']} CC: {values['email_cc']}") + template.send_mail(invs[0].id, force_send=True, email_values=values) + + # Post ke chatter + user_system = self.env['res.users'].browse(25) + system_id = user_system.partner_id.id if user_system else False + + for inv in invs: + inv.message_post( + subject=values['subject'], + body=body_html, + subtype_id=self.env.ref('mail.mt_note').id, + author_id=system_id, + ) + + _logger.info(f"Reminder terkirim ke {partner.name} ({values['email_to']}) → {len(invs)} invoice (dtd = {dtd})") @api.onchange('invoice_date') diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index 236df16f..f260f58e 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -27,6 +27,11 @@ class ResPartner(models.Model): # Referensi supplier_ids = fields.Many2many('user.pengajuan.tempo.line', string="Suppliers") + reminder_invoices = fields.Boolean( + string='Reminder Invoice?', + help='Centang jika kontak ini harus menerima email pengingat invoice.', default=False + ) + # informasi perusahaan name_tempo = fields.Many2one('res.partner', string='Nama Perusahaan',tracking=True) industry_id_tempo = fields.Many2one('res.partner.industry', 'Customer Industry', readonly=True) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 5eb90d83..e71e3830 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -2160,9 +2160,9 @@ class SaleOrder(models.Model): # return self._create_notification_action('Notification', # 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension') - if not order._is_request_to_own_team_leader(): + if not order.with_context(ask_approval=True)._is_request_to_own_team_leader(): return self._create_notification_action( - 'Peringatan', + 'Peringatan', 'Hanya bisa konfirmasi SO tim Anda.' ) if order._requires_approval_margin_leader(): @@ -2528,7 +2528,10 @@ class SaleOrder(models.Model): if user.is_leader or user.is_sales_manager: return True - if not self.team_id or not self.team_id.user_id: + if user.id in (3401, 20, 3988): # admin (fida, nabila, ninda) + return True + + if self.env.context.get("ask_approval") and user.id in (3401, 20, 3988): return True salesperson_id = self.user_id.id diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 46bb6cee..82f81642 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1059,10 +1059,13 @@ class StockPicking(models.Model): return self.sale_id.date_doc_kirim = self.date_doc_kirim - from odoo import fields - def action_assign(self): - pickings_to_assign = self.filtered(lambda p: not (p.sale_id and p.sale_id.hold_outgoing)) + if self.env.context.get('default_picking_type_id'): + pickings_to_assign = self.filtered( + lambda p: not (p.sale_id and p.sale_id.hold_outgoing) + ) + else: + pickings_to_assign = self res = super(StockPicking, pickings_to_assign).action_assign() diff --git a/indoteknik_custom/views/mail_template_invoice_reminder.xml b/indoteknik_custom/views/mail_template_invoice_reminder.xml index 21055eb0..8450be28 100644 --- a/indoteknik_custom/views/mail_template_invoice_reminder.xml +++ b/indoteknik_custom/views/mail_template_invoice_reminder.xml @@ -6,29 +6,32 @@ <field name="model_id" ref="account.model_account_move"/> <field name="subject">Reminder Invoice Due - ${object.name}</field> <field name="email_from">finance@indoteknik.co.id</field> - <field name="email_to">andrifebriyadiputra@gmail.com</field> + <field name="email_to"></field> <field name="body_html" type="html"> <div> <p><b>Dear ${object.name},</b></p> - <p>Berikut adalah daftar invoice Anda yang mendekati atau telah jatuh tempo:</p> + <p>${days_to_due_message}</p> - <table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; width: 100%; font-size: 12px"> + <table border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; font-size: 12px"> <thead> <tr style="background-color: #f2f2f2;" align="left"> + <th>Customer</th> + <th>No. PO</th> <th>Invoice Number</th> - <th>Tanggal Invoice</th> - <th>Jatuh Tempo</th> - <th>Sisa Hari</th> - <th>Total</th> - <th>Referensi</th> + <th>Invoice Date</th> + <th>Due Date</th> + <th>Amount</th> + <th>Term</th> + <th>Days To Due</th> </tr> </thead> <tbody> </tbody> </table> - <p>Mohon bantuan dan kerjasamanya agar tetap bisa bekerjasama dengan baik</p> + <p>${closing_message}</p> + <br/> <p>Terima Kasih.</p> <br/> <br/> @@ -42,6 +45,7 @@ <a href="https://wa.me/6285716970374" target="_blank">+62-857-1697-0374</a> | <a href="mailto:finance@indoteknik.co.id">finance@indoteknik.co.id</a> </b></p> + <p><i>Email ini dikirim secara otomatis. Abaikan jika pembayaran telah dilakukan.</i></p> </div> </field> diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml index 38cd2756..b081f6f2 100644 --- a/indoteknik_custom/views/res_partner.xml +++ b/indoteknik_custom/views/res_partner.xml @@ -102,6 +102,9 @@ /> </div> </xpath> + <xpath expr="//field[@name='child_ids']/form//field[@name='mobile']" position="after"> + <field name="reminder_invoices"/> + </xpath> <xpath expr="//field[@name='property_payment_term_id']" position="attributes"> <attribute name="readonly">0</attribute> </xpath> |
