diff options
| author | Indoteknik . <it@fixcomart.co.id> | 2025-09-03 17:53:25 +0700 |
|---|---|---|
| committer | Indoteknik . <it@fixcomart.co.id> | 2025-09-03 17:53:25 +0700 |
| commit | 1b389be56daecec87008f791e856205d2234e053 (patch) | |
| tree | 32319c86882f2148ce8531ec79c7740e5605823d | |
| parent | 4aae32a042a5f77feebfa7e4f504f32a5375eaae (diff) | |
(andri) add template mail & try testing
| -rwxr-xr-x | indoteknik_custom/__manifest__.py | 1 | ||||
| -rw-r--r-- | indoteknik_custom/models/letter_receivable.py | 102 | ||||
| -rw-r--r-- | indoteknik_custom/views/letter_receivable.xml | 5 | ||||
| -rw-r--r-- | indoteknik_custom/views/letter_receivable_mail_template.xml | 77 |
4 files changed, 182 insertions, 3 deletions
diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index e300670a..493c3ad6 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -179,6 +179,7 @@ 'views/update_date_planned_po_wizard_view.xml', 'views/unpaid_invoice_view.xml', 'views/letter_receivable.xml', + 'views/letter_receivable_mail_template.xml' ], 'demo': [], 'css': [], diff --git a/indoteknik_custom/models/letter_receivable.py b/indoteknik_custom/models/letter_receivable.py index 550aa9e3..4159ecc2 100644 --- a/indoteknik_custom/models/letter_receivable.py +++ b/indoteknik_custom/models/letter_receivable.py @@ -1,8 +1,13 @@ from odoo import models, fields, api, _ from odoo.exceptions import UserError from odoo.exceptions import ValidationError -from odoo.tools import mail +from odoo.tools import mail, formatLang from terbilang import Terbilang +import re +import logging +from datetime import timedelta + +_logger = logging.getLogger(__name__) class SuratPiutang(models.Model): _name = "surat.piutang" @@ -27,6 +32,7 @@ class SuratPiutang(models.Model): ("sent", "Sent") ], default="draft", tracking=True) send_date = fields.Datetime(string="Tanggal Kirim", tracking=True) + seven_days_after_sent_date = fields.Char(string="7 Hari Setelah Tanggal Kirim", tracking=True) currency_id = fields.Many2one('res.currency') @@ -75,6 +81,100 @@ class SuratPiutang(models.Model): if rec.state == "approval_pimpinan": rec.state = "sent" rec.send_date = fields.Datetime.now() + # Format tanggal + bulan (tanpa tahun) + month_map = { + 1: "Januari", 2: "Februari", 3: "Maret", 4: "April", + 5: "Mei", 6: "Juni", 7: "Juli", 8: "Agustus", + 9: "September", 10: "Oktober", 11: "November", 12: "Desember", + } + if rec.send_date: + target_date = rec.send_date.date() + timedelta(days=7) + rec.seven_days_after_sent_date = f"{target_date.day} {month_map[target_date.month]}" + + def action_send_letter(self): + self.ensure_one() + + selected_lines = self.line_ids.filtered('selected') + if not selected_lines: + raise UserError(_("Tidak ada invoice yang dicentang untuk dikirim.")) + + if not self.tujuan_email: + raise UserError(_("Email tujuan harus diisi.")) + + template = self.env.ref('indoteknik_custom.letter_receivable_mail_template') + today = fields.Date.today() + + month_map = { + 1: "Januari", 2: "Februari", 3: "Maret", 4: "April", + 5: "Mei", 6: "Juni", 7: "Juli", 8: "Agustus", + 9: "September", 10: "Oktober", 11: "November", 12: "Desember", + } + target_date = (self.send_date or fields.Datetime.now()).date() + timedelta(days=7) + self.seven_days_after_sent_date = f"{target_date.day} {month_map[target_date.month]}" + + perihal_map = { + 'penagihan': 'Surat Resmi Penagihan', + 'sp1': 'Surat Peringatan Pertama (I)', + 'sp2': 'Surat Peringatan Kedua (II)', + 'sp3': 'Surat Peringatan Ketiga (III)', + } + perihal_text = perihal_map.get(self.perihal, self.perihal or '') + + invoice_table_rows = "" + grand_total = 0 + for line in selected_lines: + inv = line.invoice_id + if not inv: + continue + days_to_due = (line.invoice_date_due - today).days if line.invoice_date_due else 0 + grand_total += line.amount_residual + invoice_table_rows += f""" + <tr> + <td>{line.invoice_number or '-'}</td> + <td>{self.partner_id.name or '-'}</td> + <td>{fields.Date.to_string(line.invoice_date) or '-'}</td> + <td>{fields.Date.to_string(line.invoice_date_due) or '-'}</td> + <td>{days_to_due}</td> + <td>{line.ref or '-'}</td> + <td>{formatLang(self.env, line.amount_residual, currency_obj=line.currency_id)}</td> + <td>{line.payment_term_id.name or '-'}</td> + </tr> + """ + + invoice_table_footer = f""" + <tfoot> + <tr style="font-weight:bold; background-color:#f9f9f9;"> + <td colspan="6" align="right">Grand Total</td> + <td>{formatLang(self.env, grand_total, currency_obj=self.currency_id)}</td> + <td colspan="2"></td> + </tr> + </tfoot> + """ + # inject table rows ke template + body_html = re.sub( + r"<tbody[^>]*>.*?</tbody>", + f"<tbody>{invoice_table_rows}</tbody>{invoice_table_footer}", + template.body_html, + flags=re.DOTALL + ).replace('${object.name}', self.name or '') \ + .replace('${object.partner_id.name}', self.partner_id.name or '') \ + .replace('${object.seven_days_after_sent_date}', self.seven_days_after_sent_date or '') \ + .replace('${object.perihal}', perihal_text or '') + + values = { + 'subject': template.subject.replace('${object.name}', self.name or ''), + 'email_to': self.tujuan_email, + 'email_from': 'finance@indoteknik.co.id', + 'body_html': body_html, + 'reply_to': 'finance@indoteknik.co.id', + } + + template.send_mail(self.id, force_send=True, email_values=values) + + _logger.info( + f"Surat Piutang {self.name} terkirim ke {self.tujuan_email} " + f"({self.partner_id.name}), total {len(selected_lines)} invoice." + ) @api.onchange('partner_id') def _onchange_partner_id(self): diff --git a/indoteknik_custom/views/letter_receivable.xml b/indoteknik_custom/views/letter_receivable.xml index 15875da9..e5acaef4 100644 --- a/indoteknik_custom/views/letter_receivable.xml +++ b/indoteknik_custom/views/letter_receivable.xml @@ -27,6 +27,7 @@ <header> <field name="state" widget="statusbar" statusbar_visible="draft,approval_pimpinan,sent"/> <button name="action_approve" type="object" string="Approval & Send" class="btn-primary"/> + <button name="action_send_letter" type="object" string="Email Send" class="btn-primary"/> </header> <div class="alert alert-info" role="alert" @@ -73,8 +74,8 @@ style="height: 40px; margin-bottom:0px;"> <strong>Info!</strong> Hanya invoice yang dipilih (tercentang) akan disertakan dalam dokumen surat piutang. </div> - <div> - <strong>Grand Total Invoice Terpilih: Rp. + <div style="margin-bottom:4px; margin-top:4px;"> + <strong>Grand Total Invoice Terpilih:<br/>Rp. <field name="grand_total"/> ( <field name="grand_total_text"/> ) diff --git a/indoteknik_custom/views/letter_receivable_mail_template.xml b/indoteknik_custom/views/letter_receivable_mail_template.xml new file mode 100644 index 00000000..0ee6f75c --- /dev/null +++ b/indoteknik_custom/views/letter_receivable_mail_template.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data noupdate="0"> + <record id="letter_receivable_mail_template" model="mail.template"> + <field name="name">Surat Piutang Invoices</field> + <field name="model_id" ref="indoteknik_custom.model_surat_piutang"/> + <field name="subject">Surat Peringatan Piutang ${object.name}</field> + <field name="email_from">finance@indoteknik.co.id</field> + <field name="email_to"></field> + <field name="body_html" type="html"> + <div style="font-family:Arial, sans-serif; font-size:13px; color:#333;"> + <div><b>Dengan hormat,</b></div> + <br/> + <div>Kepada Yth.</div> + <div><b>Manajemen ${object.partner_id.name}</b></div> + <br/> + <div> + Melalui email ini, kami ingin mengingatkan kembali terkait kewajiban pembayaran + ${object.partner_id.name} atas transaksi dengan rincian sebagai berikut: + </div> + <br/> + + <table cellpadding="6" cellspacing="0" width="100%" + style="border-collapse:collapse; font-size:12px; border:1px solid #ddd;"> + <thead> + <tr style="background-color:#f2f2f2; text-align:left;"> + <th style="border:1px solid #ddd;">Invoice Number</th> + <th style="border:1px solid #ddd;">Customer</th> + <th style="border:1px solid #ddd;">Invoice Date</th> + <th style="border:1px solid #ddd;">Due Date</th> + <th style="border:1px solid #ddd;">Days To Due</th> + <th style="border:1px solid #ddd;">Reference</th> + <th style="border:1px solid #ddd;">Amount Due Signed</th> + <th style="border:1px solid #ddd;">Payment Terms</th> + </tr> + </thead> + <tbody> + <!-- baris invoice akan diinject dari Python --> + </tbody> + </table> + + <p> + Hingga saat ini, kami belum menerima pembayaran atas tagihan tersebut. + Mohon konfirmasi dan tindak lanjut dari pihak saudara paling lambat pada + tanggal <b>${object.seven_days_after_sent_date}</b> (7 hari setelah email ini dikirimkan). + </p> + + <p> + Sebagai informasi, kami lampirkan <b>${object.perihal}</b> untuk menjadi perhatian. + Jika tidak ada tanggapan atau penyelesaian dalam batas waktu tersebut, kami akan + melanjutkan dengan pengiriman surat peringatan berikutnya dan mengambil langkah-langkah + penyelesaian sesuai ketentuan yang berlaku. + </p> + + <p> + Demikian kami sampaikan. Atas perhatian dan kerja samanya, kami ucapkan terima kasih. + </p> + + <br/><br/> + <p> + <b> + Best Regards,<br/><br/> + Widya R.<br/> + Dept. Finance<br/> + PT. INDOTEKNIK DOTCOM GEMILANG<br/> + <img src="https://erp.indoteknik.com/api/image/ir.attachment/datas/2135765" + alt="Indoteknik" style="max-width:18%; height:auto;"/><br/> + <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> + </div> + </field> + <field name="auto_delete" eval="True"/> + </record> + </data> +</odoo> |
