summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIndoteknik . <it@fixcomart.co.id>2025-09-03 17:53:25 +0700
committerIndoteknik . <it@fixcomart.co.id>2025-09-03 17:53:25 +0700
commit1b389be56daecec87008f791e856205d2234e053 (patch)
tree32319c86882f2148ce8531ec79c7740e5605823d
parent4aae32a042a5f77feebfa7e4f504f32a5375eaae (diff)
(andri) add template mail & try testing
-rwxr-xr-xindoteknik_custom/__manifest__.py1
-rw-r--r--indoteknik_custom/models/letter_receivable.py102
-rw-r--r--indoteknik_custom/views/letter_receivable.xml5
-rw-r--r--indoteknik_custom/views/letter_receivable_mail_template.xml77
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 &amp; 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>